de-experimentalizing
[oweals/gnunet.git] / src / datastore / plugin_datastore_sqlite.c
index eca82a6fbe826fa65e7d2d6368467adbbff81d96..6e77ec3646da49edcfae2c9438d877566c627aa7 100644 (file)
@@ -174,14 +174,16 @@ create_indices (sqlite3 * dbh)
   /* create indices */
   sqlite3_exec (dbh,
                 "CREATE INDEX idx_hash ON gn090 (hash)", NULL, NULL, NULL);
-  sqlite3_exec (dbh, "CREATE INDEX idx_prio ON gn090 (prio)", NULL, NULL,
-                NULL);
-  sqlite3_exec (dbh, "CREATE INDEX idx_expire_prio ON gn090 (expire,prio)", NULL, NULL,
-                NULL);
   sqlite3_exec (dbh,
                 "CREATE INDEX idx_hash_vhash ON gn090 (hash,vhash)", NULL,
                 NULL, NULL);
-  sqlite3_exec (dbh, "CREATE INDEX idx_comb ON gn090 (prio,expire,anonLevel,hash)",
+  sqlite3_exec (dbh, "CREATE INDEX idx_expire_repl ON gn090 (expire ASC,repl DESC)", NULL, NULL,
+                NULL);
+  sqlite3_exec (dbh, "CREATE INDEX idx_comb ON gn090 (anonLevel ASC,expire ASC,prio,type,hash)",
+                NULL, NULL, NULL);
+  sqlite3_exec (dbh, "CREATE INDEX idx_expire ON gn090 (expire)",
+                NULL, NULL, NULL);
+  sqlite3_exec (dbh, "CREATE INDEX idx_repl ON gn090 (repl)",
                 NULL, NULL, NULL);
 }
 
@@ -263,9 +265,15 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
   CHECK (SQLITE_OK ==
          sqlite3_exec (plugin->dbh,
                        "PRAGMA synchronous=OFF", NULL, NULL, ENULL));
+  CHECK (SQLITE_OK ==
+         sqlite3_exec (plugin->dbh,
+                       "PRAGMA legacy_file_format=OFF", NULL, NULL, ENULL));
   CHECK (SQLITE_OK ==
          sqlite3_exec (plugin->dbh,
                        "PRAGMA auto_vacuum=INCREMENTAL", NULL, NULL, ENULL));
+  CHECK (SQLITE_OK ==
+         sqlite3_exec (plugin->dbh,
+                       "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL, ENULL));
   CHECK (SQLITE_OK ==
          sqlite3_exec (plugin->dbh,
                        "PRAGMA count_changes=OFF", NULL, NULL, ENULL));
@@ -303,45 +311,25 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
   sqlite3_finalize (stmt);
   create_indices (plugin->dbh);
 
-  CHECK (SQLITE_OK ==
-         sq_prepare (plugin->dbh,
-                     "SELECT 1 FROM sqlite_master WHERE tbl_name = 'gn071'",
-                     &stmt));
-  if ( (sqlite3_step (stmt) == SQLITE_DONE) &&
-       (sqlite3_exec (plugin->dbh,
-                     "CREATE TABLE gn071 ("
-                     "  key TEXT NOT NULL DEFAULT '',"
-                     "  value INTEGER NOT NULL DEFAULT 0)", NULL, NULL,
-                     NULL) != SQLITE_OK) )
-    {
-      LOG_SQLITE (plugin, NULL,
-                 GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec");
-      sqlite3_finalize (stmt);
-      return GNUNET_SYSERR;
-    }
-  sqlite3_finalize (stmt);
-
   if ((sq_prepare (plugin->dbh,
-                   "UPDATE gn090 SET prio = prio + ?, expire = MAX(expire,?) WHERE "
-                   "_ROWID_ = ?",
+                   "UPDATE gn090 SET prio = prio + ?, expire = MAX(expire,?) WHERE _ROWID_ = ?",
                    &plugin->updPrio) != SQLITE_OK) ||
       (sq_prepare (plugin->dbh,
-                   "UPDATE gn090 SET repl = MAX (0, repl - 1) WHERE "
-                   "_ROWID_ = ?",
+                   "UPDATE gn090 SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?",
                    &plugin->updRepl) != SQLITE_OK) ||
       (sq_prepare (plugin->dbh,
-                  "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn090 WHERE (expire > ?1) "
+                  "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn090"
                   " ORDER BY repl DESC, Random() LIMIT 1",
                    &plugin->selRepl) != SQLITE_OK) ||
       (sq_prepare (plugin->dbh,
-                  "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn090 WHERE (expire < ?1) "
-                  " OR NOT EXISTS (SELECT 1 from gn090 WHERE (expire < ?1)) "
+                  "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn090 "
+                  " WHERE NOT EXISTS (SELECT 1 FROM gn090 WHERE expire < ?1 LIMIT 1) OR expire < ?1 "
                   " ORDER BY prio ASC LIMIT 1",
                    &plugin->selExpi) != SQLITE_OK) ||
       (sq_prepare (plugin->dbh,
                    "INSERT INTO gn090 (repl, type, prio, "
-                   "anonLevel, expire, hash, vhash, value) VALUES "
-                   "(?, ?, ?, ?, ?, ?, ?, ?)",
+                   "anonLevel, expire, hash, vhash, value) "
+                   "VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
                    &plugin->insertContent) != SQLITE_OK) ||
       (sq_prepare (plugin->dbh,
                    "DELETE FROM gn090 WHERE _ROWID_ = ?",
@@ -1032,7 +1020,7 @@ sqlite_plugin_iter_zero_anonymity (void *cls,
   now = GNUNET_TIME_absolute_get ();
   GNUNET_asprintf (&q, 
                   "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn090 "
-                  "WHERE (prio = ?1 AND expire > %llu AND anonLevel = 0 AND type=%d AND hash < ?2) "
+                  "WHERE (anonLevel = 0 AND expire > %llu AND prio = ?1 AND type=%d AND hash < ?2) "
                   "ORDER BY hash DESC LIMIT 1",
                   (unsigned long long) now.abs_value,
                   type);
@@ -1048,7 +1036,7 @@ sqlite_plugin_iter_zero_anonymity (void *cls,
   GNUNET_free (q);
   GNUNET_asprintf (&q, 
                   "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn090 "
-                  "WHERE (prio < ?1 AND expire > %llu AND anonLevel = 0 AND type=%d) "
+                  "WHERE (anonLevel = 0 AND expire > %llu AND prio < ?1 AND type=%d) "
                   "ORDER BY prio DESC, hash DESC LIMIT 1",
                   (unsigned long long) now.abs_value,
                   type);
@@ -1415,7 +1403,95 @@ execute_get (struct Plugin *plugin,
 
 
 /**
- * Get a random item for replication.  Returns a single, not expired, random item
+ * Context for 'repl_iter' function.
+ */
+struct ReplCtx
+{
+  
+  /**
+   * Plugin handle.
+   */
+  struct Plugin *plugin;
+  
+  /**
+   * Function to call for the result (or the NULL).
+   */
+  PluginIterator iter;
+  
+  /**
+   * Closure for iter.
+   */
+  void *iter_cls;
+};
+
+
+/**
+ * Wrapper for the iterator for 'sqlite_plugin_replication_get'.
+ * Decrements the replication counter and calls the original
+ * iterator.
+ *
+ * @param cls closure
+ * @param next_cls closure to pass to the "next" function.
+ * @param key key for the content
+ * @param size number of bytes in data
+ * @param data content stored
+ * @param type type of the content
+ * @param priority priority of the content
+ * @param anonymity anonymity-level for the content
+ * @param expiration expiration time for the content
+ * @param uid unique identifier for the datum;
+ *        maybe 0 if no unique identifier is available
+ *
+ * @return GNUNET_SYSERR to abort the iteration, GNUNET_OK to continue
+ *         (continue on call to "next", of course),
+ *         GNUNET_NO to delete the item and continue (if supported)
+ */
+static int
+repl_iter (void *cls,
+          void *next_cls,
+          const GNUNET_HashCode *key,
+          uint32_t size,
+          const void *data,
+          enum GNUNET_BLOCK_Type type,
+          uint32_t priority,
+          uint32_t anonymity,
+          struct GNUNET_TIME_Absolute expiration, 
+          uint64_t uid)
+{
+  struct ReplCtx *rc = cls;
+  struct Plugin *plugin = rc->plugin;
+  int ret;
+
+  ret = rc->iter (rc->iter_cls,
+                 next_cls, key,
+                 size, data, 
+                 type, priority, anonymity, expiration,
+                 uid);
+  if (NULL != key)
+    {
+      sqlite3_bind_int64 (plugin->updRepl, 1, uid);
+      if (SQLITE_DONE != sqlite3_step (plugin->updRepl))
+       {
+         LOG_SQLITE (plugin, NULL,
+                     GNUNET_ERROR_TYPE_ERROR |
+                     GNUNET_ERROR_TYPE_BULK, "sqlite3_step");
+         if (SQLITE_OK != sqlite3_reset (plugin->updRepl))
+           LOG_SQLITE (plugin, NULL,
+                       GNUNET_ERROR_TYPE_ERROR |
+                       GNUNET_ERROR_TYPE_BULK, "sqlite3_reset");
+         return GNUNET_SYSERR;
+       }
+      if (SQLITE_OK != sqlite3_reset (plugin->delRow))
+       LOG_SQLITE (plugin, NULL,
+                   GNUNET_ERROR_TYPE_ERROR |
+                   GNUNET_ERROR_TYPE_BULK, "sqlite3_reset");
+    }
+  return ret;
+}
+
+
+/**
+ * Get a random item for replication.  Returns a single random item
  * from those with the highest replication counters.  The item's 
  * replication counter is decremented by one IF it was positive before.
  * Call 'iter' with all values ZERO or NULL if the datastore is empty.
@@ -1429,28 +1505,17 @@ sqlite_plugin_replication_get (void *cls,
                               PluginIterator iter, void *iter_cls)
 {
   struct Plugin *plugin = cls;
-  sqlite3_stmt *stmt;
-  struct GNUNET_TIME_Absolute now;
+  struct ReplCtx rc;
 
 #if DEBUG_SQLITE
   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
                   "sqlite",
                   "Getting random block based on replication order.\n");
 #endif
-  stmt = plugin->selRepl;
-  now = GNUNET_TIME_absolute_get ();
-  if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, now.abs_value))
-    {
-      LOG_SQLITE (plugin, NULL,                  
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX");
-      if (SQLITE_OK != sqlite3_reset (stmt))
-        LOG_SQLITE (plugin, NULL,
-                    GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset");
-      iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, 
-           GNUNET_TIME_UNIT_ZERO_ABS, 0);
-      return;
-    }
-  execute_get (plugin, stmt, iter, iter_cls);
+  rc.plugin = plugin;
+  rc.iter = iter;
+  rc.iter_cls = iter_cls;
+  execute_get (plugin, plugin->selRepl, &repl_iter, &rc);
 }
 
 
@@ -1531,10 +1596,6 @@ sqlite_plugin_get_size (void *cls)
                       _("sqlite version to old to determine size, assuming zero\n"));
       return 0;
     }
-  if (SQLITE_OK !=
-      sqlite3_exec (plugin->dbh,
-                   "VACUUM", NULL, NULL, ENULL))
-    abort ();
   CHECK (SQLITE_OK ==
         sqlite3_exec (plugin->dbh,
                       "VACUUM", NULL, NULL, ENULL));