/*
* This file is part of GNUnet
* (C) 2009, 2011 Christian Grothoff (and other contributing authors)
- *
+ *
* GNUnet is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 3, 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
* General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with GNUnet; see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
#include "gnunet_datastore_plugin.h"
#include <sqlite3.h>
-/**
- * Enable or disable logging debug messages.
- */
-#define DEBUG_SQLITE GNUNET_NO
/**
* We allocate items on the stack at times. To prevent a stack
result =
sqlite3_prepare_v2 (dbh, zSql, strlen (zSql), ppStmt,
(const char **) &dummy);
-#if DEBUG_SQLITE && 0
GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
"Prepared `%s' / %p: %d\n", zSql, *ppStmt, result);
-#endif
return result;
}
/**
* Create our database indices.
- *
+ *
* @param dbh handle to the database
*/
static void
&plugin->updRepl) != SQLITE_OK) ||
(sq_prepare
(plugin->dbh,
- "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ "
- "FROM gn090 INDEXED BY idx_repl_rvalue " "WHERE repl=?2 AND"
- " (rvalue>=?1 OR"
- " NOT EXISTS (SELECT 1 FROM gn090 INDEXED BY idx_repl_rvalue WHERE repl=?2 AND rvalue>=?1 LIMIT 1))"
- " ORDER BY rvalue ASC" " LIMIT 1",
- &plugin->selRepl) != SQLITE_OK) ||
- (sq_prepare
- (plugin->dbh,
- "SELECT MAX(repl) " "FROM gn090 INDEXED BY idx_repl_rvalue",
- &plugin->maxRepl) != SQLITE_OK) ||
+ "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
+#if SQLITE_VERSION_NUMBER >= 3007000
+ "INDEXED BY idx_repl_rvalue "
+#endif
+ "WHERE repl=?2 AND " " (rvalue>=?1 OR "
+ " NOT EXISTS (SELECT 1 FROM gn090 "
+#if SQLITE_VERSION_NUMBER >= 3007000
+ "INDEXED BY idx_repl_rvalue "
+#endif
+ "WHERE repl=?2 AND rvalue>=?1 LIMIT 1) ) "
+ "ORDER BY rvalue ASC LIMIT 1", &plugin->selRepl) != SQLITE_OK) ||
+ (sq_prepare (plugin->dbh, "SELECT MAX(repl) FROM gn090"
+#if SQLITE_VERSION_NUMBER >= 3007000
+ " INDEXED BY idx_repl_rvalue"
+#endif
+ "", &plugin->maxRepl) != SQLITE_OK) ||
(sq_prepare
(plugin->dbh,
- "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ "
- "FROM gn090 INDEXED BY idx_expire"
- " WHERE NOT EXISTS (SELECT 1 FROM gn090 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) "
- " ORDER BY expire ASC LIMIT 1", &plugin->selExpi) != SQLITE_OK) ||
+ "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
+#if SQLITE_VERSION_NUMBER >= 3007000
+ "INDEXED BY idx_expire "
+#endif
+ "WHERE NOT EXISTS (SELECT 1 FROM gn090 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) "
+ "ORDER BY expire ASC LIMIT 1", &plugin->selExpi) != SQLITE_OK) ||
(sq_prepare
(plugin->dbh,
- "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ "
- "FROM gn090 INDEXED BY idx_anon_type_hash "
+ "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
+#if SQLITE_VERSION_NUMBER >= 3007000
+ "INDEXED BY idx_anon_type_hash "
+#endif
"WHERE (anonLevel = 0 AND type=?1) "
"ORDER BY hash DESC LIMIT 1 OFFSET ?2",
&plugin->selZeroAnon) != SQLITE_OK) ||
(sq_prepare
(plugin->dbh,
- "INSERT INTO gn090 (repl, type, prio, "
- "anonLevel, expire, rvalue, hash, vhash, value) "
+ "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
&plugin->insertContent) != SQLITE_OK) ||
(sq_prepare
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",
+ GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite",
"Failed to close statement %p: %d\n", stmt, result);
-#endif
stmt = sqlite3_next_stmt (plugin->dbh, NULL);
}
result = sqlite3_close (plugin->dbh);
if (size > MAX_ITEM_SIZE)
return GNUNET_SYSERR;
-#if DEBUG_SQLITE
GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
"Storing in database block with type %u/key `%s'/priority %u/expiration in %llu ms (%lld).\n",
type, GNUNET_h2s (key), priority,
(unsigned long long)
GNUNET_TIME_absolute_get_remaining (expiration).rel_value,
(long long) expiration.abs_value);
-#endif
GNUNET_CRYPTO_hash (data, size, &vhash);
stmt = plugin->insertContent;
rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
{
case SQLITE_DONE:
plugin->env->duc (plugin->env->cls, size + GNUNET_DATASTORE_ENTRY_OVERHEAD);
-#if DEBUG_SQLITE
GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
"Stored new entry (%u bytes)\n",
size + GNUNET_DATASTORE_ENTRY_OVERHEAD);
-#endif
ret = GNUNET_OK;
break;
case SQLITE_BUSY:
switch (n)
{
case SQLITE_DONE:
-#if DEBUG_SQLITE
GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Block updated\n");
-#endif
return GNUNET_OK;
case SQLITE_BUSY:
LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
break;
}
expiration.abs_value = sqlite3_column_int64 (stmt, 3);
-#if DEBUG_SQLITE
GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
"Found reply in database with expiration %llu\n",
(unsigned long long) expiration.abs_value);
-#endif
ret = proc (proc_cls, sqlite3_column_blob (stmt, 4) /* key */ ,
size, sqlite3_column_blob (stmt, 5) /* data */ ,
sqlite3_column_int (stmt, 0) /* type */ ,
* the given processor for the item.
*
* @param cls our plugin context
- * @param offset offset of the result (modulo num-results);
+ * @param offset offset of the result (modulo num-results);
* specific ordering does not matter for the offset
* @param type entries of which type should be considered?
* Use 0 for any type.
/**
* Get a random item for replication. Returns a single random item
- * from those with the highest replication counters. The item's
+ * from those with the highest replication counters. The item's
* replication counter is decremented by one IF it was positive before.
* Call 'proc' with all values ZERO or NULL if the datastore is empty.
*
uint32_t repl;
sqlite3_stmt *stmt;
-#if DEBUG_SQLITE
GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
"Getting random block based on replication order.\n");
-#endif
rc.have_uid = GNUNET_NO;
rc.proc = proc;
rc.proc_cls = proc_cls;
sqlite3_stmt *stmt;
struct GNUNET_TIME_Absolute now;
-#if DEBUG_SQLITE
GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
"Getting random block based on expiration and priority order.\n");
-#endif
now = GNUNET_TIME_absolute_get ();
stmt = plugin->selExpi;
if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, now.abs_value))
}
+
+/**
+ * Get all of the keys in the datastore.
+ *
+ * @param cls closure
+ * @param proc function to call on each key
+ * @param proc_cls closure for proc
+ */
+static void
+sqlite_plugin_get_keys (void *cls,
+ PluginKeyProcessor proc,
+ void *proc_cls)
+{
+ struct Plugin *plugin = cls;
+ const GNUNET_HashCode *key;
+ sqlite3_stmt *stmt;
+ int ret;
+
+ GNUNET_assert (proc != NULL);
+ if (sq_prepare (plugin->dbh, "SELECT hash FROM gn090", &stmt) != SQLITE_OK)
+ {
+ LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "sqlite_prepare");
+ return;
+ }
+ while (SQLITE_ROW == (ret = sqlite3_step (stmt)))
+ {
+ key = sqlite3_column_blob (stmt, 1);
+ if (sizeof (GNUNET_HashCode) == sqlite3_column_bytes (stmt, 1))
+ proc (proc_cls, key, 1);
+ }
+ if (SQLITE_DONE != ret)
+ LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite_step");
+ sqlite3_finalize (stmt);
+}
+
+
/**
* Drop database.
*
api->get_replication = &sqlite_plugin_get_replication;
api->get_expiration = &sqlite_plugin_get_expiration;
api->get_zero_anonymity = &sqlite_plugin_get_zero_anonymity;
+ api->get_keys = &sqlite_plugin_get_keys;
api->drop = &sqlite_plugin_drop;
GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "sqlite",
_("Sqlite database running\n"));
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 done\n");
-#endif
-
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);
GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
GNUNET_free (fn);
}
-#if DEBUG_SQLITE
GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
"sqlite plugin is finished\n");
-#endif
return NULL;
}