38#define MAX_ITEM_SIZE 65536
50#define BUSY_TIMEOUT_MS 250
58#define LOG_SQLITE(db, level, cmd) \
61 GNUNET_log_from (level, \
63 _ ("`%s' failed at %s:%d with error: %s\n"), \
67 sqlite3_errmsg (db->dbh)); \
76#define LOG_SQLITE_MSG(db, msg, level, cmd) \
79 GNUNET_log_from (level, \
81 _ ("`%s' failed at %s:%d with error: %s\n"), \
85 sqlite3_errmsg (db->dbh)); \
86 GNUNET_asprintf (msg, \
87 _ ("`%s' failed at %s:%u with error: %s"), \
91 sqlite3_errmsg (db->dbh)); \
181sq_prepare (sqlite3 *dbh,
const char *zSql, sqlite3_stmt **ppStmt)
186 result = sqlite3_prepare_v2 (dbh,
190 (
const char **) &
dummy);
193 "Prepared `%s' / %p: %d\n",
214 "CREATE INDEX IF NOT EXISTS idx_hash ON gn091 (hash)",
221 "CREATE INDEX IF NOT EXISTS idx_anon_type ON gn091 (anonLevel ASC,type)",
227 "CREATE INDEX IF NOT EXISTS idx_expire ON gn091 (expire ASC)",
234 "CREATE INDEX IF NOT EXISTS idx_repl_rvalue ON gn091 (repl,rvalue)",
240 "Failed to create indices: %s\n",
241 sqlite3_errmsg (dbh));
246#define CHECK(a) GNUNET_break (a)
250#define ENULL_DEFINED 1
254 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", e); \
300 if (NULL !=
plugin->env->duc)
307 if (SQLITE_OK != sqlite3_open (
plugin->fn, &
plugin->dbh))
311 _ (
"Unable to initialize SQLite: %s.\n"),
312 sqlite3_errmsg (
plugin->dbh));
317 sqlite3_exec (
plugin->dbh,
"PRAGMA temp_store=MEMORY", NULL, NULL,
ENULL));
320 sqlite3_exec (
plugin->dbh,
"PRAGMA synchronous=OFF", NULL, NULL,
ENULL));
322 "PRAGMA legacy_file_format=OFF",
327 "PRAGMA auto_vacuum=INCREMENTAL",
332 "PRAGMA locking_mode=EXCLUSIVE",
338 sqlite3_exec (
plugin->dbh,
"PRAGMA page_size=4096", NULL, NULL,
ENULL));
346 "SELECT 1 FROM sqlite_master WHERE tbl_name = 'gn091'",
353if ((SQLITE_DONE == sqlite3_step (stmt)) &&
354 (SQLITE_OK != sqlite3_exec (
plugin->dbh,
355 "CREATE TABLE gn091 ("
356 " repl INT4 NOT NULL DEFAULT 0,"
357 " type INT4 NOT NULL DEFAULT 0,"
358 " prio INT4 NOT NULL DEFAULT 0,"
359 " anonLevel INT4 NOT NULL DEFAULT 0,"
360 " expire INT8 NOT NULL DEFAULT 0,"
361 " rvalue INT8 NOT NULL,"
362 " hash TEXT NOT NULL DEFAULT '',"
363 " vhash TEXT NOT NULL DEFAULT '',"
364 " value BLOB NOT NULL DEFAULT '')",
370 sqlite3_finalize (stmt);
373 sqlite3_finalize (stmt);
376#define RESULT_COLUMNS \
377 "repl, type, prio, anonLevel, expire, hash, value, _ROWID_"
381 "SET prio = prio + ?, "
383 "expire = MAX(expire, ?) "
384 "WHERE hash = ? AND vhash = ?",
388 "SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?",
394 " NOT EXISTS (SELECT 1 FROM gn091 "
395 "WHERE repl=?2 AND rvalue>=?1 LIMIT 1) ) "
396 "ORDER BY rvalue ASC LIMIT 1",
399 "SELECT MAX(repl) FROM gn091",
404 "WHERE NOT EXISTS (SELECT 1 FROM gn091 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) "
405 "ORDER BY expire ASC LIMIT 1",
409 "WHERE _ROWID_ >= ? AND "
412 "ORDER BY _ROWID_ ASC LIMIT 1",
416 "INSERT INTO gn091 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) "
417 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
418 &
plugin->insertContent)) ||
421 "WHERE _ROWID_ >= ?1 "
422 "ORDER BY _ROWID_ ASC LIMIT 1",
426 "WHERE _ROWID_ >= ?1 AND "
428 "ORDER BY _ROWID_ ASC LIMIT 1",
432 "WHERE _ROWID_ >= ?1 AND "
434 "ORDER BY _ROWID_ ASC LIMIT 1",
438 "WHERE _ROWID_ >= ?1 AND "
441 "ORDER BY _ROWID_ ASC LIMIT 1",
445 "WHERE _ROWID_ >= ?1 AND "
447 "ORDER BY _ROWID_ ASC LIMIT 1",
451 "WHERE _ROWID_ >= ?1 AND "
454 "ORDER BY _ROWID_ ASC LIMIT 1",
458 "WHERE _ROWID_ >= ?1 AND "
461 "ORDER BY _ROWID_ ASC LIMIT 1",
465 "WHERE _ROWID_ >= ?1 AND "
469 "ORDER BY _ROWID_ ASC LIMIT 1",
472 "DELETE FROM gn091 WHERE _ROWID_ = ?",
476 "WHERE hash = ? AND "
499#if SQLITE_VERSION_NUMBER >= 3007000
503 if (NULL !=
plugin->remove)
504 sqlite3_finalize (
plugin->remove);
505 if (NULL !=
plugin->delRow)
506 sqlite3_finalize (
plugin->delRow);
507 if (NULL !=
plugin->update)
508 sqlite3_finalize (
plugin->update);
509 if (NULL !=
plugin->updRepl)
510 sqlite3_finalize (
plugin->updRepl);
511 if (NULL !=
plugin->selRepl)
512 sqlite3_finalize (
plugin->selRepl);
513 if (NULL !=
plugin->maxRepl)
514 sqlite3_finalize (
plugin->maxRepl);
515 if (NULL !=
plugin->selExpi)
516 sqlite3_finalize (
plugin->selExpi);
517 if (NULL !=
plugin->selZeroAnon)
518 sqlite3_finalize (
plugin->selZeroAnon);
519 if (NULL !=
plugin->insertContent)
520 sqlite3_finalize (
plugin->insertContent);
521 for (
int i = 0; i < 8; ++i)
522 if (NULL !=
plugin->get[i])
523 sqlite3_finalize (
plugin->get[i]);
525#if SQLITE_VERSION_NUMBER >= 3007000
526 if (
result == SQLITE_BUSY)
532 "Tried to close sqlite without finalizing all prepared statements.\n"));
533 stmt = sqlite3_next_stmt (
plugin->dbh, NULL);
538 "Closing statement %p\n",
540 result = sqlite3_finalize (stmt);
544 "Failed to close statement %p: %d\n",
547 stmt = sqlite3_next_stmt (
plugin->dbh, NULL);
573 if (SQLITE_DONE != sqlite3_step (
plugin->delRow))
637 if (SQLITE_DONE != sqlite3_step (
plugin->update))
648 int changes = sqlite3_changes (
plugin->dbh);
661 uint32_t type32 = (uint32_t)
type;
685 "Storing in database block with type %u/key `%s'/priority %u/expiration in %s (%s).\n",
694 stmt =
plugin->insertContent;
701 n = sqlite3_step (stmt);
705 if (NULL !=
plugin->env->duc)
710 "Stored new entry (%u bytes)\n",
780 n = sqlite3_step (stmt);
791 "Found reply in database with expiration %s\n",
793 ret = proc (proc_cls,
806 (NULL !=
plugin->env->duc))
822 if (SQLITE_OK != sqlite3_reset (stmt))
857 uint32_t type32 =
type;
898 int use_rvalue = random;
899 uint32_t type32 = (uint32_t)
type;
901 int use_key = NULL !=
key;
902 sqlite3_stmt *stmt =
plugin->get[use_rvalue * 4 + use_key * 2 + use_type];
1039 uint64_t rvalue = 0;
1050 "Getting random block based on replication order.\n");
1051 if (SQLITE_ROW != sqlite3_step (
plugin->maxRepl))
1058 repl = sqlite3_column_int (
plugin->maxRepl, 0);
1077 if (SQLITE_DONE != sqlite3_step (
plugin->updRepl))
1114 "Getting random block based on expiration and priority order.\n");
1144 if (SQLITE_OK !=
sq_prepare (
plugin->dbh,
"SELECT hash FROM gn091", &stmt))
1149 proc (proc_cls, NULL, 0);
1152 while (SQLITE_ROW == (
ret = sqlite3_step (stmt)))
1155 proc (proc_cls, &
key, 1);
1159 if (SQLITE_DONE !=
ret)
1161 sqlite3_finalize (stmt);
1162 proc (proc_cls, NULL, 0);
1209 if (SQLITE_DONE != sqlite3_step (
plugin->remove))
1219 int changes = sqlite3_changes (
plugin->dbh);
1227 if (NULL !=
plugin->env->duc)
1253 if (NULL == estimate)
1255 if (SQLITE_VERSION_NUMBER < 3006000)
1260 _ (
"sqlite version to old to determine size, assuming zero\n"));
1264 CHECK (SQLITE_OK == sqlite3_exec (
plugin->dbh,
"VACUUM", NULL, NULL,
ENULL));
1266 "PRAGMA auto_vacuum=INCREMENTAL",
1275 _ (
"error preparing statement\n"));
1278 if (SQLITE_ROW == sqlite3_step (stmt))
1279 pages = sqlite3_column_int64 (stmt, 0);
1282 sqlite3_finalize (stmt);
1288 _ (
"error preparing statement\n"));
1291 if (SQLITE_ROW != sqlite3_step (stmt))
1296 _ (
"error stepping\n"));
1299 page_size = sqlite3_column_int64 (stmt, 0);
1300 sqlite3_finalize (stmt);
1304 "Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"),
1305 (
unsigned long long) pages,
1306 (
unsigned long long) page_size);
1307 *estimate = pages * page_size;
1349 _ (
"Sqlite database running\n"));
1372 "sqlite plugin is done\n");
1374 if (
plugin->drop_on_shutdown)
1381 if (0 != unlink (
fn))
struct GNUNET_MessageHeader * msg
struct GNUNET_MQ_Envelope * env
static int ret
Final status code.
static struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
static struct GNUNET_TESTING_PluginFunctions * plugin
Plugin to dynamically load a test case.
static unsigned int replication
Desired replication level.
static char * data
The data to insert into the dht.
struct GNUNET_HashCode key
The key used in the DHT.
static struct GNUNET_TIME_Relative expiration
User supplied expiration value.
static unsigned int anonymity
static struct in_addr dummy
Target "dummy" address of the packet we pretend to respond to.
static char * value
Value of the record to add/remove.
static uint32_t type
Type string converted to DNS type value.
static int result
Global testing status.
static unsigned int results
API for the database backend plugins.
GNUNET_BLOCK_Type
WARNING: This header is generated! In order to add DHT block types, you must register them in GANA,...
@ GNUNET_BLOCK_TYPE_ANY
Identifier for any block.
helper functions for Sqlite3 DB interactions
struct GNUNET_SQ_QueryParam GNUNET_SQ_query_param_fixed_size(const void *ptr, size_t ptr_size)
Generate query parameter for a buffer ptr of ptr_size bytes.
enum GNUNET_GenericReturnValue GNUNET_SQ_extract_result(sqlite3_stmt *result, struct GNUNET_SQ_ResultSpec *rs)
Extract results from a query result according to the given specification.
void GNUNET_SQ_cleanup_result(struct GNUNET_SQ_ResultSpec *rs)
Free all memory that was allocated in rs during GNUNET_SQ_extract_result().
struct GNUNET_SQ_QueryParam GNUNET_SQ_query_param_uint32(const uint32_t *x)
Generate query parameter for an uint32_t in host byte order.
struct GNUNET_SQ_QueryParam GNUNET_SQ_query_param_uint64(const uint64_t *x)
Generate query parameter for an uint16_t in host byte order.
struct GNUNET_SQ_ResultSpec GNUNET_SQ_result_spec_absolute_time(struct GNUNET_TIME_Absolute *at)
Absolute time expected.
struct GNUNET_SQ_ResultSpec GNUNET_SQ_result_spec_uint32(uint32_t *u32)
uint32_t expected.
struct GNUNET_SQ_QueryParam GNUNET_SQ_query_param_absolute_time(const struct GNUNET_TIME_Absolute *x)
Generate query parameter for an absolute time value.
#define GNUNET_SQ_result_spec_end
End of result parameter specification.
struct GNUNET_SQ_ResultSpec GNUNET_SQ_result_spec_variable_size(void **dst, size_t *sptr)
Variable-size result expected.
#define GNUNET_SQ_query_param_auto_from_type(x)
Generate fixed-size query parameter with size determined by variable type.
enum GNUNET_GenericReturnValue GNUNET_SQ_bind(sqlite3_stmt *stmt, const struct GNUNET_SQ_QueryParam *params)
Execute binding operations for a prepared statement.
void GNUNET_SQ_reset(sqlite3 *dbh, sqlite3_stmt *stmt)
Reset stmt and log error.
#define GNUNET_SQ_query_param_end
End of query parameter specification.
#define GNUNET_SQ_result_spec_auto_from_type(dst)
We expect a fixed-size result, with size determined by the type of * dst
struct GNUNET_SQ_ResultSpec GNUNET_SQ_result_spec_uint64(uint64_t *u64)
uint64_t expected.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_filename(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be the name of a file or directory.
uint64_t GNUNET_CRYPTO_random_u64(enum GNUNET_CRYPTO_Quality mode, uint64_t max)
Generate a random unsigned 64-bit value.
@ GNUNET_CRYPTO_QUALITY_WEAK
No good quality of the operation is needed (i.e., random numbers can be pseudo-random).
enum GNUNET_GenericReturnValue(* PluginDatumProcessor)(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, uint64_t uid)
An processor over a set of items stored in the datastore.
void(* PluginPutCont)(void *cls, const struct GNUNET_HashCode *key, uint32_t size, int status, const char *msg)
Put continuation.
#define GNUNET_DATASTORE_ENTRY_OVERHEAD
How many bytes of overhead will we assume per entry in any DB (for reservations)?
void(* PluginKeyProcessor)(void *cls, const struct GNUNET_HashCode *key, unsigned int count)
An processor over a set of keys stored in the datastore.
void(* PluginRemoveCont)(void *cls, const struct GNUNET_HashCode *key, uint32_t size, int status, const char *msg)
Remove continuation.
enum GNUNET_GenericReturnValue GNUNET_DISK_file_test(const char *fil)
Check that fil corresponds to a filename (of a file that exists and that is not a directory).
enum GNUNET_GenericReturnValue GNUNET_DISK_directory_create_for_file(const char *filename)
Create the directory structure for storing a file.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
#define GNUNET_log(kind,...)
#define GNUNET_log_from(kind, comp,...)
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
const char * GNUNET_h2s(const struct GNUNET_HashCode *hc)
Convert a hash value to a string (for printing debug messages).
void GNUNET_log_config_missing(enum GNUNET_ErrorType kind, const char *section, const char *option)
Log error message about missing configuration option.
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining(struct GNUNET_TIME_Absolute future)
Given a timestamp in the future, how much time remains until then?
const char * GNUNET_STRINGS_relative_time_to_string(struct GNUNET_TIME_Relative delta, int do_round)
Give relative time in human-readable fancy format.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
#define GNUNET_TIME_UNIT_ZERO_ABS
Absolute time zero.
const char * GNUNET_STRINGS_absolute_time_to_string(struct GNUNET_TIME_Absolute t)
Like asctime, except for GNUnet time.
static unsigned int size
Size of the "table".
static int database_setup(const struct GNUNET_CONFIGURATION_Handle *cfg, struct Plugin *plugin)
Initialize the database connections and associated data structures (create tables and indices as need...
static void sqlite_plugin_estimate_size(void *cls, unsigned long long *estimate)
Get an estimate of how much space the database is currently using.
#define MAX_ITEM_SIZE
We allocate items on the stack at times.
#define LOG_SQLITE_MSG(db, msg, level, cmd)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' on file 'file...
static int 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, uint32_t replication, struct GNUNET_TIME_Absolute expiration, uint64_t uid)
Wrapper for the processor for sqlite_plugin_get_replication().
#define BUSY_TIMEOUT_MS
After how many ms "busy" should a DB operation fail for good? A low value makes sure that we are more...
static void sqlite_plugin_put(void *cls, const struct GNUNET_HashCode *key, bool absent, 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, PluginPutCont cont, void *cont_cls)
Store an item in the datastore.
static void sqlite_plugin_remove_key(void *cls, const struct GNUNET_HashCode *key, uint32_t size, const void *data, PluginRemoveCont cont, void *cont_cls)
Remove a particular key in the datastore.
#define LOG_SQLITE(db, level, cmd)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' on file 'file...
static int sq_prepare(sqlite3 *dbh, const char *zSql, sqlite3_stmt **ppStmt)
Prepare a SQL statement.
static void sqlite_plugin_get_keys(void *cls, PluginKeyProcessor proc, void *proc_cls)
Get all of the keys in the datastore.
static void create_indices(sqlite3 *dbh)
Create our database indices.
static int delete_by_rowid(struct Plugin *plugin, uint64_t rid)
Delete the database entry with the given row identifier.
static void database_shutdown(struct Plugin *plugin)
Shutdown database connection and associate data structures.
static void execute_get(struct Plugin *plugin, sqlite3_stmt *stmt, PluginDatumProcessor proc, void *proc_cls)
Execute statement that gets a row and call the callback with the result.
void * libgnunet_plugin_datastore_sqlite_done(void *cls)
Exit point from the plugin.
static void sqlite_plugin_get_key(void *cls, uint64_t next_uid, bool random, const struct GNUNET_HashCode *key, enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, void *proc_cls)
Get results for a particular key in the datastore.
static void sqlite_plugin_get_replication(void *cls, PluginDatumProcessor proc, void *proc_cls)
Get a random item for replication.
static void sqlite_plugin_get_zero_anonymity(void *cls, uint64_t next_uid, enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, void *proc_cls)
Select a subset of the items in the datastore and call the given processor for the item.
static void sqlite_plugin_drop(void *cls)
Drop database.
void * libgnunet_plugin_datastore_sqlite_init(void *cls)
Entry point for the plugin.
static void sqlite_plugin_get_expiration(void *cls, PluginDatumProcessor proc, void *proc_cls)
Get a random item that has expired or has low priority.
void * cls
Closure for all of the callbacks.
The datastore service will pass a pointer to a struct of this type as the first and only argument to ...
Each plugin is required to return a pointer to a struct of this type as the return value from its ent...
PluginGetKey get_key
Get a particular datum matching a given hash from the datastore.
PluginGetRandom get_expiration
Function to get a random expired item or, if none are expired, either the oldest entry or one with a ...
PluginEstimateSize estimate_size
Calculate the current on-disk size of the SQ store.
PluginGetKeys get_keys
Iterate over all keys in the database.
PluginGetRandom get_replication
Function to get a random item with high replication score from the database, lowering the item's repl...
PluginPut put
Function to store an item in the datastore.
void * cls
Closure to use for all of the following callbacks (except "next_request").
PluginGetType get_zero_anonymity
Get datum (of the specified type) with anonymity level zero.
PluginDrop drop
Delete the database.
PluginRemoveKey remove_key
Function to remove an item from the database.
Description of a DB query parameter.
Description of a DB result cell.
void * cls
Closure for conv and cleaner.
void * cls
Closure to pass to start_testcase.
Time for absolute times used by GNUnet, in microseconds.
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
sqlite3_stmt * maxRepl
Get maximum repl value in database.
sqlite3_stmt * insertContent
Precompiled SQL for insertion.
sqlite3_stmt * update
Precompiled SQL for update.
sqlite3_stmt * remove
Precompiled SQL for remove_key.
char * fn
Filename used for the DB.
struct GNUNET_DATACACHE_PluginEnvironment * env
Our execution environment.
int drop_on_shutdown
Should the database be dropped on shutdown?
sqlite3_stmt * selRepl
Precompiled SQL for replication selection.
sqlite3_stmt * delRow
Precompiled SQL for deletion.
sqlite3_stmt * get[8]
Precompiled SQL for selection.
struct GNUNET_PQ_Context * dbh
Native Postgres database handle.
sqlite3_stmt * selZeroAnon
Precompiled SQL for expiration selection.
sqlite3_stmt * selExpi
Precompiled SQL for expiration selection.
sqlite3_stmt * updRepl
Precompiled SQL for replication decrement.
Context for #repl_iter() function.
void * proc_cls
Closure for proc.
int have_uid
Yes if UID was set.
PluginDatumProcessor proc
Function to call for the result (or the NULL).