gnunet-svn
[Top][All Lists]
Advanced

[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.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]