View Issue Details

IDProjectCategoryView StatusLast Update
0001630GNUnetdatastore servicepublic2010-12-23 23:50
ReporterLRN Assigned ToLRN  
PrioritynormalSeveritymajorReproducibilityalways
Status closedResolutionfixed 
Summary0001630: W32-specific fixes for datastore tests and a fix for sqlite plugin
Description1) Same as datacache tests - argv[0] is used as-is for plugin name, resulting in a plugin_name "sqlite.exe", which prevents testcases from loading the right config file. The fix looks somewhat awkward, but it is also short. Personally, i think that it would have been better to use a single binary for all plugin tests, passing the plugin name as argv[1] (thus also eliminating the need for parsing argv[0]).

2) sqlite all-iterator prepares a statement, but iterator cleanup for this particular iterator does not finalize that statement (its counterpart, the basic iterator, works with iterator context, which includes two statements, and it does finalize them on cleanup, while all-iterator doesn't use context). I've fixed it to use NextContext as its iterator context, and to finalize its statement on cleanup.
Steps To Reproduce1) Run datastore tests on W32

2) Run perf_plugin_datastore_sqlite on any platform. On non-W32 this bug is not apparent, because it manifests itself in sharing violation over the database file, which only occur on W32 because of its non-standard unlink() implementation, which cannot unlink files that are in use. The new logging lines in plugin unloading routine will expose this bug if some other statements get lost.
TagsNo tags attached.
Attached Files
0001-Minor-W32-datastore-tweaks.-Fixed-stmt-finalizing-in.patch (10,991 bytes)   
From e6e55b80de5c8ad85fdfec45709af907208f5d75 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= <lrn1986@gmail.com>
Date: Sun, 12 Dec 2010 11:37:21 +0300
Subject: [PATCH] Minor W32 datastore tweaks. Fixed stmt finalizing in all iterator in sqlite plugin

---
 src/datastore/perf_datastore_api.c            |    8 ++-
 src/datastore/perf_plugin_datastore.c         |    8 ++-
 src/datastore/plugin_datastore_sqlite.c       |  108 ++++++++++++++++++++-----
 src/datastore/test_datastore_api.c            |    8 ++-
 src/datastore/test_datastore_api_management.c |    8 ++-
 5 files changed, 116 insertions(+), 24 deletions(-)

diff --git a/src/datastore/perf_datastore_api.c b/src/datastore/perf_datastore_api.c
index aa0c932..7d402ce 100644
--- a/src/datastore/perf_datastore_api.c
+++ b/src/datastore/perf_datastore_api.c
@@ -407,13 +407,17 @@ int
 main (int argc, char *argv[])
 {
   int ret;
-  const char *pos;
+  char *pos;
   char dir_name[128];
 
   /* determine name of plugin to use */
   plugin_name = argv[0];
   while (NULL != (pos = strstr(plugin_name, "_")))
     plugin_name = pos+1;
+  if (NULL != (pos = strstr(plugin_name, ".")))
+    pos[0] = 0;
+  else
+    pos = (char *) plugin_name;
 
   GNUNET_snprintf (dir_name,
 		   sizeof (dir_name),
@@ -428,6 +432,8 @@ main (int argc, char *argv[])
 #endif
                     NULL);
   ret = check ();
+  if (pos != plugin_name)
+    pos[0] = '.';
 #if REPORT_ID
   fprintf (stderr, "\n");
 #endif
diff --git a/src/datastore/perf_plugin_datastore.c b/src/datastore/perf_plugin_datastore.c
index c55fb62..facf7be 100644
--- a/src/datastore/perf_plugin_datastore.c
+++ b/src/datastore/perf_plugin_datastore.c
@@ -415,13 +415,17 @@ int
 main (int argc, char *argv[])
 {
   int ret;
-  const char *pos;
+  char *pos;
   char dir_name[128];
 
   /* determine name of plugin to use */
   plugin_name = argv[0];
   while (NULL != (pos = strstr(plugin_name, "_")))
     plugin_name = pos+1;
+  if (NULL != (pos = strstr(plugin_name, ".")))
+    pos[0] = 0;
+  else
+    pos = (char *) plugin_name;
 
   GNUNET_snprintf (dir_name,
 		   sizeof (dir_name),
@@ -436,6 +440,8 @@ main (int argc, char *argv[])
 #endif
                     NULL);
   ret = check ();
+  if (pos != plugin_name)
+    pos[0] = '.';
   GNUNET_DISK_directory_remove (dir_name);
 
   return ret;
diff --git a/src/datastore/plugin_datastore_sqlite.c b/src/datastore/plugin_datastore_sqlite.c
index 457f75c..1b83825 100644
--- a/src/datastore/plugin_datastore_sqlite.c
+++ b/src/datastore/plugin_datastore_sqlite.c
@@ -28,7 +28,7 @@
 #include "gnunet_datastore_plugin.h"
 #include <sqlite3.h>
 
-#define DEBUG_SQLITE GNUNET_YES
+#define DEBUG_SQLITE GNUNET_NO
 
 
 /**
@@ -105,6 +105,11 @@ struct Plugin
   sqlite3 *dbh;
 
   /**
+   * Precompiled SQL for deletion.
+   */
+  sqlite3_stmt *delRow;
+
+  /**
    * Precompiled SQL for update.
    */
   sqlite3_stmt *updPrio;
@@ -145,9 +150,16 @@ sq_prepare (sqlite3 * dbh, const char *zSql,
             sqlite3_stmt ** ppStmt)
 {
   char *dummy;
-  return sqlite3_prepare_v2 (dbh,
-			     zSql,
-			     strlen (zSql), ppStmt, (const char **) &dummy);
+  int result;
+  result = sqlite3_prepare_v2 (dbh,
+			       zSql,
+			       strlen (zSql), ppStmt, (const char **) &dummy);
+#if DEBUG_SQLITE
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+		   "sqlite",
+                   "Prepared %p: %d\n", *ppStmt, result);
+#endif
+  return result;
 }
 
 
@@ -324,12 +336,16 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
                    "INSERT INTO gn080 (size, type, prio, "
                    "anonLevel, expire, hash, vhash, value) VALUES "
                    "(?, ?, ?, ?, ?, ?, ?, ?)",
-                   &plugin->insertContent) != SQLITE_OK))
+                   &plugin->insertContent) != SQLITE_OK) ||
+      (sq_prepare (plugin->dbh,
+                   "DELETE FROM gn080 WHERE _ROWID_ = ?",
+                   &plugin->delRow) != SQLITE_OK))
     {
       LOG_SQLITE (plugin, NULL,
                   GNUNET_ERROR_TYPE_ERROR, "precompiling");
       return GNUNET_SYSERR;
     }
+
   return GNUNET_OK;
 }
 
@@ -342,11 +358,36 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
 static void
 database_shutdown (struct Plugin *plugin)
 {
+  int result;
+  if (plugin->delRow != NULL)
+    sqlite3_finalize (plugin->delRow);
   if (plugin->updPrio != NULL)
     sqlite3_finalize (plugin->updPrio);
   if (plugin->insertContent != NULL)
     sqlite3_finalize (plugin->insertContent);
-  sqlite3_close (plugin->dbh);
+  result = sqlite3_close(plugin->dbh);
+  while (result == SQLITE_BUSY)
+    {
+      sqlite3_stmt *stmt;
+      GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, 
+		       "sqlite",
+		       _("Tried to close sqlite without finalizing all prepared statements.\n"));
+      for (stmt = sqlite3_next_stmt(plugin->dbh, NULL); stmt != NULL; stmt = sqlite3_next_stmt(plugin->dbh, NULL))
+        {
+#if DEBUG_SQLITE
+          GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+		     "sqlite", "Closing statement %p\n", stmt);
+#endif
+          result = sqlite3_finalize(stmt);
+#if DEBUG_SQLITE
+          if (result != SQLITE_OK)
+              GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+		               "sqlite",
+                               "Failed to close statement %p: %d\n", stmt, result);
+#endif
+        }
+      result = sqlite3_close(plugin->dbh);
+    }
   GNUNET_free_non_null (plugin->fn);
 }
 
@@ -362,26 +403,23 @@ static int
 delete_by_rowid (struct Plugin* plugin, 
 		 unsigned long long rid)
 {
-  sqlite3_stmt *stmt;
 
-  if (sq_prepare (plugin->dbh,
-                  "DELETE FROM gn080 WHERE _ROWID_ = ?", &stmt) != SQLITE_OK)
+  sqlite3_bind_int64 (plugin->delRow, 1, rid);
+  if (SQLITE_DONE != sqlite3_step (plugin->delRow))
     {
       LOG_SQLITE (plugin, NULL,
                   GNUNET_ERROR_TYPE_ERROR |
-                  GNUNET_ERROR_TYPE_BULK, "sq_prepare");
+                  GNUNET_ERROR_TYPE_BULK, "sqlite3_step");
+      if (SQLITE_OK != sqlite3_reset (plugin->delRow))
+          LOG_SQLITE (plugin, NULL,
+                      GNUNET_ERROR_TYPE_ERROR |
+                      GNUNET_ERROR_TYPE_BULK, "sqlite3_reset");
       return GNUNET_SYSERR;
     }
-  sqlite3_bind_int64 (stmt, 1, rid);
-  if (SQLITE_DONE != sqlite3_step (stmt))
-    {
+  if (SQLITE_OK != sqlite3_reset (plugin->delRow))
       LOG_SQLITE (plugin, NULL,
                   GNUNET_ERROR_TYPE_ERROR |
-                  GNUNET_ERROR_TYPE_BULK, "sqlite3_step");
-      sqlite3_finalize (stmt);
-      return GNUNET_SYSERR;
-    }
-  sqlite3_finalize (stmt);
+                  GNUNET_ERROR_TYPE_BULK, "sqlite3_reset");
   return GNUNET_OK;
 }
 
@@ -1167,7 +1205,7 @@ sqlite_plugin_iter_migration_order (void *cls,
  * Call sqlite using the already prepared query to get
  * the next result.
  *
- * @param cls not used
+ * @param cls context with the prepared query
  * @param nc context with the prepared query
  * @return GNUNET_OK on success, GNUNET_SYSERR on error, GNUNET_NO if
  *        there are no more results 
@@ -1185,6 +1223,10 @@ all_next_prepare (void *cls,
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
 		  "Asked to clean up iterator state.\n");
 #endif
+      nc = (struct NextContext *)cls;
+      if (nc->stmt)
+          sqlite3_finalize (nc->stmt);
+      nc->stmt = NULL;
       return GNUNET_SYSERR;
     }
   plugin = nc->plugin;
@@ -1241,7 +1283,7 @@ sqlite_plugin_iter_all_now (void *cls,
   nc->iter_cls = iter_cls;
   nc->stmt = stmt;
   nc->prep = &all_next_prepare;
-  nc->prep_cls = NULL;
+  nc->prep_cls = nc;
   sqlite_next_request (nc, GNUNET_NO);
 }
 
@@ -1595,10 +1637,26 @@ libgnunet_plugin_datastore_sqlite_done (void *cls)
   struct GNUNET_DATASTORE_PluginFunctions *api = cls;
   struct Plugin *plugin = api->cls;
 
+#if DEBUG_SQLITE
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+		   "sqlite",
+		   "sqlite plugin is doneing\n");
+#endif
+
   if (plugin->next_task != GNUNET_SCHEDULER_NO_TASK)
     {
+#if DEBUG_SQLITE
+      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+		       "sqlite",
+		       "Canceling next task\n");
+#endif
       GNUNET_SCHEDULER_cancel (plugin->next_task);
       plugin->next_task = GNUNET_SCHEDULER_NO_TASK;
+#if DEBUG_SQLITE
+      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+		       "sqlite",
+		       "Prep'ing next task\n");
+#endif
       plugin->next_task_nc->prep (plugin->next_task_nc->prep_cls, NULL);
       GNUNET_free (plugin->next_task_nc);
       plugin->next_task_nc = NULL;
@@ -1606,6 +1664,11 @@ libgnunet_plugin_datastore_sqlite_done (void *cls)
   fn = NULL;
   if (plugin->drop_on_shutdown)
     fn = GNUNET_strdup (plugin->fn);
+#if DEBUG_SQLITE
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+		   "sqlite",
+		   "Shutting down database\n");
+#endif
   database_shutdown (plugin);
   plugin->env = NULL; 
   GNUNET_free (api);
@@ -1617,6 +1680,11 @@ libgnunet_plugin_datastore_sqlite_done (void *cls)
 				  fn);
       GNUNET_free (fn);
     }
+#if DEBUG_SQLITE
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+		   "sqlite",
+		   "sqlite plugin is finished doneing\n");
+#endif
   return NULL;
 }
 
diff --git a/src/datastore/test_datastore_api.c b/src/datastore/test_datastore_api.c
index de04655..94d068a 100644
--- a/src/datastore/test_datastore_api.c
+++ b/src/datastore/test_datastore_api.c
@@ -678,13 +678,17 @@ int
 main (int argc, char *argv[])
 {
   int ret;
-  const char *pos;
+  char *pos;
   char dir_name[128];
 
   /* determine name of plugin to use */
   plugin_name = argv[0];
   while (NULL != (pos = strstr(plugin_name, "_")))
     plugin_name = pos+1;
+  if (NULL != (pos = strstr(plugin_name, ".")))
+    pos[0] = 0;
+  else
+    pos = (char *) plugin_name;
 
   GNUNET_snprintf (dir_name,
 		   sizeof (dir_name),
@@ -699,6 +703,8 @@ main (int argc, char *argv[])
 #endif
                     NULL);
   ret = check ();
+  if (pos != plugin_name)
+    pos[0] = '.';
   GNUNET_DISK_directory_remove (dir_name);
   return ret;
 }
diff --git a/src/datastore/test_datastore_api_management.c b/src/datastore/test_datastore_api_management.c
index 03e14d6..5778f0b 100644
--- a/src/datastore/test_datastore_api_management.c
+++ b/src/datastore/test_datastore_api_management.c
@@ -388,13 +388,17 @@ main (int argc, char *argv[])
 {
   int ret;
   
-  const char *pos;
+  char *pos;
   char dir_name[128];
 
   /* determine name of plugin to use */
   plugin_name = argv[0];
   while (NULL != (pos = strstr(plugin_name, "_")))
     plugin_name = pos+1;
+  if (NULL != (pos = strstr(plugin_name, ".")))
+    pos[0] = 0;
+  else
+    pos = (char *) plugin_name;
 
   GNUNET_snprintf (dir_name,
 		   sizeof (dir_name),
@@ -409,6 +413,8 @@ main (int argc, char *argv[])
 #endif
                     NULL);
   ret = check ();
+  if (pos != plugin_name)
+    pos[0] = '.';
   GNUNET_DISK_directory_remove (dir_name);
   return ret;
 }
-- 
1.7.3.1.msysgit.0

Activities

Christian Grothoff

2010-12-19 19:23

manager   ~0004207

Committed as 13933.

Issue History

Date Modified Username Field Change
2010-12-12 16:40 LRN New Issue
2010-12-12 16:40 LRN File Added: 0001-Minor-W32-datastore-tweaks.-Fixed-stmt-finalizing-in.patch
2010-12-19 19:23 Christian Grothoff Note Added: 0004207
2010-12-19 19:23 Christian Grothoff Status new => resolved
2010-12-19 19:23 Christian Grothoff Resolution open => fixed
2010-12-19 19:23 Christian Grothoff Assigned To => Christian Grothoff
2010-12-19 19:23 Christian Grothoff Assigned To Christian Grothoff => LRN
2010-12-23 23:50 Christian Grothoff Status resolved => closed