fix
[oweals/gnunet.git] / src / datacache / plugin_datacache_sqlite.c
index 7674402c7ba430788bf8bb7a219805f11fc6a333..4c429c1b4576893e8b5a60f84386f49ef77a8447 100644 (file)
@@ -25,7 +25,7 @@
  */
 #include "platform.h"
 #include "gnunet_util_lib.h"
-#include "plugin_datacache.h"
+#include "gnunet_datacache_plugin.h"
 #include <sqlite3.h>
 
 #define DEBUG_DATACACHE_SQLITE GNUNET_NO
@@ -283,6 +283,8 @@ sqlite_plugin_del (void *cls)
   unsigned int dtype;
   sqlite3_stmt *stmt;
   sqlite3_stmt *dstmt;
+  char blob[65536];
+  GNUNET_HashCode hc;
 
 #if DEBUG_DATACACHE_SQLITE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -291,21 +293,15 @@ sqlite_plugin_del (void *cls)
 #endif
   stmt = NULL;
   dstmt = NULL;
-  if ((sq_prepare (plugin->dbh,
+  if (sq_prepare (plugin->dbh,
                    "SELECT type, key, value FROM ds090 ORDER BY expire ASC LIMIT 1",
-                   &stmt) != SQLITE_OK) ||
-      (sq_prepare (plugin->dbh,
-                   "DELETE FROM ds090 "
-                   "WHERE key=? AND value=? AND type=?",
-                   &dstmt) != SQLITE_OK))
+                   &stmt) != SQLITE_OK)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                  _("`%s' failed at %s:%d with error: %s\n"),
                  "sq_prepare", __FILE__, __LINE__, sqlite3_errmsg (plugin->dbh));
-      if (dstmt != NULL)
-        sqlite3_finalize (dstmt);
       if (stmt != NULL)
-        sqlite3_finalize (stmt);
+        (void) sqlite3_finalize (stmt);
       return GNUNET_SYSERR;
     }
   if (SQLITE_ROW != sqlite3_step (stmt))
@@ -314,37 +310,69 @@ sqlite_plugin_del (void *cls)
                  _("`%s' failed at %s:%d with error: %s\n"),
                  "sqlite3_step", __FILE__, __LINE__,
                  sqlite3_errmsg (plugin->dbh));
-      sqlite3_finalize (dstmt);
-      sqlite3_finalize (stmt);
+      (void) sqlite3_finalize (stmt);
       return GNUNET_SYSERR;
     }
   dtype = sqlite3_column_int (stmt, 0);
   GNUNET_break (sqlite3_column_bytes (stmt, 1) == sizeof (GNUNET_HashCode));
   dsize = sqlite3_column_bytes (stmt, 2);
-  sqlite3_bind_blob (dstmt,
-                    1, sqlite3_column_blob (stmt, 1),
-                    sizeof (GNUNET_HashCode),
-                    SQLITE_TRANSIENT);
-  sqlite3_bind_blob (dstmt,
-                    2, sqlite3_column_blob (stmt, 2),
-                    dsize,
-                    SQLITE_TRANSIENT);
-  sqlite3_bind_int (dstmt, 3, dtype);
+  GNUNET_assert (dsize <= sizeof (blob));
+  memcpy (blob, sqlite3_column_blob (stmt, 2), dsize);
+  memcpy (&hc, sqlite3_column_blob (stmt, 1), sizeof (GNUNET_HashCode));
+  if (SQLITE_OK != sqlite3_finalize (stmt))
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+               _("`%s' failed at %s:%d with error: %s\n"),
+               "sqlite3_step", __FILE__, __LINE__,
+               sqlite3_errmsg (plugin->dbh));    
+  if (sq_prepare (plugin->dbh,
+                 "DELETE FROM ds090 "
+                 "WHERE key=? AND value=? AND type=?",
+                 &dstmt) != SQLITE_OK)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                 _("`%s' failed at %s:%d with error: %s\n"),
+                 "sq_prepare", __FILE__, __LINE__, sqlite3_errmsg (plugin->dbh));
+      if (stmt != NULL)
+        (void) sqlite3_finalize (stmt);
+      return GNUNET_SYSERR;
+    }
+  if ( (SQLITE_OK !=
+       sqlite3_bind_blob (dstmt,
+                          1, &hc,
+                          sizeof (GNUNET_HashCode),
+                          SQLITE_TRANSIENT)) ||
+       (SQLITE_OK !=
+       sqlite3_bind_blob (dstmt,
+                          2, blob,
+                          dsize,
+                          SQLITE_TRANSIENT)) ||
+       (SQLITE_OK != 
+       sqlite3_bind_int (dstmt, 3, dtype)) )
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                 _("`%s' failed at %s:%d with error: %s\n"),
+                 "sqlite3_bind", __FILE__, __LINE__,
+                 sqlite3_errmsg (plugin->dbh));    
+      (void) sqlite3_finalize (dstmt);
+      return GNUNET_SYSERR;
+    }
   if (sqlite3_step (dstmt) != SQLITE_DONE)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                  _("`%s' failed at %s:%d with error: %s\n"),
                  "sqlite3_step", __FILE__, __LINE__,
                  sqlite3_errmsg (plugin->dbh));    
-      sqlite3_finalize (dstmt);
-      sqlite3_finalize (stmt);
+      (void) sqlite3_finalize (dstmt);
       return GNUNET_SYSERR;
     }
   plugin->env->delete_notify (plugin->env->cls,
-                             sqlite3_column_blob (stmt, 1),
+                             &hc,
                              dsize + OVERHEAD);
-  sqlite3_finalize (dstmt);
-  sqlite3_finalize (stmt);
+  if (SQLITE_OK != sqlite3_finalize (dstmt))
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+               _("`%s' failed at %s:%d with error: %s\n"),
+               "sqlite3_finalize", __FILE__, __LINE__,
+               sqlite3_errmsg (plugin->dbh));    
   return GNUNET_OK;
 }
 
@@ -387,6 +415,8 @@ libgnunet_plugin_datacache_sqlite_init (void *cls)
   GNUNET_free (fn);
 
   SQLITE3_EXEC (dbh, "PRAGMA temp_store=MEMORY");
+  SQLITE3_EXEC (dbh, "PRAGMA locking_mode=EXCLUSIVE");
+  SQLITE3_EXEC (dbh, "PRAGMA journal_mode=OFF");
   SQLITE3_EXEC (dbh, "PRAGMA synchronous=OFF");
   SQLITE3_EXEC (dbh, "PRAGMA count_changes=OFF");
   SQLITE3_EXEC (dbh, "PRAGMA page_size=4092");
@@ -410,6 +440,7 @@ libgnunet_plugin_datacache_sqlite_init (void *cls)
                    "sqlite", _("Sqlite datacache running\n"));
   return api;
 }
+// explain SELECT type FROM gn090 WHERE NOT EXISTS (SELECT 1 from gn090 WHERE expire < 42 LIMIT 1) OR expire < 42 ORDER BY repl DESC, Random() LIMIT 1;
 
 
 /**
@@ -423,13 +454,56 @@ libgnunet_plugin_datacache_sqlite_done (void *cls)
 {
   struct GNUNET_DATACACHE_PluginFunctions *api = cls;
   struct Plugin *plugin = api->cls;
+  int result;
+#if SQLITE_VERSION_NUMBER >= 3007000
+  sqlite3_stmt *stmt;
+#endif
+
+#if !WINDOWS || defined(__CYGWIN__)
+  if (0 != UNLINK (plugin->fn))
+    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                             "unlink", 
+                             plugin->fn);
+  GNUNET_free (plugin->fn);
+#endif
+  result = sqlite3_close (plugin->dbh);
+#if SQLITE_VERSION_NUMBER >= 3007000
+  if (result == SQLITE_BUSY)
+    {
+      GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, 
+                      "sqlite",
+                      _("Tried to close sqlite without finalizing all prepared statements.\n"));
+      stmt = sqlite3_next_stmt(plugin->dbh, NULL); 
+      while (stmt != 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
+         stmt = sqlite3_next_stmt(plugin->dbh, NULL);
+        }
+      result = sqlite3_close(plugin->dbh);
+    }
+#endif
+  if (SQLITE_OK != result)
+    LOG_SQLITE (plugin->dbh,
+               GNUNET_ERROR_TYPE_ERROR, 
+               "sqlite3_close");
 
+#if WINDOWS && !defined(__CYGWIN__)
   if (0 != UNLINK (plugin->fn))
     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
                              "unlink", 
                              plugin->fn);
   GNUNET_free (plugin->fn);
-  sqlite3_close (plugin->dbh);
+#endif
   GNUNET_free (plugin);
   GNUNET_free (api);
   return NULL;