#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;
}
GNUNET_CONFIGURATION_get_value_filename (cfg, "datastore-sqlite",
"FILENAME", &afsdir))
{
- GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "sqlite",
- _
- ("Option `%s' in section `%s' missing in configuration!\n"),
- "FILENAME", "datastore-sqlite");
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "datastore-sqlite", "FILENAME");
return GNUNET_SYSERR;
}
if (GNUNET_OK != GNUNET_DISK_file_test (afsdir))
/* database is new or got deleted, reset payload to zero! */
plugin->env->duc (plugin->env->cls, 0);
}
-#ifdef ENABLE_NLS
- plugin->fn =
- GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), nl_langinfo (CODESET));
-#else
- plugin->fn = GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), "UTF-8"); /* good luck */
-#endif
- GNUNET_free (afsdir);
+ /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */
+ plugin->fn = afsdir;
/* Open database and precompile statements */
if (sqlite3_open (plugin->fn, &plugin->dbh) != SQLITE_OK)
&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);
* @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
+ * @return #GNUNET_OK on success
*/
static int
-sqlite_plugin_put (void *cls, const GNUNET_HashCode * key, uint32_t size,
+sqlite_plugin_put (void *cls, const struct GNUNET_HashCode * key, uint32_t size,
const void *data, enum GNUNET_BLOCK_Type type,
uint32_t priority, uint32_t anonymity, uint32_t replication,
struct GNUNET_TIME_Absolute expiration, char **msg)
int n;
int ret;
sqlite3_stmt *stmt;
- GNUNET_HashCode vhash;
+ struct GNUNET_HashCode vhash;
uint64_t rvalue;
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",
+ "Storing in database block with type %u/key `%s'/priority %u/expiration in %s (%s).\n",
type, GNUNET_h2s (key), priority,
(unsigned long long)
- GNUNET_TIME_absolute_get_remaining (expiration).rel_value,
- (long long) expiration.abs_value);
-#endif
+ GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (expiration),
+ GNUNET_YES),
+ GNUNET_STRINGS_absolute_time_to_string (expiration));
GNUNET_CRYPTO_hash (data, size, &vhash);
stmt = plugin->insertContent;
rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
(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, expiration.abs_value)) ||
+ (SQLITE_OK != sqlite3_bind_int64 (stmt, 5, expiration.abs_value_us)) ||
(SQLITE_OK != sqlite3_bind_int64 (stmt, 6, rvalue)) ||
(SQLITE_OK !=
- sqlite3_bind_blob (stmt, 7, key, sizeof (GNUNET_HashCode),
+ sqlite3_bind_blob (stmt, 7, key, sizeof (struct GNUNET_HashCode),
SQLITE_TRANSIENT)) ||
(SQLITE_OK !=
- sqlite3_bind_blob (stmt, 8, &vhash, sizeof (GNUNET_HashCode),
+ sqlite3_bind_blob (stmt, 8, &vhash, sizeof (struct GNUNET_HashCode),
SQLITE_TRANSIENT)) ||
(SQLITE_OK != sqlite3_bind_blob (stmt, 9, data, size, SQLITE_TRANSIENT)))
{
{
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:
int n;
if ((SQLITE_OK != sqlite3_bind_int (plugin->updPrio, 1, delta)) ||
- (SQLITE_OK != sqlite3_bind_int64 (plugin->updPrio, 2, expire.abs_value))
+ (SQLITE_OK != sqlite3_bind_int64 (plugin->updPrio, 2, expire.abs_value_us))
|| (SQLITE_OK != sqlite3_bind_int64 (plugin->updPrio, 3, uid)))
{
LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
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,
case SQLITE_ROW:
size = sqlite3_column_bytes (stmt, 5);
rowid = sqlite3_column_int64 (stmt, 6);
- if (sqlite3_column_bytes (stmt, 4) != sizeof (GNUNET_HashCode))
+ if (sqlite3_column_bytes (stmt, 4) != sizeof (struct GNUNET_HashCode))
{
GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite",
_
-(size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
break;
}
- expiration.abs_value = sqlite3_column_int64 (stmt, 3);
-#if DEBUG_SQLITE
+ expiration.abs_value_us = sqlite3_column_int64 (stmt, 3);
GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
- "Found reply in database with expiration %llu\n",
- (unsigned long long) expiration.abs_value);
-#endif
+ "Found reply in database with expiration %s\n",
+ GNUNET_STRINGS_absolute_time_to_string (expiration));
ret = proc (proc_cls, sqlite3_column_blob (stmt, 4) /* key */ ,
size, sqlite3_column_blob (stmt, 5) /* data */ ,
sqlite3_column_int (stmt, 0) /* type */ ,
* @param proc_cls closure for proc
*/
static void
-sqlite_plugin_get_key (void *cls, uint64_t offset, const GNUNET_HashCode * key,
- const GNUNET_HashCode * vhash,
+sqlite_plugin_get_key (void *cls, uint64_t offset, const struct GNUNET_HashCode * key,
+ const struct GNUNET_HashCode * vhash,
enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc,
void *proc_cls)
{
}
sqoff = 1;
ret =
- sqlite3_bind_blob (stmt, sqoff++, key, sizeof (GNUNET_HashCode),
+ sqlite3_bind_blob (stmt, sqoff++, key, sizeof (struct GNUNET_HashCode),
SQLITE_TRANSIENT);
if ((vhash != NULL) && (ret == SQLITE_OK))
ret =
- sqlite3_bind_blob (stmt, sqoff++, vhash, sizeof (GNUNET_HashCode),
+ sqlite3_bind_blob (stmt, sqoff++, vhash, sizeof (struct GNUNET_HashCode),
SQLITE_TRANSIENT);
if ((type != 0) && (ret == SQLITE_OK))
ret = sqlite3_bind_int (stmt, sqoff++, type);
}
sqoff = 1;
ret =
- sqlite3_bind_blob (stmt, sqoff++, key, sizeof (GNUNET_HashCode),
+ sqlite3_bind_blob (stmt, sqoff++, key, sizeof (struct GNUNET_HashCode),
SQLITE_TRANSIENT);
if ((vhash != NULL) && (ret == SQLITE_OK))
ret =
- sqlite3_bind_blob (stmt, sqoff++, vhash, sizeof (GNUNET_HashCode),
+ sqlite3_bind_blob (stmt, sqoff++, vhash, sizeof (struct GNUNET_HashCode),
SQLITE_TRANSIENT);
if ((type != 0) && (ret == SQLITE_OK))
ret = sqlite3_bind_int (stmt, sqoff++, type);
* GNUNET_NO to delete the item
*/
static int
-repl_proc (void *cls, const GNUNET_HashCode * key, uint32_t size,
+repl_proc (void *cls, const struct 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)
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))
+ if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, now.abs_value_us))
{
LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
"sqlite3_bind_XXXX");
}
+
+/**
+ * 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 struct 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, 0);
+ if (sizeof (struct GNUNET_HashCode) == sqlite3_column_bytes (stmt, 0))
+ proc (proc_cls, key, 1);
+ else
+ GNUNET_break (0);
+ }
+ 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;
}