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.
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.
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.
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).