[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnunet] 01/06: NAMESTORE: Add DB setup utility with SQlite support; PQ
From: |
gnunet |
Subject: |
[gnunet] 01/06: NAMESTORE: Add DB setup utility with SQlite support; PQ broken |
Date: |
Fri, 30 Sep 2022 17:42:06 +0200 |
This is an automated email from the git hooks/post-receive script.
martin-schanzenbach pushed a commit to branch master
in repository gnunet.
commit c3eca4a0aabe79be51c18fbe56a91b033b1f0549
Author: Martin Schanzenbach <schanzen@gnunet.org>
AuthorDate: Fri Sep 30 17:36:52 2022 +0900
NAMESTORE: Add DB setup utility with SQlite support; PQ broken
---
src/include/gnunet_namestore_plugin.h | 22 +++
src/namestore/.gitignore | 1 +
src/namestore/Makefile.am | 9 +
src/namestore/gnunet-namestore-dbtool.c | 189 +++++++++++++++++++++
src/namestore/gnunet-service-namestore.c | 77 ++++++---
src/namestore/plugin_namestore_sqlite.c | 243 +++++++++++++++++++--------
src/namestore/test_common.c | 10 ++
src/namestore/test_namestore_api_sqlite.conf | 1 +
8 files changed, 463 insertions(+), 89 deletions(-)
diff --git a/src/include/gnunet_namestore_plugin.h
b/src/include/gnunet_namestore_plugin.h
index 5e8ac3203..1df0a5eb0 100644
--- a/src/include/gnunet_namestore_plugin.h
+++ b/src/include/gnunet_namestore_plugin.h
@@ -205,6 +205,28 @@ struct GNUNET_NAMESTORE_PluginFunctions
GNUNET_NAMESTORE_RecordIterator iter,
void *iter_cls);
+ /**
+ * Setup the database.
+ * Note that this will also fail if the database is already initialized.
+ * See reset_database().
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param emsg error message on failure. Will be allocated, must be freed.
+ * @return #GNUNET_OK on success, else fails with #GNUNET_SYSERR
+ */
+ int
+ (*initialize_database) (void *cls, char **emsg);
+
+ /**
+ * Re-initializes the database.
+ * DANGEROUS: All existing data in the dabase will be lost!
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param emsg error message on failure. Will be allocated, must be freed.
+ * @return #GNUNET_OK on success, else fails with #GNUNET_SYSERR
+ */
+ int
+ (*reset_database) (void *cls, char **emsg);
};
diff --git a/src/namestore/.gitignore b/src/namestore/.gitignore
index b6a968d61..907361276 100644
--- a/src/namestore/.gitignore
+++ b/src/namestore/.gitignore
@@ -1,5 +1,6 @@
gnunet-service-namestore
gnunet-namestore
+gnunet-namestore-dbtool
gnunet-namestore-fcfsd
test_namestore_api_lookup_nick.nc
test_namestore_api_lookup_private.nc
diff --git a/src/namestore/Makefile.am b/src/namestore/Makefile.am
index 5142058ad..d5e110206 100644
--- a/src/namestore/Makefile.am
+++ b/src/namestore/Makefile.am
@@ -90,6 +90,7 @@ libexec_PROGRAMS = \
bin_PROGRAMS = \
gnunet-namestore \
+ gnunet-namestore-dbtool \
gnunet-zoneimport
libexec_PROGRAMS += \
@@ -153,6 +154,14 @@ gnunet_namestore_LDADD = \
libgnunetnamestore.la \
$(GN_LIBINTL)
+gnunet_namestore_dbtool_SOURCES = \
+ gnunet-namestore-dbtool.c
+gnunet_namestore_dbtool_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunetnamestore.la \
+ $(GN_LIBINTL)
+
+
gnunet_namestore_fcfsd_SOURCES = \
gnunet-namestore-fcfsd.c
diff --git a/src/namestore/gnunet-namestore-dbtool.c
b/src/namestore/gnunet-namestore-dbtool.c
new file mode 100644
index 000000000..b0f7e2ab9
--- /dev/null
+++ b/src/namestore/gnunet-namestore-dbtool.c
@@ -0,0 +1,189 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2012, 2013, 2014, 2019, 2022 GNUnet e.V.
+
+ GNUnet is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ SPDX-License-Identifier: AGPL3.0-or-later
+ */
+/**
+ * @file gnunet-namestore-dbtool.c
+ * @brief command line tool to manipulate the database backends for the
namestore
+ * @author Martin Schanzenbach
+ *
+ */
+#include "platform.h"
+#include <gnunet_util_lib.h>
+#include <gnunet_namestore_plugin.h>
+
+/**
+ * Name of the plugin argument
+ */
+static char *pluginname;
+
+/**
+ * Reset argument
+ */
+static int reset;
+
+/**
+ * Initialize argument
+ */
+static int init;
+
+/**
+ * Return code
+ */
+static int ret = 0;
+
+/**
+ * Task run on shutdown. Cleans up everything.
+ *
+ * @param cls unused
+ */
+static void
+do_shutdown (void *cls)
+{
+ (void) cls;
+ if (NULL != pluginname)
+ GNUNET_free (pluginname);
+}
+/**
+ * Main function that will be run.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be
NULL!)
+ * @param cfg configuration
+ */
+static void
+run (void *cls,
+ char *const *args,
+ const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ const char *pkey_str;
+ char *db_lib_name;
+ char *emsg;
+ struct GNUNET_NAMESTORE_PluginFunctions *plugin;
+
+ (void) cls;
+ (void) args;
+ (void) cfgfile;
+ if (NULL != args[0])
+ GNUNET_log (
+ GNUNET_ERROR_TYPE_WARNING,
+ _ ("Superfluous command line arguments (starting with `%s') ignored\n"),
+ args[0]);
+
+ GNUNET_SCHEDULER_add_shutdown (&do_shutdown, (void *) cfg);
+ if (NULL == pluginname)
+ {
+ fprintf (stderr, "No plugin given!\n");
+ ret = 1;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", pluginname);
+ plugin = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg);
+ if (NULL == plugin)
+ {
+ fprintf (stderr, "Failed to load %s!\n", db_lib_name);
+ ret = 1;
+ GNUNET_SCHEDULER_shutdown ();
+ GNUNET_free (db_lib_name);
+ return;
+ }
+ if (reset)
+ {
+ if (GNUNET_OK != plugin->reset_database (plugin->cls, &emsg))
+ {
+ // FIXME do we want to return a reason?
+ fprintf (stderr, "Failed to reset database: %s\n",
+ emsg);
+ ret = 1;
+ GNUNET_free (emsg);
+ GNUNET_free (db_lib_name);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ }
+ else if (init)
+ {
+ if (GNUNET_OK != plugin->initialize_database (plugin->cls, &emsg))
+ {
+ // FIXME do we want to return a reason?
+ fprintf (stderr, "Failed to initialize database: %s\n",
+ emsg);
+ ret = 1;
+ GNUNET_free (emsg);
+ GNUNET_free (db_lib_name);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ }
+ GNUNET_SCHEDULER_shutdown ();
+ GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, plugin));
+ GNUNET_free (db_lib_name);
+}
+
+
+/**
+ * The main function for gnunet-namestore-dbtool.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+ struct GNUNET_GETOPT_CommandLineOption options[] =
+ { GNUNET_GETOPT_option_flag ('i', "init", gettext_noop (
+ "initialize database"), &init),
+ GNUNET_GETOPT_option_flag ('r',
+ "reset",
+ gettext_noop (
+ "reset database (DANGEROUS: All existing data
is lost!"),
+ &reset),
+ GNUNET_GETOPT_option_string (
+ 'p',
+ "plugin",
+ "PLUGIN",
+ gettext_noop (
+ "the namestore plugin to work with, e.g. 'sqlite'"),
+ &pluginname),
+ GNUNET_GETOPT_OPTION_END };
+ int lret;
+
+ if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
+ return 2;
+
+ GNUNET_log_setup ("gnunet-namestore-dbtool", "WARNING", NULL);
+ if (GNUNET_OK !=
+ (lret = GNUNET_PROGRAM_run (argc,
+ argv,
+ "gnunet-namestore-dbtool",
+ _ (
+ "GNUnet namestore database manipulation
tool"),
+ options,
+ &run,
+ NULL)))
+ {
+ GNUNET_free_nz ((void *) argv);
+ return lret;
+ }
+ GNUNET_free_nz ((void *) argv);
+ return ret;
+}
diff --git a/src/namestore/gnunet-service-namestore.c
b/src/namestore/gnunet-service-namestore.c
index 0a3dfea25..36f6d337c 100644
--- a/src/namestore/gnunet-service-namestore.c
+++ b/src/namestore/gnunet-service-namestore.c
@@ -137,10 +137,15 @@ struct NamestoreClient
struct GNUNET_SERVICE_Client *client;
/**
- * Database handle
+ * Database handle for client
*/
struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
+ /**
+ * Name of loaded plugin (neeed for cleanup)
+ */
+ char *db_lib_name;
+
/**
* Message queue for transmission to @e client
*/
@@ -372,6 +377,12 @@ static struct GNUNET_NAMECACHE_Handle *namecache;
*/
static char *db_lib_name;
+/**
+ * Database handle for service
+ */
+struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
+
+
/**
* Head of cop DLL.
*/
@@ -446,8 +457,6 @@ cleanup_task (void *cls)
GNUNET_NAMECACHE_disconnect (namecache);
namecache = NULL;
}
- GNUNET_free (db_lib_name);
- db_lib_name = NULL;
if (NULL != monitor_nc)
{
GNUNET_notification_context_destroy (monitor_nc);
@@ -458,6 +467,9 @@ cleanup_task (void *cls)
GNUNET_STATISTICS_destroy (statistics, GNUNET_NO);
statistics = NULL;
}
+ GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database));
+ GNUNET_free (db_lib_name);
+ db_lib_name = NULL;
}
@@ -574,8 +586,7 @@ cache_nick (const struct GNUNET_IDENTITY_PrivateKey *zone,
* @return NULL if no NICK record was found
*/
static struct GNUNET_GNSRECORD_Data *
-get_nick_record (const struct NamestoreClient *nc,
- const struct GNUNET_IDENTITY_PrivateKey *zone)
+get_nick_record (const struct GNUNET_IDENTITY_PrivateKey *zone)
{
struct GNUNET_IDENTITY_PublicKey pub;
struct GNUNET_GNSRECORD_Data *nick;
@@ -599,11 +610,11 @@ get_nick_record (const struct NamestoreClient *nc,
}
nick = NULL;
- res = nc->GSN_database->lookup_records (nc->GSN_database->cls,
- zone,
- GNUNET_GNS_EMPTY_LABEL_AT,
- &lookup_nick_it,
- &nick);
+ res = GSN_database->lookup_records (GSN_database->cls,
+ zone,
+ GNUNET_GNS_EMPTY_LABEL_AT,
+ &lookup_nick_it,
+ &nick);
if ((GNUNET_OK != res) || (NULL == nick))
{
#if ! defined(GNUNET_CULL_LOGGING)
@@ -753,7 +764,7 @@ send_lookup_response_with_filter (struct NamestoreClient
*nc,
char *rd_ser;
char *emsg;
- nick = get_nick_record (nc, zone_key);
+ nick = get_nick_record (zone_key);
GNUNET_assert (-1 != GNUNET_GNSRECORD_records_get_size (rd_count, rd));
if (GNUNET_OK != GNUNET_GNSRECORD_normalize_record_set (name,
@@ -996,7 +1007,7 @@ refresh_block (struct NamestoreClient *nc,
rd_clean[rd_count_clean++] = rd[i];
}
- nick = get_nick_record (nc, zone_key);
+ nick = get_nick_record (zone_key);
res_count = rd_count_clean;
res = (struct GNUNET_GNSRECORD_Data *) rd_clean; /* fixme: a bit unclean...
*/
if ((NULL != nick) && (0 != strcmp (name, GNUNET_GNS_EMPTY_LABEL_AT)))
@@ -1229,7 +1240,8 @@ client_disconnect_cb (void *cls,
for (cop = cop_head; NULL != cop; cop = cop->next)
if (nc == cop->nc)
cop->nc = NULL;
- GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, nc->GSN_database));
+ GNUNET_break (NULL == GNUNET_PLUGIN_unload (nc->db_lib_name,
nc->GSN_database));
+ GNUNET_free (nc->db_lib_name);
GNUNET_free (nc);
}
@@ -1249,7 +1261,6 @@ client_connect_cb (void *cls,
{
struct NamestoreClient *nc;
char *database;
- char *db_lib_name;
(void) cls;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client);
@@ -1261,9 +1272,12 @@ client_connect_cb (void *cls,
"namestore",
"database",
&database))
+ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
- GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Loading %s\n", db_lib_name);
+ GNUNET_free (nc);
+ return NULL;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading %s\n", db_lib_name);
nc->GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg);
GNUNET_free (database);
if (NULL == nc->GSN_database)
@@ -1271,12 +1285,11 @@ client_connect_cb (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Could not load database backend `%s'\n",
db_lib_name);
- GNUNET_free (db_lib_name);
GNUNET_free (nc);
return NULL;
}
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Loaded %s\n", db_lib_name);
- GNUNET_free (db_lib_name);
+ nc->db_lib_name = GNUNET_strdup (db_lib_name);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded %s\n", db_lib_name);
return nc;
}
@@ -1487,7 +1500,7 @@ handle_record_lookup (void *cls, const struct
LabelLookupMessage *ll_msg)
rlc.res_rd_count = 0;
rlc.res_rd = NULL;
rlc.rd_ser_len = 0;
- rlc.nick = get_nick_record (nc, &ll_msg->zone);
+ rlc.nick = get_nick_record (&ll_msg->zone);
if (GNUNET_YES != ntohl (ll_msg->is_edit_request))
res = nc->GSN_database->lookup_records (nc->GSN_database->cls,
&ll_msg->zone,
@@ -2469,6 +2482,7 @@ run (void *cls,
const struct GNUNET_CONFIGURATION_Handle *cfg,
struct GNUNET_SERVICE_Handle *service)
{
+ char *database;
(void) cls;
(void) service;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n");
@@ -2484,6 +2498,29 @@ run (void *cls,
GNUNET_assert (NULL != namecache);
}
statistics = GNUNET_STATISTICS_create ("namestore", cfg);
+ /* Loading database plugin */
+ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
+ "namestore",
+ "database",
+ &database))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
+ GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
+ return;
+ }
+ GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading %s\n", db_lib_name);
+ GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg);
+ GNUNET_free (database);
+ if (NULL == GSN_database)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not load database backend `%s'\n",
+ db_lib_name);
+ GNUNET_free (db_lib_name);
+ GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
+ return;
+ }
GNUNET_SCHEDULER_add_shutdown (&cleanup_task, NULL);
}
diff --git a/src/namestore/plugin_namestore_sqlite.c
b/src/namestore/plugin_namestore_sqlite.c
index c63339db7..f1097ad0a 100644
--- a/src/namestore/plugin_namestore_sqlite.c
+++ b/src/namestore/plugin_namestore_sqlite.c
@@ -74,6 +74,11 @@ struct Plugin
*/
char *fn;
+ /**
+ * Statements prepared, we are ready to go if GNUNET_YES
+ */
+ int ready;
+
/**
* Native SQLite database handle.
*/
@@ -120,9 +125,10 @@ struct Plugin
* @return #GNUNET_OK on success
*/
static int
-database_setup (struct Plugin *plugin)
+database_prepare (struct Plugin *plugin)
{
- char *sqlite_filename;
+ if (GNUNET_YES == plugin->ready)
+ return GNUNET_OK;
struct GNUNET_SQ_ExecuteStatement es[] = {
GNUNET_SQ_make_try_execute ("PRAGMA temp_store=MEMORY"),
GNUNET_SQ_make_try_execute ("PRAGMA synchronous=NORMAL"),
@@ -132,19 +138,6 @@ database_setup (struct Plugin *plugin)
GNUNET_SQ_make_try_execute ("PRAGMA locking_mode=NORMAL"),
GNUNET_SQ_make_try_execute ("PRAGMA journal_mode=WAL"),
GNUNET_SQ_make_try_execute ("PRAGMA page_size=4092"),
- GNUNET_SQ_make_execute ("CREATE TABLE IF NOT EXISTS ns098records ("
- " uid INTEGER PRIMARY KEY,"
- " zone_private_key BLOB NOT NULL,"
- " pkey BLOB,"
- " rvalue INT8 NOT NULL,"
- " record_count INT NOT NULL,"
- " record_data BLOB NOT NULL,"
- " label TEXT NOT NULL"
- ")"),
- GNUNET_SQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_reverse "
- "ON ns098records (zone_private_key,pkey)"),
- GNUNET_SQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_iter "
- "ON ns098records (zone_private_key,uid)"),
GNUNET_SQ_EXECUTE_STATEMENT_END
};
struct GNUNET_SQ_PrepareStatement ps[] = {
@@ -179,66 +172,26 @@ database_setup (struct Plugin *plugin)
GNUNET_SQ_PREPARE_END
};
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
- "namestore-sqlite",
- "FILENAME",
- &sqlite_filename))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "namestore-sqlite",
- "FILENAME");
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_DISK_file_test (sqlite_filename))
- {
- if (GNUNET_OK !=
- GNUNET_DISK_directory_create_for_file (sqlite_filename))
- {
- GNUNET_break (0);
- GNUNET_free (sqlite_filename);
- return GNUNET_SYSERR;
- }
- }
-
- /* Open database and precompile statements */
- if (SQLITE_OK !=
- sqlite3_open (sqlite_filename,
- &plugin->dbh))
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _ ("Unable to initialize SQLite: %s.\n"),
- sqlite3_errmsg (plugin->dbh));
- GNUNET_free (sqlite_filename);
- return GNUNET_SYSERR;
- }
- GNUNET_break (SQLITE_OK ==
- sqlite3_busy_timeout (plugin->dbh,
- BUSY_TIMEOUT_MS));
if (GNUNET_OK !=
GNUNET_SQ_exec_statements (plugin->dbh,
es))
{
- GNUNET_break (0);
LOG (GNUNET_ERROR_TYPE_ERROR,
- _ ("Failed to setup database at `%s'\n"),
- sqlite_filename);
- GNUNET_free (sqlite_filename);
+ _("Failed to setup database with: `%s'\n"),
+ sqlite3_errmsg (plugin->dbh));
return GNUNET_SYSERR;
}
-
if (GNUNET_OK !=
GNUNET_SQ_prepare (plugin->dbh,
ps))
{
GNUNET_break (0);
LOG (GNUNET_ERROR_TYPE_ERROR,
- _ ("Failed to setup database at `%s'\n"),
- sqlite_filename);
- GNUNET_free (sqlite_filename);
+ _ ("Failed to setup database with: `%s'\n"),
+ sqlite3_errmsg (plugin->dbh));
return GNUNET_SYSERR;
}
+ plugin->ready = GNUNET_YES;
return GNUNET_OK;
}
@@ -325,6 +278,7 @@ namestore_sqlite_store_records (void *cls,
uint64_t rvalue;
ssize_t data_size;
+ GNUNET_assert (GNUNET_OK == database_prepare (plugin));
memset (&pkey,
0,
sizeof(pkey));
@@ -594,6 +548,7 @@ namestore_sqlite_lookup_records (void *cls,
void *iter_cls)
{
struct Plugin *plugin = cls;
+ GNUNET_assert (GNUNET_OK == database_prepare (plugin));
struct GNUNET_SQ_QueryParam params[] = {
GNUNET_SQ_query_param_auto_from_type (zone),
GNUNET_SQ_query_param_string (label),
@@ -649,6 +604,7 @@ namestore_sqlite_iterate_records (void *cls,
sqlite3_stmt *stmt;
int err;
+ GNUNET_assert (GNUNET_OK == database_prepare (plugin));
if (NULL == zone)
{
struct GNUNET_SQ_QueryParam params[] = {
@@ -712,6 +668,7 @@ namestore_sqlite_zone_to_name (void *cls,
void *iter_cls)
{
struct Plugin *plugin = cls;
+ GNUNET_assert (GNUNET_OK == database_prepare (plugin));
struct GNUNET_SQ_QueryParam params[] = {
GNUNET_SQ_query_param_auto_from_type (zone),
GNUNET_SQ_query_param_auto_from_type (value_zone),
@@ -755,8 +712,11 @@ namestore_sqlite_transaction_begin (void *cls,
char **emsg)
{
struct Plugin *plugin = cls;
- return (SQLITE_BUSY == sqlite3_exec (plugin->dbh, "BEGIN IMMEDIATE
TRANSACTION;", NULL,
- NULL, emsg)) ? GNUNET_SYSERR :
GNUNET_YES;
+ GNUNET_assert (GNUNET_OK == database_prepare (plugin));
+ return (SQLITE_BUSY == sqlite3_exec (plugin->dbh,
+ "BEGIN IMMEDIATE TRANSACTION;", NULL,
+ NULL, emsg)) ? GNUNET_SYSERR :
+ GNUNET_YES;
}
/**
@@ -772,8 +732,10 @@ namestore_sqlite_transaction_rollback (void *cls,
char **emsg)
{
struct Plugin *plugin = cls;
+ GNUNET_assert (GNUNET_OK == database_prepare (plugin));
return (SQLITE_BUSY == sqlite3_exec (plugin->dbh, "ROLLBACK;", NULL,
- NULL, emsg)) ? GNUNET_SYSERR :
GNUNET_YES;
+ NULL, emsg)) ? GNUNET_SYSERR :
+ GNUNET_YES;
}
/**
@@ -789,10 +751,150 @@ namestore_sqlite_transaction_commit (void *cls,
char **emsg)
{
struct Plugin *plugin = cls;
+ GNUNET_assert (GNUNET_OK == database_prepare (plugin));
return (SQLITE_BUSY == sqlite3_exec (plugin->dbh, "END TRANSACTION;", NULL,
- NULL, emsg)) ? GNUNET_SYSERR :
GNUNET_YES;
+ NULL, emsg)) ? GNUNET_SYSERR :
+ GNUNET_YES;
+}
+
+static enum GNUNET_GenericReturnValue
+init_database (void *cls, char **emsg, int drop)
+{
+ struct Plugin *plugin = cls;
+ struct GNUNET_SQ_ExecuteStatement es_drop[] = {
+ GNUNET_SQ_make_execute ("DROP TABLE IF EXISTS ns098records"),
+ GNUNET_SQ_EXECUTE_STATEMENT_END
+ };
+ struct GNUNET_SQ_ExecuteStatement es[] = {
+ GNUNET_SQ_make_try_execute ("PRAGMA temp_store=MEMORY"),
+ GNUNET_SQ_make_try_execute ("PRAGMA synchronous=NORMAL"),
+ GNUNET_SQ_make_try_execute ("PRAGMA legacy_file_format=OFF"),
+ GNUNET_SQ_make_try_execute ("PRAGMA auto_vacuum=INCREMENTAL"),
+ GNUNET_SQ_make_try_execute ("PRAGMA encoding=\"UTF-8\""),
+ GNUNET_SQ_make_try_execute ("PRAGMA locking_mode=NORMAL"),
+ GNUNET_SQ_make_try_execute ("PRAGMA journal_mode=WAL"),
+ GNUNET_SQ_make_try_execute ("PRAGMA page_size=4092"),
+ GNUNET_SQ_make_execute ("CREATE TABLE ns098records ("
+ " uid INTEGER PRIMARY KEY,"
+ " zone_private_key BLOB NOT NULL,"
+ " pkey BLOB,"
+ " rvalue INT8 NOT NULL,"
+ " record_count INT NOT NULL,"
+ " record_data BLOB NOT NULL,"
+ " label TEXT NOT NULL"
+ ")"),
+ GNUNET_SQ_make_try_execute ("CREATE INDEX ir_pkey_reverse "
+ "ON ns098records (zone_private_key,pkey)"),
+ GNUNET_SQ_make_try_execute ("CREATE INDEX ir_pkey_iter "
+ "ON ns098records (zone_private_key,uid)"),
+ GNUNET_SQ_EXECUTE_STATEMENT_END
+ };
+ if ((GNUNET_YES == drop) &&
+ (GNUNET_OK != GNUNET_SQ_exec_statements (plugin->dbh,
+ es_drop)))
+ {
+ GNUNET_asprintf (emsg,
+ _ ("Failed to drop database with: `%s'\n"),
+ sqlite3_errmsg (plugin->dbh));
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_SQ_exec_statements (plugin->dbh,
+ es))
+ {
+ GNUNET_asprintf (emsg,
+ _ ("Failed to setup database with: `%s'\n"),
+ sqlite3_errmsg (plugin->dbh));
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+enum GNUNET_GenericReturnValue
+namestore_sqlite_initialize_database (void *cls, char **emsg)
+{
+ return init_database (cls, emsg, GNUNET_NO);
+}
+
+enum GNUNET_GenericReturnValue
+namestore_sqlite_reset_database (void *cls, char **emsg)
+{
+ return init_database (cls, emsg, GNUNET_YES);
}
+/**
+ * Initialize the database connections and associated
+ * data structures (create tables and indices
+ * as needed as well).
+ *
+ * @param plugin the plugin context (state for this module)
+ * @return #GNUNET_OK on success
+ */
+static int
+database_connect (struct Plugin *plugin)
+{
+ char *sqlite_filename;
+ char *emsg;
+ int try_create = GNUNET_NO;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
+ "namestore-sqlite",
+ "FILENAME",
+ &sqlite_filename))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "namestore-sqlite",
+ "FILENAME");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_DISK_file_test (sqlite_filename))
+ {
+ if (GNUNET_OK !=
+ GNUNET_DISK_directory_create_for_file (sqlite_filename))
+ {
+ GNUNET_break (0);
+ GNUNET_free (sqlite_filename);
+ return GNUNET_SYSERR;
+ }
+ }
+
+ /* Open database and precompile statements */
+ if ((NULL == plugin->dbh) &&
+ (SQLITE_OK != sqlite3_open (sqlite_filename,
+ &plugin->dbh)))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _ ("Unable to initialize SQLite: %s.\n"),
+ sqlite3_errmsg (plugin->dbh));
+ GNUNET_free (sqlite_filename);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_break (SQLITE_OK ==
+ sqlite3_busy_timeout (plugin->dbh,
+ BUSY_TIMEOUT_MS));
+ if (GNUNET_YES ==
+ GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg,
+ "namestore-sqlite",
+ "INIT_ON_CONNECT"))
+ {
+ /**
+ * Gracefully fail as this should not be a critical error if the
+ * database is already created
+ */
+ if (GNUNET_OK != init_database (plugin, &emsg, GNUNET_NO))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to initialize database on connect: `%s'\n",
+ emsg);
+ GNUNET_free (emsg);
+ }
+ }
+ return GNUNET_OK;
+}
+
+
/**
* Entry point for the plugin.
*
@@ -808,9 +910,10 @@ libgnunet_plugin_namestore_sqlite_init (void *cls)
plugin = GNUNET_new (struct Plugin);
plugin->cfg = cfg;
- if (GNUNET_OK != database_setup (plugin))
+ if (GNUNET_OK != database_connect (plugin))
{
- database_shutdown (plugin);
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "Database could not be connected to.\n");
GNUNET_free (plugin);
return NULL;
}
@@ -823,14 +926,16 @@ libgnunet_plugin_namestore_sqlite_init (void *cls)
api->transaction_begin = &namestore_sqlite_transaction_begin;
api->transaction_commit = &namestore_sqlite_transaction_commit;
api->transaction_rollback = &namestore_sqlite_transaction_rollback;
+ api->initialize_database = &namestore_sqlite_initialize_database;
+ api->reset_database = &namestore_sqlite_reset_database;
/**
* NOTE: Since SQlite does not support SELECT ... FOR UPDATE this is
* just an alias to lookup_records. The BEGIN IMMEDIATE mechanic currently
* implicitly ensures this API behaves as it should
*/
api->edit_records = &namestore_sqlite_lookup_records;
- LOG (GNUNET_ERROR_TYPE_INFO,
- _ ("Sqlite database running\n"));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ _ ("SQlite database running\n"));
return api;
}
@@ -852,7 +957,7 @@ libgnunet_plugin_namestore_sqlite_done (void *cls)
GNUNET_free (plugin);
GNUNET_free (api);
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "sqlite plugin is finished\n");
+ "SQlite plugin is finished\n");
return NULL;
}
diff --git a/src/namestore/test_common.c b/src/namestore/test_common.c
index 58afb0a32..24a88c180 100644
--- a/src/namestore/test_common.c
+++ b/src/namestore/test_common.c
@@ -21,6 +21,7 @@
* @file namestore/test_common.c
* @brief common functions for testcase setup
*/
+#include <gnunet_namestore_plugin.h>
/**
* test if we can load the plugin @a name.
@@ -30,6 +31,7 @@ TNC_test_plugin (const char *cfg_name)
{
char *database;
char *db_lib_name;
+ char *emsg;
struct GNUNET_NAMESTORE_PluginFunctions *db;
struct GNUNET_CONFIGURATION_Handle *cfg;
@@ -53,7 +55,15 @@ TNC_test_plugin (const char *cfg_name)
GNUNET_free (database);
db = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg);
if (NULL != db)
+ {
+ if (GNUNET_OK != db->reset_database (db->cls, &emsg))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error resetting database: %s\n",
emsg);
+ GNUNET_free (emsg);
+ return GNUNET_SYSERR;
+ }
GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, db));
+ }
GNUNET_free (db_lib_name);
GNUNET_CONFIGURATION_destroy (cfg);
if (NULL == db)
diff --git a/src/namestore/test_namestore_api_sqlite.conf
b/src/namestore/test_namestore_api_sqlite.conf
index cd4822097..342356247 100644
--- a/src/namestore/test_namestore_api_sqlite.conf
+++ b/src/namestore/test_namestore_api_sqlite.conf
@@ -6,3 +6,4 @@ DATABASE = sqlite
[namestore-sqlite]
FILENAME = $GNUNET_TEST_HOME/namestore/sqlite_test.db
+INIT_ON_CONNECT = YES
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [gnunet] branch master updated (003cc0ea2 -> dcc8fea2f), gnunet, 2022/09/30
- [gnunet] 03/06: -fix, gnunet, 2022/09/30
- [gnunet] 04/06: NAMESTORE: Add manpage for new database CLI, gnunet, 2022/09/30
- [gnunet] 01/06: NAMESTORE: Add DB setup utility with SQlite support; PQ broken,
gnunet <=
- [gnunet] 02/06: NAMESTORE: Add postgres functions for DB setup utility, gnunet, 2022/09/30
- [gnunet] 06/06: Merge branch 'master' of git+ssh://git.gnunet.org/gnunet, gnunet, 2022/09/30
- [gnunet] 05/06: -file, gnunet, 2022/09/30