X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fdatastore%2Fplugin_datastore_sqlite.c;h=f14855219c411cac571014fff0423ee140fa21d3;hb=ae64def363d4eeeaf8acfe586f00ae962da479fb;hp=85657663ccaebb2d05c280f52066c5271098f23e;hpb=315d8796d3bc43970905e1c141f97b9f8ddad02d;p=oweals%2Fgnunet.git diff --git a/src/datastore/plugin_datastore_sqlite.c b/src/datastore/plugin_datastore_sqlite.c index 85657663c..f14855219 100644 --- a/src/datastore/plugin_datastore_sqlite.c +++ b/src/datastore/plugin_datastore_sqlite.c @@ -1,10 +1,10 @@ /* This file is part of GNUnet - (C) 2009 Christian Grothoff (and other contributing authors) + (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 2, or (at your + 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 @@ -25,58 +25,20 @@ */ #include "platform.h" -#include "gnunet_statistics_service.h" -#include "plugin_datastore.h" +#include "gnunet_datastore_plugin.h" #include -#define DEBUG_SQLITE GNUNET_YES - /** - * After how many payload-changing operations - * do we sync our statistics? + * Enable or disable logging debug messages. */ -#define MAX_STAT_SYNC_LAG 50 - -#define QUOTA_STAT_NAME gettext_noop ("file-sharing datastore utilization (in bytes)") +#define DEBUG_SQLITE GNUNET_NO /** - * Log an error message at log-level 'level' that indicates - * a failure of the command 'cmd' on file 'filename' - * with the message given by strerror(errno). + * We allocate items on the stack at times. To prevent a stack + * overflow, we impose a limit on the maximum size for the data per + * item. 64k should be enough. */ -#define LOG_SQLITE(db, msg, level, cmd) do { GNUNET_log_from (level, "sqlite", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); if (msg != NULL) GNUNET_asprintf(msg, _("`%s' failed with error: %s"), cmd, sqlite3_errmsg(db->dbh)); } while(0) - -#define SELECT_IT_LOW_PRIORITY_1 \ - "SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (prio = ? AND hash > ?) "\ - "ORDER BY hash ASC LIMIT 1" - -#define SELECT_IT_LOW_PRIORITY_2 \ - "SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (prio > ?) "\ - "ORDER BY prio ASC, hash ASC LIMIT 1" - -#define SELECT_IT_NON_ANONYMOUS_1 \ - "SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (prio = ? AND hash < ? AND anonLevel = 0 AND expire > %llu) "\ - " ORDER BY hash DESC LIMIT 1" - -#define SELECT_IT_NON_ANONYMOUS_2 \ - "SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (prio < ? AND anonLevel = 0 AND expire > %llu)"\ - " ORDER BY prio DESC, hash DESC LIMIT 1" - -#define SELECT_IT_EXPIRATION_TIME_1 \ - "SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (expire = ? AND hash > ?) "\ - " ORDER BY hash ASC LIMIT 1" - -#define SELECT_IT_EXPIRATION_TIME_2 \ - "SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (expire > ?) "\ - " ORDER BY expire ASC, hash ASC LIMIT 1" - -#define SELECT_IT_MIGRATION_ORDER_1 \ - "SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (expire = ? AND hash < ?) "\ - " ORDER BY hash DESC LIMIT 1" - -#define SELECT_IT_MIGRATION_ORDER_2 \ - "SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (expire < ? AND expire > %llu) "\ - " ORDER BY expire DESC, hash DESC LIMIT 1" +#define MAX_ITEM_SIZE 65536 /** * After how many ms "busy" should a DB operation fail for good? @@ -91,6 +53,14 @@ #define BUSY_TIMEOUT_MS 250 +/** + * Log an error message at log-level 'level' that indicates + * a failure of the command 'cmd' on file 'filename' + * with the message given by strerror(errno). + */ +#define LOG_SQLITE(db, msg, level, cmd) do { GNUNET_log_from (level, "sqlite", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); if (msg != NULL) GNUNET_asprintf(msg, _("`%s' failed at %s:%u with error: %s"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); } while(0) + + /** * Context for all functions in this plugin. @@ -112,25 +82,35 @@ struct Plugin */ sqlite3 *dbh; + /** + * Precompiled SQL for deletion. + */ + sqlite3_stmt *delRow; + /** * Precompiled SQL for update. */ sqlite3_stmt *updPrio; /** - * Precompiled SQL for insertion. + * Precompiled SQL for replication decrement. */ - sqlite3_stmt *insertContent; + sqlite3_stmt *updRepl; /** - * Handle to the statistics service. + * Precompiled SQL for replication selection. */ - struct GNUNET_STATISTICS_Handle *statistics; + sqlite3_stmt *selRepl; /** - * Handle for pending get request. + * Precompiled SQL for expiration selection. */ - struct GNUNET_STATISTICS_GetHandle *stat_get; + sqlite3_stmt *selExpi; + + /** + * Precompiled SQL for insertion. + */ + sqlite3_stmt *insertContent; /** * Closure of the 'next_task' (must be freed if 'next_task' is cancelled). @@ -141,29 +121,12 @@ struct Plugin * Pending task with scheduler for running the next request. */ GNUNET_SCHEDULER_TaskIdentifier next_task; - - /** - * How much data are we currently storing - * in the database? - */ - unsigned long long payload; - - /** - * Number of updates that were made to the - * payload value since we last synchronized - * it with the statistics service. - */ - unsigned int lastSync; /** * Should the database be dropped on shutdown? */ int drop_on_shutdown; - /** - * Did we get an answer from statistics? - */ - int stats_worked; }; @@ -176,13 +139,27 @@ struct Plugin * @return 0 on success */ static int -sq_prepare (sqlite3 * dbh, const char *zSql, +sq_prepare (sqlite3 * dbh, + const char *zSql, sqlite3_stmt ** ppStmt) { char *dummy; - return sqlite3_prepare (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 && 0 + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "sqlite", + "Prepared `%s' / %p: %d\n", + zSql, + *ppStmt, + result); +#endif + return result; } @@ -196,36 +173,29 @@ create_indices (sqlite3 * dbh) { /* create indices */ sqlite3_exec (dbh, - "CREATE INDEX idx_hash ON gn080 (hash)", NULL, NULL, NULL); - sqlite3_exec (dbh, - "CREATE INDEX idx_hash_vhash ON gn080 (hash,vhash)", NULL, - NULL, NULL); - sqlite3_exec (dbh, "CREATE INDEX idx_prio ON gn080 (prio)", NULL, NULL, + "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 ON gn080 (expire)", NULL, NULL, + sqlite3_exec (dbh, "CREATE INDEX idx_expire_prio ON gn090 (expire,prio)", NULL, NULL, NULL); - sqlite3_exec (dbh, "CREATE INDEX idx_comb3 ON gn080 (prio,anonLevel)", NULL, + sqlite3_exec (dbh, + "CREATE INDEX idx_hash_vhash ON gn090 (hash,vhash)", NULL, NULL, NULL); - sqlite3_exec (dbh, "CREATE INDEX idx_comb4 ON gn080 (prio,hash,anonLevel)", + sqlite3_exec (dbh, "CREATE INDEX idx_comb ON gn090 (prio,expire,anonLevel,hash)", NULL, NULL, NULL); - sqlite3_exec (dbh, "CREATE INDEX idx_comb7 ON gn080 (expire,hash)", NULL, - NULL, NULL); } - -#if 1 +#if 0 #define CHECK(a) GNUNET_break(a) #define ENULL NULL #else #define ENULL &e #define ENULL_DEFINED 1 -#define CHECK(a) if (! a) { GNUNET_log(GNUNET_ERROR_TYPE_ERRROR, "%s\n", e); sqlite3_free(e); } +#define CHECK(a) if (! a) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", e); sqlite3_free(e); } #endif - - /** * Initialize the database connections and associated * data structures (create tables and indices @@ -258,19 +228,24 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg, "datastore-sqlite"); return GNUNET_SYSERR; } - if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (afsdir)) + if (GNUNET_OK != GNUNET_DISK_file_test (afsdir)) { - GNUNET_break (0); - GNUNET_free (afsdir); - return GNUNET_SYSERR; + if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (afsdir)) + { + GNUNET_break (0); + GNUNET_free (afsdir); + return GNUNET_SYSERR; + } + /* database is new or got deleted, reset payload to zero! */ + plugin->env->duc (plugin->env->cls, 0); } - plugin->fn = GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), #ifdef ENABLE_NLS - nl_langinfo (CODESET) + plugin->fn = GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), + nl_langinfo (CODESET)); #else - "UTF-8" /* good luck */ + plugin->fn = GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), + "UTF-8"); /* good luck */ #endif - ); GNUNET_free (afsdir); /* Open database and precompile statements */ @@ -304,12 +279,12 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg, /* We have to do it here, because otherwise precompiling SQL might fail */ CHECK (SQLITE_OK == sq_prepare (plugin->dbh, - "SELECT 1 FROM sqlite_master WHERE tbl_name = 'gn080'", + "SELECT 1 FROM sqlite_master WHERE tbl_name = 'gn090'", &stmt)); if ( (sqlite3_step (stmt) == SQLITE_DONE) && (sqlite3_exec (plugin->dbh, - "CREATE TABLE gn080 (" - " size INT4 NOT NULL DEFAULT 0," + "CREATE TABLE gn090 (" + " repl INT4 NOT NULL DEFAULT 0," " type INT4 NOT NULL DEFAULT 0," " prio INT4 NOT NULL DEFAULT 0," " anonLevel INT4 NOT NULL DEFAULT 0," @@ -347,36 +322,37 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg, sqlite3_finalize (stmt); if ((sq_prepare (plugin->dbh, - "UPDATE gn080 SET prio = prio + ?, expire = MAX(expire,?) WHERE " + "UPDATE gn090 SET prio = prio + ?, expire = MAX(expire,?) WHERE " "_ROWID_ = ?", &plugin->updPrio) != SQLITE_OK) || (sq_prepare (plugin->dbh, - "INSERT INTO gn080 (size, type, prio, " + "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) " + " 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)) " + " 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 " "(?, ?, ?, ?, ?, ?, ?, ?)", - &plugin->insertContent) != SQLITE_OK)) + &plugin->insertContent) != SQLITE_OK) || + (sq_prepare (plugin->dbh, + "DELETE FROM gn090 WHERE _ROWID_ = ?", + &plugin->delRow) != SQLITE_OK)) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR, "precompiling"); return GNUNET_SYSERR; } - return GNUNET_OK; -} - -/** - * Synchronize our utilization statistics with the - * statistics service. - * @param plugin the plugin context (state for this module) - */ -static void -sync_stats (struct Plugin *plugin) -{ - GNUNET_STATISTICS_set (plugin->statistics, - QUOTA_STAT_NAME, - plugin->payload, - GNUNET_YES); - plugin->lastSync = 0; + return GNUNET_OK; } @@ -388,28 +364,55 @@ sync_stats (struct Plugin *plugin) static void database_shutdown (struct Plugin *plugin) { - if (plugin->lastSync > 0) - sync_stats (plugin); + int result; +#if SQLITE_VERSION_NUMBER >= 3007000 + sqlite3_stmt *stmt; +#endif + + if (plugin->delRow != NULL) + sqlite3_finalize (plugin->delRow); if (plugin->updPrio != NULL) sqlite3_finalize (plugin->updPrio); + if (plugin->updRepl != NULL) + sqlite3_finalize (plugin->updRepl); + if (plugin->selRepl != NULL) + sqlite3_finalize (plugin->selRepl); + if (plugin->selExpi != NULL) + sqlite3_finalize (plugin->selExpi); if (plugin->insertContent != NULL) sqlite3_finalize (plugin->insertContent); - sqlite3_close (plugin->dbh); - GNUNET_free_non_null (plugin->fn); -} - + 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, NULL, + GNUNET_ERROR_TYPE_ERROR, + "sqlite3_close"); -/** - * Get an estimate of how much space the database is - * currently using. - * - * @param cls our plugin context - * @return number of bytes used on disk - */ -static unsigned long long sqlite_plugin_get_size (void *cls) -{ - struct Plugin *plugin = cls; - return plugin->payload; + GNUNET_free_non_null (plugin->fn); } @@ -424,26 +427,22 @@ 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) - { - LOG_SQLITE (plugin, NULL, - GNUNET_ERROR_TYPE_ERROR | - GNUNET_ERROR_TYPE_BULK, "sq_prepare"); - return GNUNET_SYSERR; - } - sqlite3_bind_int64 (stmt, 1, rid); - if (SQLITE_DONE != sqlite3_step (stmt)) + 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, "sqlite3_step"); - sqlite3_finalize (stmt); + 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_finalize (stmt); + if (SQLITE_OK != sqlite3_reset (plugin->delRow)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | + GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return GNUNET_OK; } @@ -515,11 +514,6 @@ struct NextContext */ GNUNET_HashCode lastKey; - /** - * Expiration time of the last value visited. - */ - struct GNUNET_TIME_Absolute lastExpiration; - /** * Priority of the last value visited. */ @@ -540,7 +534,7 @@ struct NextContext /** * Continuation of "sqlite_next_request". * - * @param cls the next context + * @param cls the 'struct NextContext*' * @param tc the task context (unused) */ static void @@ -550,15 +544,14 @@ sqlite_next_request_cont (void *cls, struct NextContext * nc = cls; struct Plugin *plugin; unsigned long long rowid; - sqlite3_stmt *stmtd; int ret; - unsigned int type; unsigned int size; - unsigned int priority; - unsigned int anonymity; - struct GNUNET_TIME_Absolute expiration; + unsigned int hsize; + uint32_t anonymity; + uint32_t priority; + enum GNUNET_BLOCK_Type type; const GNUNET_HashCode *key; - const void *data; + struct GNUNET_TIME_Absolute expiration; plugin = nc->plugin; plugin->next_task = GNUNET_SCHEDULER_NO_TASK; @@ -567,6 +560,12 @@ sqlite_next_request_cont (void *cls, (GNUNET_OK != (nc->prep(nc->prep_cls, nc))) ) { +#if DEBUG_SQLITE + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "sqlite", + "Iteration completes after %u results\n", + nc->count); +#endif END: nc->iter (nc->iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, @@ -576,106 +575,97 @@ sqlite_next_request_cont (void *cls, return; } - rowid = sqlite3_column_int64 (nc->stmt, 7); - nc->last_rowid = rowid; - type = sqlite3_column_int (nc->stmt, 1); - size = sqlite3_column_bytes (nc->stmt, 6); - if (sqlite3_column_bytes (nc->stmt, 5) != sizeof (GNUNET_HashCode)) + type = sqlite3_column_int (nc->stmt, 0); + priority = sqlite3_column_int (nc->stmt, 1); + anonymity = sqlite3_column_int (nc->stmt, 2); + expiration.abs_value = sqlite3_column_int64 (nc->stmt, 3); + hsize = sqlite3_column_bytes (nc->stmt, 4); + key = sqlite3_column_blob (nc->stmt, 4); + size = sqlite3_column_bytes (nc->stmt, 5); + rowid = sqlite3_column_int64 (nc->stmt, 6); + if (hsize != sizeof (GNUNET_HashCode)) { - GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, - "sqlite", - _("Invalid data in database. Trying to fix (by deletion).\n")); + GNUNET_break (0); if (SQLITE_OK != sqlite3_reset (nc->stmt)) - LOG_SQLITE (nc->plugin, NULL, - GNUNET_ERROR_TYPE_ERROR | - GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); - if (sq_prepare - (nc->plugin->dbh, - "DELETE FROM gn080 WHERE NOT LENGTH(hash) = ?", - &stmtd) != SQLITE_OK) - { - LOG_SQLITE (nc->plugin, NULL, - GNUNET_ERROR_TYPE_ERROR | - GNUNET_ERROR_TYPE_BULK, - "sq_prepare"); - goto END; - } - - if (SQLITE_OK != sqlite3_bind_int (stmtd, 1, sizeof (GNUNET_HashCode))) - LOG_SQLITE (nc->plugin, NULL, - GNUNET_ERROR_TYPE_ERROR | - GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_int"); - if (SQLITE_DONE != sqlite3_step (stmtd)) - LOG_SQLITE (nc->plugin, NULL, - GNUNET_ERROR_TYPE_ERROR | - GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); - if (SQLITE_OK != sqlite3_finalize (stmtd)) - LOG_SQLITE (nc->plugin, NULL, - GNUNET_ERROR_TYPE_ERROR | - GNUNET_ERROR_TYPE_BULK, "sqlite3_finalize"); + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | + GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); + if (GNUNET_OK == delete_by_rowid (plugin, rowid)) + plugin->env->duc (plugin->env->cls, + - (size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); goto END; } - - priority = sqlite3_column_int (nc->stmt, 2); - anonymity = sqlite3_column_int (nc->stmt, 3); - expiration.value = sqlite3_column_int64 (nc->stmt, 4); - key = sqlite3_column_blob (nc->stmt, 5); - nc->lastPriority = priority; - nc->lastExpiration = expiration; - memcpy (&nc->lastKey, key, sizeof(GNUNET_HashCode)); - data = sqlite3_column_blob (nc->stmt, 6); - nc->count++; - ret = nc->iter (nc->iter_cls, - nc, - key, - size, - data, - type, - priority, - anonymity, - expiration, - rowid); - if (ret == GNUNET_SYSERR) - { - nc->end_it = GNUNET_YES; - return; - } #if DEBUG_SQLITE - if (ret == GNUNET_NO) - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "sqlite", - "Asked to remove entry %llu (%u bytes)\n", - (unsigned long long) rowid, - size + GNUNET_DATASTORE_ENTRY_OVERHEAD); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "sqlite", + "Iterator returns value with type %u/key `%s'/priority %u/expiration %llu (%lld).\n", + type, + GNUNET_h2s(key), + priority, + (unsigned long long) GNUNET_TIME_absolute_get_remaining (expiration).rel_value, + (long long) expiration.abs_value); #endif - if ( (ret == GNUNET_NO) && - (GNUNET_OK == delete_by_rowid (plugin, rowid)) ) + if (size > MAX_ITEM_SIZE) { - if (plugin->payload >= size + GNUNET_DATASTORE_ENTRY_OVERHEAD) - plugin->payload -= (size + GNUNET_DATASTORE_ENTRY_OVERHEAD); - else - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Datastore payload inaccurate, please fix and restart!\n")); - plugin->lastSync++; + GNUNET_break (0); + if (SQLITE_OK != sqlite3_reset (nc->stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | + GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); + if (GNUNET_OK == delete_by_rowid (plugin, rowid)) + plugin->env->duc (plugin->env->cls, + - (size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); + goto END; + } + { + char data[size]; + + memcpy (data, sqlite3_column_blob (nc->stmt, 5), size); + nc->count++; + nc->last_rowid = rowid; + nc->lastPriority = priority; + nc->lastKey = *key; + if (SQLITE_OK != sqlite3_reset (nc->stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | + GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); + ret = nc->iter (nc->iter_cls, nc, + &nc->lastKey, + size, data, + type, priority, + anonymity, expiration, + rowid); + } + switch (ret) + { + case GNUNET_SYSERR: + nc->end_it = GNUNET_YES; + break; + case GNUNET_NO: + if (GNUNET_OK == delete_by_rowid (plugin, rowid)) + { #if DEBUG_SQLITE - if (ret == GNUNET_NO) - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "sqlite", - "Removed entry %llu (%u bytes), new payload is %llu\n", - (unsigned long long) rowid, - size + GNUNET_DATASTORE_ENTRY_OVERHEAD, - plugin->payload); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "sqlite", + "Removed entry %llu (%u bytes)\n", + (unsigned long long) rowid, + size + GNUNET_DATASTORE_ENTRY_OVERHEAD); #endif - if (plugin->lastSync >= MAX_STAT_SYNC_LAG) - sync_stats (plugin); + plugin->env->duc (plugin->env->cls, + - (size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); + } + break; + case GNUNET_YES: + break; + default: + GNUNET_break (0); } } /** - * Function invoked on behalf of a "PluginIterator" - * asking the database plugin to call the iterator - * with the next item. + * Function invoked on behalf of a "PluginIterator" asking the + * database plugin to call the iterator with the next item. * * @param next_cls whatever argument was given * to the PluginIterator as "next_cls". @@ -693,13 +683,11 @@ sqlite_next_request (void *next_cls, if (GNUNET_YES == end_it) nc->end_it = GNUNET_YES; nc->plugin->next_task_nc = nc; - nc->plugin->next_task = GNUNET_SCHEDULER_add_now (nc->plugin->env->sched, - &sqlite_next_request_cont, + nc->plugin->next_task = GNUNET_SCHEDULER_add_now (&sqlite_next_request_cont, nc); } - /** * Store an item in the datastore. * @@ -710,26 +698,31 @@ sqlite_next_request (void *next_cls, * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content + * @param replication replication-level for the content * @param expiration expiration time for the content * @param msg set to an error message * @return GNUNET_OK on success */ static int sqlite_plugin_put (void *cls, - const GNUNET_HashCode * key, + const GNUNET_HashCode *key, uint32_t size, const void *data, - uint32_t type, + enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, + uint32_t replication, struct GNUNET_TIME_Absolute expiration, char ** msg) { struct Plugin *plugin = cls; int n; + int ret; sqlite3_stmt *stmt; GNUNET_HashCode vhash; + if (size > MAX_ITEM_SIZE) + return GNUNET_SYSERR; #if DEBUG_SQLITE GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", @@ -737,16 +730,16 @@ sqlite_plugin_put (void *cls, type, GNUNET_h2s(key), priority, - (unsigned long long) GNUNET_TIME_absolute_get_remaining (expiration).value, - (long long) expiration.value); + (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; - if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, size)) || + if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, replication)) || (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) || (SQLITE_OK != sqlite3_bind_int (stmt, 3, priority)) || (SQLITE_OK != sqlite3_bind_int (stmt, 4, anonymity)) || - (SQLITE_OK != sqlite3_bind_int64 (stmt, 5, (sqlite3_int64) expiration.value)) || + (SQLITE_OK != sqlite3_bind_int64 (stmt, 5, expiration.abs_value)) || (SQLITE_OK != sqlite3_bind_blob (stmt, 6, key, sizeof (GNUNET_HashCode), SQLITE_TRANSIENT)) || @@ -766,37 +759,44 @@ sqlite_plugin_put (void *cls, return GNUNET_SYSERR; } n = sqlite3_step (stmt); - if (n != SQLITE_DONE) + switch (n) { - if (n == SQLITE_BUSY) - { - LOG_SQLITE (plugin, msg, - GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); - sqlite3_reset (stmt); - GNUNET_break (0); - return GNUNET_NO; - } + 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: + GNUNET_break (0); LOG_SQLITE (plugin, msg, - GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); - sqlite3_reset (stmt); - return GNUNET_SYSERR; + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + ret = GNUNET_SYSERR; + break; + default: + LOG_SQLITE (plugin, msg, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | + GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); + database_shutdown (plugin); + database_setup (plugin->env->cfg, + plugin); + return GNUNET_SYSERR; } if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, - GNUNET_ERROR_TYPE_ERROR | - GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); - plugin->lastSync++; - plugin->payload += size + GNUNET_DATASTORE_ENTRY_OVERHEAD; -#if DEBUG_SQLITE - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "sqlite", - "Stored new entry (%u bytes), new payload is %llu\n", - size + GNUNET_DATASTORE_ENTRY_OVERHEAD, - plugin->payload); -#endif - if (plugin->lastSync >= MAX_STAT_SYNC_LAG) - sync_stats (plugin); - return GNUNET_OK; + GNUNET_ERROR_TYPE_ERROR | + GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); + return ret; } @@ -833,83 +833,69 @@ sqlite_plugin_update (void *cls, int n; sqlite3_bind_int (plugin->updPrio, 1, delta); - sqlite3_bind_int64 (plugin->updPrio, 2, expire.value); + sqlite3_bind_int64 (plugin->updPrio, 2, expire.abs_value); sqlite3_bind_int64 (plugin->updPrio, 3, uid); n = sqlite3_step (plugin->updPrio); - if (n != SQLITE_DONE) - LOG_SQLITE (plugin, msg, - GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); + sqlite3_reset (plugin->updPrio); + switch (n) + { + case SQLITE_DONE: #if DEBUG_SQLITE - else - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "sqlite", - "Block updated\n"); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "sqlite", + "Block updated\n"); #endif - sqlite3_reset (plugin->updPrio); - - if (n == SQLITE_BUSY) - return GNUNET_NO; - return n == SQLITE_DONE ? GNUNET_OK : GNUNET_SYSERR; + return GNUNET_OK; + case SQLITE_BUSY: + LOG_SQLITE (plugin, msg, + GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + return GNUNET_NO; + default: + LOG_SQLITE (plugin, msg, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + return GNUNET_SYSERR; + } } /** * Internal context for an iteration. */ -struct IterContext +struct ZeroIterContext { /** - * FIXME. + * First iterator statement for zero-anonymity iteration. */ sqlite3_stmt *stmt_1; /** - * FIXME. + * Second iterator statement for zero-anonymity iteration. */ sqlite3_stmt *stmt_2; - /** - * FIXME. - */ - int is_asc; - - /** - * FIXME. - */ - int is_prio; - - /** - * FIXME. - */ - int is_migr; - - /** - * FIXME. - */ - int limit_nonanonymous; - /** * Desired type for blocks returned by this iterator. */ - uint32_t type; + enum GNUNET_BLOCK_Type type; }; /** * Prepare our SQL query to obtain the next record from the database. * - * @param cls our "struct IterContext" + * @param cls our "struct ZeroIterContext" * @param nc NULL to terminate the iteration, otherwise our context for * getting the next result. * @return GNUNET_OK on success, GNUNET_NO if there are no more results, * GNUNET_SYSERR on error (or end of iteration) */ static int -iter_next_prepare (void *cls, - struct NextContext *nc) +zero_iter_next_prepare (void *cls, + struct NextContext *nc) { - struct IterContext *ic = cls; + struct ZeroIterContext *ic = cls; struct Plugin *plugin; int ret; @@ -923,38 +909,30 @@ iter_next_prepare (void *cls, sqlite3_finalize (ic->stmt_2); return GNUNET_SYSERR; } - sqlite3_reset (ic->stmt_1); - sqlite3_reset (ic->stmt_2); plugin = nc->plugin; - if (ic->is_prio) - { + + /* first try iter 1 */ #if DEBUG_SQLITE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Restricting to results larger than the last priority %u\n", - nc->lastPriority); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Restricting to results larger than the last priority %u and key `%s'\n", + nc->lastPriority, + GNUNET_h2s (&nc->lastKey)); #endif - sqlite3_bind_int (ic->stmt_1, 1, nc->lastPriority); - sqlite3_bind_int (ic->stmt_2, 1, nc->lastPriority); - } - else + if ( (SQLITE_OK != sqlite3_bind_int (ic->stmt_1, 1, nc->lastPriority)) || + (SQLITE_OK != sqlite3_bind_blob (ic->stmt_1, 2, + &nc->lastKey, + sizeof (GNUNET_HashCode), + SQLITE_TRANSIENT)) ) { -#if DEBUG_SQLITE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Restricting to results larger than the last expiration %llu\n", - (unsigned long long) nc->lastExpiration.value); -#endif - sqlite3_bind_int64 (ic->stmt_1, 1, nc->lastExpiration.value); - sqlite3_bind_int64 (ic->stmt_2, 1, nc->lastExpiration.value); + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); + if (SQLITE_OK != sqlite3_reset (ic->stmt_1)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | + GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + return GNUNET_SYSERR; } -#if DEBUG_SQLITE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Restricting to results larger than the last key `%s'\n", - GNUNET_h2s(&nc->lastKey)); -#endif - sqlite3_bind_blob (ic->stmt_1, 2, - &nc->lastKey, - sizeof (GNUNET_HashCode), - SQLITE_TRANSIENT); if (SQLITE_ROW == (ret = sqlite3_step (ic->stmt_1))) { #if DEBUG_SQLITE @@ -970,13 +948,26 @@ iter_next_prepare (void *cls, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); + if (SQLITE_OK != sqlite3_reset (ic->stmt_1)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | + GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); return GNUNET_SYSERR; } if (SQLITE_OK != sqlite3_reset (ic->stmt_1)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); + "sqlite3_reset"); + + /* now try iter 2 */ + if (SQLITE_OK != sqlite3_bind_int (ic->stmt_2, 1, nc->lastPriority)) + { + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); + return GNUNET_SYSERR; + } if (SQLITE_ROW == (ret = sqlite3_step (ic->stmt_2))) { #if DEBUG_SQLITE @@ -992,6 +983,11 @@ iter_next_prepare (void *cls, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); + if (SQLITE_OK != sqlite3_reset (ic->stmt_2)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | + GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); return GNUNET_SYSERR; } if (SQLITE_OK != sqlite3_reset (ic->stmt_2)) @@ -1008,238 +1004,109 @@ iter_next_prepare (void *cls, /** - * Call a method for each key in the database and - * call the callback method on it. + * Select a subset of the items in the datastore and call + * the given iterator for each of them. * - * @param plugin our plugin context + * @param cls our plugin context * @param type entries of which type should be considered? - * @param is_asc are we iterating in ascending order? - * @param is_prio are we iterating by priority (otherwise by expiration) - * @param is_migr are we iterating in migration order? - * @param limit_nonanonymous are we restricting results to those with anonymity - * level zero? - * @param stmt_str_1 first SQL statement to execute - * @param stmt_str_2 SQL statement to execute to get "more" results (inner iteration) + * Use 0 for any type. * @param iter function to call on each matching value; * will be called once with a NULL value at the end * @param iter_cls closure for iter */ static void -basic_iter (struct Plugin *plugin, - uint32_t type, - int is_asc, - int is_prio, - int is_migr, - int limit_nonanonymous, - const char *stmt_str_1, - const char *stmt_str_2, - PluginIterator iter, - void *iter_cls) +sqlite_plugin_iter_zero_anonymity (void *cls, + enum GNUNET_BLOCK_Type type, + PluginIterator iter, + void *iter_cls) { + struct Plugin *plugin = cls; + struct GNUNET_TIME_Absolute now; struct NextContext *nc; - struct IterContext *ic; + struct ZeroIterContext *ic; sqlite3_stmt *stmt_1; sqlite3_stmt *stmt_2; + char *q; -#if DEBUG_SQLITE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "At %llu, using queries `%s' and `%s'\n", - (unsigned long long) GNUNET_TIME_absolute_get ().value, - stmt_str_1, - stmt_str_2); -#endif - if (sq_prepare (plugin->dbh, stmt_str_1, &stmt_1) != SQLITE_OK) + 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 hash < ?2) " + "ORDER BY hash DESC LIMIT 1", + (unsigned long long) now.abs_value); + if (sq_prepare (plugin->dbh, q, &stmt_1) != SQLITE_OK) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | - GNUNET_ERROR_TYPE_BULK, "sqlite3_prepare"); + GNUNET_ERROR_TYPE_BULK, "sqlite3_prepare_v2"); iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + GNUNET_free (q); return; } - if (sq_prepare (plugin->dbh, stmt_str_2, &stmt_2) != SQLITE_OK) + 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) " + "ORDER BY prio DESC, hash DESC LIMIT 1", + (unsigned long long) now.abs_value); + if (sq_prepare (plugin->dbh, q, &stmt_2) != SQLITE_OK) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | - GNUNET_ERROR_TYPE_BULK, "sqlite3_prepare"); + GNUNET_ERROR_TYPE_BULK, "sqlite3_prepare_v2"); sqlite3_finalize (stmt_1); iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + GNUNET_free (q); return; } + GNUNET_free (q); nc = GNUNET_malloc (sizeof(struct NextContext) + - sizeof(struct IterContext)); + sizeof(struct ZeroIterContext)); nc->plugin = plugin; nc->iter = iter; nc->iter_cls = iter_cls; nc->stmt = NULL; - ic = (struct IterContext*) &nc[1]; + ic = (struct ZeroIterContext*) &nc[1]; ic->stmt_1 = stmt_1; ic->stmt_2 = stmt_2; ic->type = type; - ic->is_asc = is_asc; - ic->is_prio = is_prio; - ic->is_migr = is_migr; - ic->limit_nonanonymous = limit_nonanonymous; - nc->prep = &iter_next_prepare; + nc->prep = &zero_iter_next_prepare; nc->prep_cls = ic; - if (is_asc) - { - nc->lastPriority = 0; - nc->lastExpiration.value = 0; - memset (&nc->lastKey, 0, sizeof (GNUNET_HashCode)); - } - else - { - nc->lastPriority = 0x7FFFFFFF; - nc->lastExpiration.value = 0x7FFFFFFFFFFFFFFFLL; - memset (&nc->lastKey, 255, sizeof (GNUNET_HashCode)); - } + nc->lastPriority = INT32_MAX; + memset (&nc->lastKey, 255, sizeof (GNUNET_HashCode)); sqlite_next_request (nc, GNUNET_NO); } /** - * Select a subset of the items in the datastore and call - * the given iterator for each of them. - * - * @param cls our plugin context - * @param type entries of which type should be considered? - * Use 0 for any type. - * @param iter function to call on each matching value; - * will be called once with a NULL value at the end - * @param iter_cls closure for iter - */ -static void -sqlite_plugin_iter_low_priority (void *cls, - uint32_t type, - PluginIterator iter, - void *iter_cls) -{ - basic_iter (cls, - type, - GNUNET_YES, GNUNET_YES, - GNUNET_NO, GNUNET_NO, - SELECT_IT_LOW_PRIORITY_1, - SELECT_IT_LOW_PRIORITY_2, - iter, iter_cls); -} - - -/** - * Select a subset of the items in the datastore and call - * the given iterator for each of them. - * - * @param cls our plugin context - * @param type entries of which type should be considered? - * Use 0 for any type. - * @param iter function to call on each matching value; - * will be called once with a NULL value at the end - * @param iter_cls closure for iter - */ -static void -sqlite_plugin_iter_zero_anonymity (void *cls, - uint32_t type, - PluginIterator iter, - void *iter_cls) -{ - struct GNUNET_TIME_Absolute now; - char *q1; - char *q2; - - now = GNUNET_TIME_absolute_get (); - GNUNET_asprintf (&q1, SELECT_IT_NON_ANONYMOUS_1, - (unsigned long long) now.value); - GNUNET_asprintf (&q2, SELECT_IT_NON_ANONYMOUS_2, - (unsigned long long) now.value); - basic_iter (cls, - type, - GNUNET_NO, GNUNET_YES, - GNUNET_NO, GNUNET_YES, - q1, - q2, - iter, iter_cls); - GNUNET_free (q1); - GNUNET_free (q2); -} - - - -/** - * Select a subset of the items in the datastore and call - * the given iterator for each of them. - * - * @param cls our plugin context - * @param type entries of which type should be considered? - * Use 0 for any type. - * @param iter function to call on each matching value; - * will be called once with a NULL value at the end - * @param iter_cls closure for iter + * Closure for 'all_next_prepare'. */ -static void -sqlite_plugin_iter_ascending_expiration (void *cls, - uint32_t type, - PluginIterator iter, - void *iter_cls) +struct IterateAllContext { - struct GNUNET_TIME_Absolute now; - char *q1; - char *q2; - - now = GNUNET_TIME_absolute_get (); - GNUNET_asprintf (&q1, SELECT_IT_EXPIRATION_TIME_1, - (unsigned long long) 0*now.value); - GNUNET_asprintf (&q2, SELECT_IT_EXPIRATION_TIME_2, - (unsigned long long) 0*now.value); - basic_iter (cls, - type, - GNUNET_YES, GNUNET_NO, - GNUNET_NO, GNUNET_NO, - q1, q2, - iter, iter_cls); - GNUNET_free (q1); - GNUNET_free (q2); -} + /** + * Offset for the current result. + */ + unsigned int off; -/** - * Select a subset of the items in the datastore and call - * the given iterator for each of them. - * - * @param cls our plugin context - * @param type entries of which type should be considered? - * Use 0 for any type. - * @param iter function to call on each matching value; - * will be called once with a NULL value at the end - * @param iter_cls closure for iter - */ -static void -sqlite_plugin_iter_migration_order (void *cls, - uint32_t type, - PluginIterator iter, - void *iter_cls) -{ - struct GNUNET_TIME_Absolute now; - char *q; + /** + * Requested block type. + */ + enum GNUNET_BLOCK_Type type; - now = GNUNET_TIME_absolute_get (); - GNUNET_asprintf (&q, SELECT_IT_MIGRATION_ORDER_2, - (unsigned long long) now.value); - basic_iter (cls, - type, - GNUNET_NO, GNUNET_NO, - GNUNET_YES, GNUNET_NO, - SELECT_IT_MIGRATION_ORDER_1, - q, - iter, iter_cls); - GNUNET_free (q); -} + /** + * Our prepared statement. + */ + sqlite3_stmt *stmt; +}; /** * Call sqlite using the already prepared query to get * the next result. * - * @param cls not used - * @param nc context with the prepared query + * @param cls context with the prepared query (of type 'struct IterateAllContext') + * @param nc generic context with the prepared query * @return GNUNET_OK on success, GNUNET_SYSERR on error, GNUNET_NO if * there are no more results */ @@ -1247,8 +1114,10 @@ static int all_next_prepare (void *cls, struct NextContext *nc) { + struct IterateAllContext *iac = cls; struct Plugin *plugin; - int ret; + int ret; + unsigned int sqoff; if (nc == NULL) { @@ -1256,22 +1125,40 @@ all_next_prepare (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asked to clean up iterator state.\n"); #endif + if (NULL != iac->stmt) + { + sqlite3_finalize (iac->stmt); + iac->stmt = NULL; + } return GNUNET_SYSERR; } plugin = nc->plugin; - if (SQLITE_ROW == (ret = sqlite3_step (nc->stmt))) - { - return GNUNET_OK; + sqoff = 1; + ret = SQLITE_OK; + if (iac->type != 0) + ret = sqlite3_bind_int (nc->stmt, sqoff++, iac->type); + if (SQLITE_OK == ret) + ret = sqlite3_bind_int64 (nc->stmt, sqoff++, iac->off++); + if (ret != SQLITE_OK) + { + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); + return GNUNET_SYSERR; } - if (ret != SQLITE_DONE) + ret = sqlite3_step (nc->stmt); + switch (ret) { + case SQLITE_ROW: + return GNUNET_OK; + case SQLITE_DONE: + return GNUNET_NO; + default: LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); return GNUNET_SYSERR; } - return GNUNET_NO; } @@ -1288,84 +1175,99 @@ all_next_prepare (void *cls, */ static void sqlite_plugin_iter_all_now (void *cls, - uint32_t type, + enum GNUNET_BLOCK_Type type, PluginIterator iter, void *iter_cls) { struct Plugin *plugin = cls; struct NextContext *nc; + struct IterateAllContext *iac; sqlite3_stmt *stmt; + const char *q; - if (sq_prepare (plugin->dbh, - "SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080", - &stmt) != SQLITE_OK) + if (type == 0) + q = "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn090 ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?"; + else + q = "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn090 WHERE type=? ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?"; + if (sq_prepare (plugin->dbh, q, &stmt) != SQLITE_OK) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | - GNUNET_ERROR_TYPE_BULK, "sqlite3_prepare"); + GNUNET_ERROR_TYPE_BULK, "sqlite3_prepare_v2"); iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } - nc = GNUNET_malloc (sizeof(struct NextContext)); + nc = GNUNET_malloc (sizeof(struct NextContext) + + sizeof(struct IterateAllContext)); + iac = (struct IterateAllContext*) &nc[1]; nc->plugin = plugin; nc->iter = iter; nc->iter_cls = iter_cls; nc->stmt = stmt; nc->prep = &all_next_prepare; - nc->prep_cls = NULL; + nc->prep_cls = iac; + iac->off = 0; + iac->type = type; + iac->stmt = stmt; /* alias used for freeing at the end */ sqlite_next_request (nc, GNUNET_NO); } /** - * FIXME. + * Context for get_next_prepare. */ struct GetNextContext { /** - * FIXME. + * Our prepared statement. */ - int total; + sqlite3_stmt *stmt; /** - * FIXME. + * Plugin handle. */ - int off; + struct Plugin *plugin; /** - * FIXME. + * Key for the query. */ - int have_vhash; + GNUNET_HashCode key; /** - * FIXME. + * Vhash for the query. */ - unsigned int type; + GNUNET_HashCode vhash; /** - * FIXME. + * Expected total number of results. */ - sqlite3_stmt *stmt; + unsigned int total; /** - * FIXME. + * Offset to add for the selected result. */ - GNUNET_HashCode key; + unsigned int off; /** - * FIXME. + * Is vhash set? */ - GNUNET_HashCode vhash; -}; + int have_vhash; + /** + * Desired block type. + */ + enum GNUNET_BLOCK_Type type; + +}; /** - * FIXME. + * Prepare the stmt in 'nc' for the next round of execution, selecting the + * next return value. * * @param cls our "struct GetNextContext*" - * @param nc FIXME + * @param nc the general context * @return GNUNET_YES if there are more results, * GNUNET_NO if there are no more results, * GNUNET_SYSERR on internal error @@ -1375,9 +1277,9 @@ get_next_prepare (void *cls, struct NextContext *nc) { struct GetNextContext *gnc = cls; - int sqoff; int ret; int limit_off; + unsigned int sqoff; if (nc == NULL) { @@ -1392,8 +1294,8 @@ get_next_prepare (void *cls, limit_off = gnc->off; else limit_off = 0; - sqoff = 1; sqlite3_reset (nc->stmt); + sqoff = 1; ret = sqlite3_bind_blob (nc->stmt, sqoff++, &gnc->key, @@ -1407,14 +1309,31 @@ get_next_prepare (void *cls, if ((gnc->type != 0) && (ret == SQLITE_OK)) ret = sqlite3_bind_int (nc->stmt, sqoff++, gnc->type); if (ret == SQLITE_OK) - ret = sqlite3_bind_int64 (nc->stmt, sqoff++, nc->last_rowid + 1); - if (ret == SQLITE_OK) - ret = sqlite3_bind_int (nc->stmt, sqoff++, limit_off); + ret = sqlite3_bind_int64 (nc->stmt, sqoff++, limit_off); if (ret != SQLITE_OK) return GNUNET_SYSERR; - if (SQLITE_ROW != sqlite3_step (nc->stmt)) - return GNUNET_NO; - return GNUNET_OK; +#if DEBUG_SQLITE + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "sqlite", + "Preparing to GET for key `%s' with type %d at offset %u\n", + GNUNET_h2s (&gnc->key), + gnc->type, + limit_off); +#endif + ret = sqlite3_step (nc->stmt); + switch (ret) + { + case SQLITE_ROW: + return GNUNET_OK; + case SQLITE_DONE: + return GNUNET_NO; + default: + LOG_SQLITE (gnc->plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | + GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + return GNUNET_SYSERR; + } } @@ -1423,7 +1342,7 @@ get_next_prepare (void *cls, * in the datastore. * * @param cls closure - * @param key maybe NULL (to match all entries) + * @param key key to match, never NULL * @param vhash hash of the value, maybe NULL (to * match all values that have the right key). * Note that for DBlocks there is no difference @@ -1437,31 +1356,26 @@ get_next_prepare (void *cls, */ static void sqlite_plugin_get (void *cls, - const GNUNET_HashCode * key, - const GNUNET_HashCode * vhash, - uint32_t type, + const GNUNET_HashCode *key, + const GNUNET_HashCode *vhash, + enum GNUNET_BLOCK_Type type, PluginIterator iter, void *iter_cls) { struct Plugin *plugin = cls; - struct GetNextContext *gpc; + struct GetNextContext *gnc; struct NextContext *nc; int ret; int total; sqlite3_stmt *stmt; char scratch[256]; - int sqoff; + unsigned int sqoff; GNUNET_assert (iter != NULL); - if (key == NULL) - { - sqlite_plugin_iter_low_priority (cls, type, iter, iter_cls); - return; - } + GNUNET_assert (key != NULL); GNUNET_snprintf (scratch, sizeof (scratch), - "SELECT count(*) FROM gn080 WHERE hash=:1%s%s", - vhash == NULL ? "" : " AND vhash=:2", - type == 0 ? "" : (vhash == - NULL) ? " AND type=:2" : " AND type=:3"); + "SELECT count(*) FROM gn090 WHERE hash=?%s%s", + vhash == NULL ? "" : " AND vhash=?", + type == 0 ? "" : " AND type=?"); if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK) { LOG_SQLITE (plugin, NULL, @@ -1470,12 +1384,10 @@ sqlite_plugin_get (void *cls, return; } sqoff = 1; - ret = sqlite3_bind_blob (stmt, - sqoff++, + ret = sqlite3_bind_blob (stmt, sqoff++, key, sizeof (GNUNET_HashCode), SQLITE_TRANSIENT); if ((vhash != NULL) && (ret == SQLITE_OK)) - ret = sqlite3_bind_blob (stmt, - sqoff++, + ret = sqlite3_bind_blob (stmt, sqoff++, vhash, sizeof (GNUNET_HashCode), SQLITE_TRANSIENT); if ((type != 0) && (ret == SQLITE_OK)) @@ -1484,7 +1396,6 @@ sqlite_plugin_get (void *cls, { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite_bind"); - sqlite3_reset (stmt); sqlite3_finalize (stmt); iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; @@ -1495,28 +1406,24 @@ sqlite_plugin_get (void *cls, LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR| GNUNET_ERROR_TYPE_BULK, "sqlite_step"); - sqlite3_reset (stmt); sqlite3_finalize (stmt); iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } total = sqlite3_column_int (stmt, 0); - sqlite3_reset (stmt); sqlite3_finalize (stmt); if (0 == total) { iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } - GNUNET_snprintf (scratch, sizeof (scratch), - "SELECT size, type, prio, anonLevel, expire, hash, value, _ROWID_ " - "FROM gn080 WHERE hash=:1%s%s AND _ROWID_ >= :%d " - "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET :d", - vhash == NULL ? "" : " AND vhash=:2", - type == 0 ? "" : (vhash == - NULL) ? " AND type=:2" : " AND type=:3", - sqoff, sqoff + 1); + "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ " + "FROM gn090 WHERE hash=?%s%s " + "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?", + vhash == NULL ? "" : " AND vhash=?", + type == 0 ? "" : " AND type=?"); + if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK) { LOG_SQLITE (plugin, NULL, @@ -1531,104 +1438,264 @@ sqlite_plugin_get (void *cls, nc->iter = iter; nc->iter_cls = iter_cls; nc->stmt = stmt; - gpc = (struct GetNextContext*) &nc[1]; - gpc->total = total; - gpc->type = type; - gpc->key = *key; - gpc->stmt = stmt; /* alias used for freeing at the end! */ + gnc = (struct GetNextContext*) &nc[1]; + gnc->total = total; + gnc->type = type; + gnc->key = *key; + gnc->plugin = plugin; + gnc->stmt = stmt; /* alias used for freeing at the end! */ if (NULL != vhash) { - gpc->have_vhash = GNUNET_YES; - gpc->vhash = *vhash; + gnc->have_vhash = GNUNET_YES; + gnc->vhash = *vhash; } - gpc->off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total); + gnc->off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total); nc->prep = &get_next_prepare; - nc->prep_cls = gpc; + nc->prep_cls = gnc; sqlite_next_request (nc, GNUNET_NO); } /** - * Drop database. + * Execute statement that gets a row and call the callback + * with the result. Resets the statement afterwards. * - * @param cls our plugin context + * @param plugin the plugin + * @param stmt the statement + * @param iter iterator to call + * @param iter_cls closure for 'iter' */ -static void -sqlite_plugin_drop (void *cls) +static void +execute_get (struct Plugin *plugin, + sqlite3_stmt *stmt, + PluginIterator iter, void *iter_cls) { - struct Plugin *plugin = cls; - plugin->drop_on_shutdown = GNUNET_YES; + int n; + struct GNUNET_TIME_Absolute expiration; + unsigned long long rowid; + unsigned int size; + int ret; + + n = sqlite3_step (stmt); + switch (n) + { + case SQLITE_ROW: + size = sqlite3_column_bytes (stmt, 5); + rowid = sqlite3_column_int64 (stmt, 6); + if (sqlite3_column_bytes (stmt, 4) != sizeof (GNUNET_HashCode)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, + "sqlite", + _("Invalid data in database. Trying to fix (by deletion).\n")); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | + GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); + if (GNUNET_OK == delete_by_rowid (plugin, rowid)) + plugin->env->duc (plugin->env->cls, + - (size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); + break; + } + expiration.abs_value = sqlite3_column_int64 (stmt, 3); + ret = iter (iter_cls, + NULL, + sqlite3_column_blob (stmt, 4) /* key */, + size, + sqlite3_column_blob (stmt, 5) /* data */, + sqlite3_column_int (stmt, 0) /* type */, + sqlite3_column_int (stmt, 1) /* priority */, + sqlite3_column_int (stmt, 2) /* anonymity */, + expiration, + rowid); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | + GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); + if ( (GNUNET_NO == ret) && + (GNUNET_OK == delete_by_rowid (plugin, rowid)) ) + plugin->env->duc (plugin->env->cls, + - (size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); + return; + case SQLITE_DONE: + /* database must be empty */ + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | + GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); + break; + case SQLITE_BUSY: + case SQLITE_ERROR: + case SQLITE_MISUSE: + default: + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | + GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + GNUNET_break (0); + database_shutdown (plugin); + database_setup (plugin->env->cfg, + plugin); + break; + } + iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, + GNUNET_TIME_UNIT_ZERO_ABS, 0); } /** - * Callback function to process statistic values. + * Get a random item for replication. Returns a single, not expired, 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. * * @param cls closure - * @param subsystem name of subsystem that created the statistic - * @param name the name of the datum - * @param value the current value - * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not - * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + * @param iter function to call the value (once only). + * @param iter_cls closure for iter */ -static int -process_stat_in (void *cls, - const char *subsystem, - const char *name, - uint64_t value, - int is_persistent) +static void +sqlite_plugin_replication_get (void *cls, + PluginIterator iter, void *iter_cls) { struct Plugin *plugin = cls; + sqlite3_stmt *stmt; + struct GNUNET_TIME_Absolute now; - plugin->stats_worked = GNUNET_YES; - plugin->payload += value; #if DEBUG_SQLITE GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", - "Notification from statistics about existing payload (%llu), new payload is %llu\n", - value, - plugin->payload); + "Getting random block based on replication order.\n"); #endif - return GNUNET_OK; + 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); } + +/** + * Get a random item that has expired or has low priority. + * Call 'iter' with all values ZERO or NULL if the datastore is empty. + * + * @param cls closure + * @param iter function to call the value (once only). + * @param iter_cls closure for iter + */ static void -process_stat_done (void *cls, - int success) +sqlite_plugin_expiration_get (void *cls, + PluginIterator iter, void *iter_cls) +{ + struct Plugin *plugin = 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)) + { + 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); +} + + +/** + * Drop database. + * + * @param cls our plugin context + */ +static void +sqlite_plugin_drop (void *cls) +{ + struct Plugin *plugin = cls; + plugin->drop_on_shutdown = GNUNET_YES; +} + + +/** + * Get an estimate of how much space the database is + * currently using. + * + * @param cls the 'struct Plugin' + * @return the size of the database on disk (estimate) + */ +static unsigned long long +sqlite_plugin_get_size (void *cls) { struct Plugin *plugin = cls; sqlite3_stmt *stmt; uint64_t pages; - uint64_t free_pages; + uint64_t page_size; +#if ENULL_DEFINED + char *e; +#endif - plugin->stat_get = NULL; - if (plugin->stats_worked == GNUNET_NO) + if (SQLITE_VERSION_NUMBER < 3006000) { - CHECK (SQLITE_OK == - sq_prepare (plugin->dbh, - "PRAGMA page_count", - &stmt)); - if (SQLITE_ROW == - sqlite3_step (stmt)) - pages = sqlite3_column_int64 (stmt, 0); - else - pages = 0; - sqlite3_finalize (stmt); - CHECK (SQLITE_OK == - sq_prepare (plugin->dbh, - "PRAGMA freelist_count", - &stmt)); - CHECK (SQLITE_ROW == - sqlite3_step (stmt)); - free_pages = sqlite3_column_int64 (stmt, 0); - sqlite3_finalize (stmt); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Using sqlite page utilization to estimate payload (%llu pages total, %llu free)\n"), - (unsigned long long) pages, - (unsigned long long) free_pages); - plugin->payload = (pages - free_pages) * 4092LL; + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, + "datastore-sqlite", + _("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)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, + "PRAGMA auto_vacuum=INCREMENTAL", NULL, NULL, ENULL)); + CHECK (SQLITE_OK == + sq_prepare (plugin->dbh, + "PRAGMA page_count", + &stmt)); + if (SQLITE_ROW == + sqlite3_step (stmt)) + pages = sqlite3_column_int64 (stmt, 0); + else + pages = 0; + sqlite3_finalize (stmt); + CHECK (SQLITE_OK == + sq_prepare (plugin->dbh, + "PRAGMA page_size", + &stmt)); + CHECK (SQLITE_ROW == + sqlite3_step (stmt)); + page_size = sqlite3_column_int64 (stmt, 0); + sqlite3_finalize (stmt); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"), + (unsigned long long) pages, + (unsigned long long) page_size); + return pages * page_size; } @@ -1649,16 +1716,6 @@ libgnunet_plugin_datastore_sqlite_init (void *cls) return NULL; /* can only initialize once! */ memset (&plugin, 0, sizeof(struct Plugin)); plugin.env = env; - plugin.statistics = GNUNET_STATISTICS_create (env->sched, - "ds-sqlite", - env->cfg); - plugin.stat_get = GNUNET_STATISTICS_get (plugin.statistics, - "ds-sqlite", - QUOTA_STAT_NAME, - GNUNET_TIME_UNIT_SECONDS, - &process_stat_done, - &process_stat_in, - &plugin); if (GNUNET_OK != database_setup (env->cfg, &plugin)) { @@ -1671,11 +1728,10 @@ libgnunet_plugin_datastore_sqlite_init (void *cls) api->put = &sqlite_plugin_put; api->next_request = &sqlite_next_request; api->get = &sqlite_plugin_get; + api->replication_get = &sqlite_plugin_replication_get; + api->expiration_get = &sqlite_plugin_expiration_get; api->update = &sqlite_plugin_update; - api->iter_low_priority = &sqlite_plugin_iter_low_priority; api->iter_zero_anonymity = &sqlite_plugin_iter_zero_anonymity; - api->iter_ascending_expiration = &sqlite_plugin_iter_ascending_expiration; - api->iter_migration_order = &sqlite_plugin_iter_migration_order; api->iter_all_now = &sqlite_plugin_iter_all_now; api->drop = &sqlite_plugin_drop; GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, @@ -1697,16 +1753,26 @@ libgnunet_plugin_datastore_sqlite_done (void *cls) struct GNUNET_DATASTORE_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; - if (plugin->stat_get != NULL) - { - GNUNET_STATISTICS_get_cancel (plugin->stat_get); - plugin->stat_get = NULL; - } +#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) { - GNUNET_SCHEDULER_cancel (plugin->env->sched, - plugin->next_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; @@ -1714,11 +1780,13 @@ 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); - GNUNET_STATISTICS_destroy (plugin->statistics, - GNUNET_NO); plugin->env = NULL; - plugin->payload = 0; GNUNET_free (api); if (fn != NULL) { @@ -1728,6 +1796,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; }