2 * This file is part of GNUnet
3 * Copyright (C) 2009, 2011, 2017 GNUnet e.V.
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file datastore/plugin_datastore_sqlite.c
23 * @brief sqlite-based datastore backend
24 * @author Christian Grothoff
28 #include "gnunet_datastore_plugin.h"
29 #include "gnunet_sq_lib.h"
34 * We allocate items on the stack at times. To prevent a stack
35 * overflow, we impose a limit on the maximum size for the data per
36 * item. 64k should be enough.
38 #define MAX_ITEM_SIZE 65536
41 * After how many ms "busy" should a DB operation fail for good?
42 * A low value makes sure that we are more responsive to requests
43 * (especially PUTs). A high value guarantees a higher success
44 * rate (SELECTs in iterate can take several seconds despite LIMIT=1).
46 * The default value of 250ms should ensure that users do not experience
47 * huge latencies while at the same time allowing operations to succeed
48 * with reasonable probability.
50 #define BUSY_TIMEOUT_MS 250
54 * Log an error message at log-level 'level' that indicates
55 * a failure of the command 'cmd' on file 'filename'
56 * with the message given by strerror(errno).
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)); \
72 * Log an error message at log-level 'level' that indicates
73 * a failure of the command 'cmd' on file 'filename'
74 * with the message given by strerror(errno).
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)); \
96 * Context for all functions in this plugin.
101 * Our execution environment.
103 struct GNUNET_DATASTORE_PluginEnvironment *env;
111 * Native SQLite database handle.
116 * Precompiled SQL for remove_key.
118 sqlite3_stmt *remove;
121 * Precompiled SQL for deletion.
123 sqlite3_stmt *delRow;
126 * Precompiled SQL for update.
128 sqlite3_stmt *update;
131 * Get maximum repl value in database.
133 sqlite3_stmt *maxRepl;
136 * Precompiled SQL for replication decrement.
138 sqlite3_stmt *updRepl;
141 * Precompiled SQL for replication selection.
143 sqlite3_stmt *selRepl;
146 * Precompiled SQL for expiration selection.
148 sqlite3_stmt *selExpi;
151 * Precompiled SQL for expiration selection.
153 sqlite3_stmt *selZeroAnon;
156 * Precompiled SQL for insertion.
158 sqlite3_stmt *insertContent;
161 * Precompiled SQL for selection
163 sqlite3_stmt *get[8];
166 * Should the database be dropped on shutdown?
168 int drop_on_shutdown;
173 * @brief Prepare a SQL statement
175 * @param dbh handle to the database
176 * @param zSql SQL statement, UTF-8 encoded
177 * @param ppStmt set to the prepared statement
178 * @return 0 on success
181 sq_prepare (sqlite3 *dbh, const char *zSql, sqlite3_stmt **ppStmt)
186 result = sqlite3_prepare_v2 (dbh,
190 (const char **) &dummy);
191 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
193 "Prepared `%s' / %p: %d\n",
202 * Create our database indices.
204 * @param dbh handle to the database
207 create_indices (sqlite3 *dbh)
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)",
238 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
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); \
261 * Initialize the database connections and associated
262 * data structures (create tables and indices
263 * as needed as well).
265 * @param cfg our configuration
266 * @param plugin the plugin context (state for this module)
267 * @return #GNUNET_OK on success
270 database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
271 struct Plugin *plugin)
279 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
284 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
287 return GNUNET_SYSERR;
289 if (GNUNET_OK != GNUNET_DISK_file_test (afsdir))
291 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (afsdir))
294 GNUNET_free (afsdir);
295 return GNUNET_SYSERR;
297 /* database is new or got deleted, reset payload to zero! */
298 if (NULL != plugin->env->duc)
299 plugin->env->duc (plugin->env->cls, 0);
301 /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */
304 /* Open database and precompile statements */
305 if (SQLITE_OK != sqlite3_open (plugin->fn, &plugin->dbh))
307 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
309 _ ("Unable to initialize SQLite: %s.\n"),
310 sqlite3_errmsg (plugin->dbh));
311 return GNUNET_SYSERR;
315 sqlite3_exec (plugin->dbh, "PRAGMA temp_store=MEMORY", NULL, NULL, ENULL));
318 sqlite3_exec (plugin->dbh, "PRAGMA synchronous=OFF", NULL, NULL, ENULL));
319 CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh,
320 "PRAGMA legacy_file_format=OFF",
324 CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh,
325 "PRAGMA auto_vacuum=INCREMENTAL",
329 CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh,
330 "PRAGMA locking_mode=EXCLUSIVE",
336 sqlite3_exec (plugin->dbh, "PRAGMA page_size=4096", NULL, NULL, ENULL));
338 CHECK (SQLITE_OK == sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS));
341 /* We have to do it here, because otherwise precompiling SQL might fail */
343 sq_prepare (plugin->dbh,
344 "SELECT 1 FROM sqlite_master WHERE tbl_name = 'gn091'",
347 /* FIXME: SQLite does not have unsigned integers! This is ok for the type column because
348 * we only test equality on it and can cast it to/from uint32_t. For repl, prio, and anonLevel
349 * we do math or inequality tests, so we can't handle the entire range of uint32_t.
350 * This will also cause problems for expiration times after 294247-01-10-04:00:54 UTC.
352 if ((SQLITE_DONE == sqlite3_step (stmt)) &&
353 (SQLITE_OK != sqlite3_exec (plugin->dbh,
354 "CREATE TABLE gn091 ("
355 " repl INT4 NOT NULL DEFAULT 0,"
356 " type INT4 NOT NULL DEFAULT 0,"
357 " prio INT4 NOT NULL DEFAULT 0,"
358 " anonLevel INT4 NOT NULL DEFAULT 0,"
359 " expire INT8 NOT NULL DEFAULT 0,"
360 " rvalue INT8 NOT NULL,"
361 " hash TEXT NOT NULL DEFAULT '',"
362 " vhash TEXT NOT NULL DEFAULT '',"
363 " value BLOB NOT NULL DEFAULT '')",
368 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec");
369 sqlite3_finalize (stmt);
370 return GNUNET_SYSERR;
372 sqlite3_finalize (stmt);
373 create_indices (plugin->dbh);
375 #define RESULT_COLUMNS \
376 "repl, type, prio, anonLevel, expire, hash, value, _ROWID_"
378 (SQLITE_OK != sq_prepare (plugin->dbh,
380 "SET prio = prio + ?, "
382 "expire = MAX(expire, ?) "
383 "WHERE hash = ? AND vhash = ?",
385 (SQLITE_OK != sq_prepare (plugin->dbh,
387 "SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?",
388 &plugin->updRepl)) ||
389 (SQLITE_OK != sq_prepare (plugin->dbh,
390 "SELECT " RESULT_COLUMNS " FROM gn091 "
393 " NOT EXISTS (SELECT 1 FROM gn091 "
394 "WHERE repl=?2 AND rvalue>=?1 LIMIT 1) ) "
395 "ORDER BY rvalue ASC LIMIT 1",
396 &plugin->selRepl)) ||
397 (SQLITE_OK != sq_prepare (plugin->dbh,
398 "SELECT MAX(repl) FROM gn091",
399 &plugin->maxRepl)) ||
401 sq_prepare (plugin->dbh,
402 "SELECT " RESULT_COLUMNS " FROM gn091 "
403 "WHERE NOT EXISTS (SELECT 1 FROM gn091 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) "
404 "ORDER BY expire ASC LIMIT 1",
405 &plugin->selExpi)) ||
406 (SQLITE_OK != sq_prepare (plugin->dbh,
407 "SELECT " RESULT_COLUMNS " FROM gn091 "
408 "WHERE _ROWID_ >= ? AND "
411 "ORDER BY _ROWID_ ASC LIMIT 1",
412 &plugin->selZeroAnon)) ||
414 sq_prepare (plugin->dbh,
415 "INSERT INTO gn091 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) "
416 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
417 &plugin->insertContent)) ||
418 (SQLITE_OK != sq_prepare (plugin->dbh,
419 "SELECT " RESULT_COLUMNS " FROM gn091 "
420 "WHERE _ROWID_ >= ?1 "
421 "ORDER BY _ROWID_ ASC LIMIT 1",
423 (SQLITE_OK != sq_prepare (plugin->dbh,
424 "SELECT " RESULT_COLUMNS " FROM gn091 "
425 "WHERE _ROWID_ >= ?1 AND "
427 "ORDER BY _ROWID_ ASC LIMIT 1",
429 (SQLITE_OK != sq_prepare (plugin->dbh,
430 "SELECT " RESULT_COLUMNS " FROM gn091 "
431 "WHERE _ROWID_ >= ?1 AND "
433 "ORDER BY _ROWID_ ASC LIMIT 1",
435 (SQLITE_OK != sq_prepare (plugin->dbh,
436 "SELECT " RESULT_COLUMNS " FROM gn091 "
437 "WHERE _ROWID_ >= ?1 AND "
440 "ORDER BY _ROWID_ ASC LIMIT 1",
442 (SQLITE_OK != sq_prepare (plugin->dbh,
443 "SELECT " RESULT_COLUMNS " FROM gn091 "
444 "WHERE _ROWID_ >= ?1 AND "
446 "ORDER BY _ROWID_ ASC LIMIT 1",
448 (SQLITE_OK != sq_prepare (plugin->dbh,
449 "SELECT " RESULT_COLUMNS " FROM gn091 "
450 "WHERE _ROWID_ >= ?1 AND "
453 "ORDER BY _ROWID_ ASC LIMIT 1",
455 (SQLITE_OK != sq_prepare (plugin->dbh,
456 "SELECT " RESULT_COLUMNS " FROM gn091 "
457 "WHERE _ROWID_ >= ?1 AND "
460 "ORDER BY _ROWID_ ASC LIMIT 1",
462 (SQLITE_OK != sq_prepare (plugin->dbh,
463 "SELECT " RESULT_COLUMNS " FROM gn091 "
464 "WHERE _ROWID_ >= ?1 AND "
468 "ORDER BY _ROWID_ ASC LIMIT 1",
470 (SQLITE_OK != sq_prepare (plugin->dbh,
471 "DELETE FROM gn091 WHERE _ROWID_ = ?",
473 (SQLITE_OK != sq_prepare (plugin->dbh,
475 "WHERE hash = ? AND "
480 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "precompiling");
481 return GNUNET_SYSERR;
488 * Shutdown database connection and associate data
491 * @param plugin the plugin context (state for this module)
494 database_shutdown (struct Plugin *plugin)
497 #if SQLITE_VERSION_NUMBER >= 3007000
501 if (NULL != plugin->remove)
502 sqlite3_finalize (plugin->remove);
503 if (NULL != plugin->delRow)
504 sqlite3_finalize (plugin->delRow);
505 if (NULL != plugin->update)
506 sqlite3_finalize (plugin->update);
507 if (NULL != plugin->updRepl)
508 sqlite3_finalize (plugin->updRepl);
509 if (NULL != plugin->selRepl)
510 sqlite3_finalize (plugin->selRepl);
511 if (NULL != plugin->maxRepl)
512 sqlite3_finalize (plugin->maxRepl);
513 if (NULL != plugin->selExpi)
514 sqlite3_finalize (plugin->selExpi);
515 if (NULL != plugin->selZeroAnon)
516 sqlite3_finalize (plugin->selZeroAnon);
517 if (NULL != plugin->insertContent)
518 sqlite3_finalize (plugin->insertContent);
519 for (int i = 0; i < 8; ++i)
520 if (NULL != plugin->get[i])
521 sqlite3_finalize (plugin->get[i]);
522 result = sqlite3_close (plugin->dbh);
523 #if SQLITE_VERSION_NUMBER >= 3007000
524 if (result == SQLITE_BUSY)
527 GNUNET_ERROR_TYPE_WARNING,
530 "Tried to close sqlite without finalizing all prepared statements.\n"));
531 stmt = sqlite3_next_stmt (plugin->dbh, NULL);
534 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
536 "Closing statement %p\n",
538 result = sqlite3_finalize (stmt);
539 if (result != SQLITE_OK)
540 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
542 "Failed to close statement %p: %d\n",
545 stmt = sqlite3_next_stmt (plugin->dbh, NULL);
547 result = sqlite3_close (plugin->dbh);
550 if (SQLITE_OK != result)
551 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close");
552 GNUNET_free_non_null (plugin->fn);
557 * Delete the database entry with the given
560 * @param plugin the plugin context (state for this module)
561 * @param rid the ID of the row to delete
564 delete_by_rowid (struct Plugin *plugin, uint64_t rid)
566 struct GNUNET_SQ_QueryParam params[] = {GNUNET_SQ_query_param_uint64 (&rid),
567 GNUNET_SQ_query_param_end};
569 if (GNUNET_OK != GNUNET_SQ_bind (plugin->delRow, params))
570 return GNUNET_SYSERR;
571 if (SQLITE_DONE != sqlite3_step (plugin->delRow))
574 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
576 GNUNET_SQ_reset (plugin->dbh, plugin->delRow);
577 return GNUNET_SYSERR;
579 GNUNET_SQ_reset (plugin->dbh, plugin->delRow);
585 * Store an item in the datastore.
588 * @param key key for the item
589 * @param absent true if the key was not found in the bloom filter
590 * @param size number of bytes in @a data
591 * @param data content stored
592 * @param type type of the content
593 * @param priority priority of the content
594 * @param anonymity anonymity-level for the content
595 * @param replication replication-level for the content
596 * @param expiration expiration time for the content
597 * @param cont continuation called with success or failure status
598 * @param cont_cls continuation closure
601 sqlite_plugin_put (void *cls,
602 const struct GNUNET_HashCode *key,
606 enum GNUNET_BLOCK_Type type,
609 uint32_t replication,
610 struct GNUNET_TIME_Absolute expiration,
614 struct Plugin *plugin = cls;
615 struct GNUNET_HashCode vhash;
618 GNUNET_CRYPTO_hash (data, size, &vhash);
622 struct GNUNET_SQ_QueryParam params[] =
623 {GNUNET_SQ_query_param_uint32 (&priority),
624 GNUNET_SQ_query_param_uint32 (&replication),
625 GNUNET_SQ_query_param_absolute_time (&expiration),
626 GNUNET_SQ_query_param_auto_from_type (key),
627 GNUNET_SQ_query_param_auto_from_type (&vhash),
628 GNUNET_SQ_query_param_end};
630 if (GNUNET_OK != GNUNET_SQ_bind (plugin->update, params))
632 cont (cont_cls, key, size, GNUNET_SYSERR, _ ("sqlite bind failure"));
635 if (SQLITE_DONE != sqlite3_step (plugin->update))
637 LOG_SQLITE_MSG (plugin,
639 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
641 cont (cont_cls, key, size, GNUNET_SYSERR, msg);
642 GNUNET_free_non_null (msg);
645 int changes = sqlite3_changes (plugin->dbh);
646 GNUNET_SQ_reset (plugin->dbh, plugin->update);
649 cont (cont_cls, key, size, GNUNET_NO, NULL);
655 uint32_t type32 = (uint32_t) type;
656 struct GNUNET_SQ_QueryParam params[] =
657 {GNUNET_SQ_query_param_uint32 (&replication),
658 GNUNET_SQ_query_param_uint32 (&type32),
659 GNUNET_SQ_query_param_uint32 (&priority),
660 GNUNET_SQ_query_param_uint32 (&anonymity),
661 GNUNET_SQ_query_param_absolute_time (&expiration),
662 GNUNET_SQ_query_param_uint64 (&rvalue),
663 GNUNET_SQ_query_param_auto_from_type (key),
664 GNUNET_SQ_query_param_auto_from_type (&vhash),
665 GNUNET_SQ_query_param_fixed_size (data, size),
666 GNUNET_SQ_query_param_end};
671 if (size > MAX_ITEM_SIZE)
673 cont (cont_cls, key, size, GNUNET_SYSERR, _ ("Data too large"));
677 GNUNET_ERROR_TYPE_DEBUG,
679 "Storing in database block with type %u/key `%s'/priority %u/expiration in %s (%s).\n",
683 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (
686 GNUNET_STRINGS_absolute_time_to_string (expiration));
687 stmt = plugin->insertContent;
688 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
689 if (GNUNET_OK != GNUNET_SQ_bind (stmt, params))
691 cont (cont_cls, key, size, GNUNET_SYSERR, NULL);
694 n = sqlite3_step (stmt);
698 if (NULL != plugin->env->duc)
699 plugin->env->duc (plugin->env->cls,
700 size + GNUNET_DATASTORE_ENTRY_OVERHEAD);
701 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
703 "Stored new entry (%u bytes)\n",
704 size + GNUNET_DATASTORE_ENTRY_OVERHEAD);
709 LOG_SQLITE_MSG (plugin,
711 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
716 LOG_SQLITE_MSG (plugin,
718 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
720 GNUNET_SQ_reset (plugin->dbh, stmt);
721 database_shutdown (plugin);
722 database_setup (plugin->env->cfg, plugin);
723 cont (cont_cls, key, size, GNUNET_SYSERR, msg);
724 GNUNET_free_non_null (msg);
727 GNUNET_SQ_reset (plugin->dbh, stmt);
728 cont (cont_cls, key, size, ret, msg);
729 GNUNET_free_non_null (msg);
734 * Execute statement that gets a row and call the callback
735 * with the result. Resets the statement afterwards.
737 * @param plugin the plugin
738 * @param stmt the statement
739 * @param proc processor to call
740 * @param proc_cls closure for @a proc
743 execute_get (struct Plugin *plugin,
745 PluginDatumProcessor proc,
749 struct GNUNET_TIME_Absolute expiration;
750 uint32_t replication;
757 struct GNUNET_HashCode key;
759 struct GNUNET_SQ_ResultSpec rs[] =
760 {GNUNET_SQ_result_spec_uint32 (&replication),
761 GNUNET_SQ_result_spec_uint32 (&type),
762 GNUNET_SQ_result_spec_uint32 (&priority),
763 GNUNET_SQ_result_spec_uint32 (&anonymity),
764 GNUNET_SQ_result_spec_absolute_time (&expiration),
765 GNUNET_SQ_result_spec_auto_from_type (&key),
766 GNUNET_SQ_result_spec_variable_size (&value, &value_size),
767 GNUNET_SQ_result_spec_uint64 (&rowid),
768 GNUNET_SQ_result_spec_end};
770 n = sqlite3_step (stmt);
774 if (GNUNET_OK != GNUNET_SQ_extract_result (stmt, rs))
779 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
781 "Found reply in database with expiration %s\n",
782 GNUNET_STRINGS_absolute_time_to_string (expiration));
783 ret = proc (proc_cls,
793 GNUNET_SQ_cleanup_result (rs);
794 GNUNET_SQ_reset (plugin->dbh, stmt);
795 if ((GNUNET_NO == ret) && (GNUNET_OK == delete_by_rowid (plugin, rowid)) &&
796 (NULL != plugin->env->duc))
797 plugin->env->duc (plugin->env->cls,
798 -(value_size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
801 /* database must be empty */
808 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
810 if (SQLITE_OK != sqlite3_reset (stmt))
812 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
815 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
816 database_shutdown (plugin);
817 database_setup (plugin->env->cfg, plugin);
820 GNUNET_SQ_reset (plugin->dbh, stmt);
821 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
826 * Select a subset of the items in the datastore and call
827 * the given processor for the item.
829 * @param cls our plugin context
830 * @param next_uid return the result with lowest uid >= next_uid
831 * @param type entries of which type should be considered?
832 * Must not be zero (ANY).
833 * @param proc function to call on the matching value;
834 * will be called with NULL if no value matches
835 * @param proc_cls closure for @a proc
838 sqlite_plugin_get_zero_anonymity (void *cls,
840 enum GNUNET_BLOCK_Type type,
841 PluginDatumProcessor proc,
844 struct Plugin *plugin = cls;
845 uint32_t type32 = type;
846 struct GNUNET_SQ_QueryParam params[] = {GNUNET_SQ_query_param_uint64 (
848 GNUNET_SQ_query_param_uint32 (
850 GNUNET_SQ_query_param_end};
852 GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY);
853 if (GNUNET_OK != GNUNET_SQ_bind (plugin->selZeroAnon, params))
855 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
858 execute_get (plugin, plugin->selZeroAnon, proc, proc_cls);
863 * Get results for a particular key in the datastore.
866 * @param next_uid return the result with lowest uid >= next_uid
867 * @param random if true, return a random result instead of using next_uid
868 * @param key maybe NULL (to match all entries)
869 * @param type entries of which type are relevant?
870 * Use 0 for any type.
871 * @param proc function to call on the matching value;
872 * will be called with NULL if nothing matches
873 * @param proc_cls closure for @a proc
876 sqlite_plugin_get_key (void *cls,
879 const struct GNUNET_HashCode *key,
880 enum GNUNET_BLOCK_Type type,
881 PluginDatumProcessor proc,
884 struct Plugin *plugin = cls;
886 int use_rvalue = random;
887 uint32_t type32 = (uint32_t) type;
888 int use_type = GNUNET_BLOCK_TYPE_ANY != type;
889 int use_key = NULL != key;
890 sqlite3_stmt *stmt = plugin->get[use_rvalue * 4 + use_key * 2 + use_type];
891 struct GNUNET_SQ_QueryParam params[] =
892 {GNUNET_SQ_query_param_uint64 (&next_uid),
893 GNUNET_SQ_query_param_uint64 (&rvalue),
894 GNUNET_SQ_query_param_auto_from_type (key),
895 GNUNET_SQ_query_param_uint32 (&type32),
896 GNUNET_SQ_query_param_end};
898 /* SQLite doesn't like it when you try to bind a parameter greater than the
899 * last numbered parameter, but unused parameters in the middle are OK.
903 params[3] = (struct GNUNET_SQ_QueryParam) GNUNET_SQ_query_param_end;
906 params[2] = (struct GNUNET_SQ_QueryParam) GNUNET_SQ_query_param_end;
908 params[1] = (struct GNUNET_SQ_QueryParam) GNUNET_SQ_query_param_end;
913 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
919 if (GNUNET_OK != GNUNET_SQ_bind (stmt, params))
921 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
924 execute_get (plugin, stmt, proc, proc_cls);
929 * Context for #repl_proc() function.
935 * Function to call for the result (or the NULL).
937 PluginDatumProcessor proc;
940 * Closure for @e proc.
950 * Yes if UID was set.
957 * Wrapper for the processor for #sqlite_plugin_get_replication().
958 * Decrements the replication counter and calls the original
962 * @param key key for the content
963 * @param size number of bytes in @a data
964 * @param data content stored
965 * @param type type of the content
966 * @param priority priority of the content
967 * @param anonymity anonymity-level for the content
968 * @param replication replication-level for the content
969 * @param expiration expiration time for the content
970 * @param uid unique identifier for the datum;
971 * maybe 0 if no unique identifier is available
972 * @return #GNUNET_OK for normal return,
973 * #GNUNET_NO to delete the item
976 repl_proc (void *cls,
977 const struct GNUNET_HashCode *key,
980 enum GNUNET_BLOCK_Type type,
983 uint32_t replication,
984 struct GNUNET_TIME_Absolute expiration,
987 struct ReplCtx *rc = cls;
990 if (GNUNET_SYSERR == rc->have_uid)
991 rc->have_uid = GNUNET_NO;
992 ret = rc->proc (rc->proc_cls,
1005 rc->have_uid = GNUNET_YES;
1012 * Get a random item for replication. Returns a single random item
1013 * from those with the highest replication counters. The item's
1014 * replication counter is decremented by one IF it was positive before.
1015 * Call @a proc with all values ZERO or NULL if the datastore is empty.
1017 * @param cls closure
1018 * @param proc function to call the value (once only).
1019 * @param proc_cls closure for @a proc
1022 sqlite_plugin_get_replication (void *cls,
1023 PluginDatumProcessor proc,
1026 struct Plugin *plugin = cls;
1030 struct GNUNET_SQ_QueryParam params_sel_repl[] =
1031 {GNUNET_SQ_query_param_uint64 (&rvalue),
1032 GNUNET_SQ_query_param_uint32 (&repl),
1033 GNUNET_SQ_query_param_end};
1034 struct GNUNET_SQ_QueryParam params_upd_repl[] =
1035 {GNUNET_SQ_query_param_uint64 (&rc.uid), GNUNET_SQ_query_param_end};
1037 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1039 "Getting random block based on replication order.\n");
1040 if (SQLITE_ROW != sqlite3_step (plugin->maxRepl))
1042 GNUNET_SQ_reset (plugin->dbh, plugin->maxRepl);
1044 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1047 repl = sqlite3_column_int (plugin->maxRepl, 0);
1048 GNUNET_SQ_reset (plugin->dbh, plugin->maxRepl);
1049 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
1050 if (GNUNET_OK != GNUNET_SQ_bind (plugin->selRepl, params_sel_repl))
1052 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1055 rc.have_uid = GNUNET_SYSERR;
1057 rc.proc_cls = proc_cls;
1058 execute_get (plugin, plugin->selRepl, &repl_proc, &rc);
1059 if (GNUNET_YES == rc.have_uid)
1061 if (GNUNET_OK != GNUNET_SQ_bind (plugin->updRepl, params_upd_repl))
1063 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1066 if (SQLITE_DONE != sqlite3_step (plugin->updRepl))
1068 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1070 GNUNET_SQ_reset (plugin->dbh, plugin->updRepl);
1072 if (GNUNET_SYSERR == rc.have_uid)
1074 /* proc was not called at all so far, do it now. */
1075 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1081 * Get a random item that has expired or has low priority.
1082 * Call @a proc with all values ZERO or NULL if the datastore is empty.
1084 * @param cls closure
1085 * @param proc function to call the value (once only).
1086 * @param proc_cls closure for @a proc
1089 sqlite_plugin_get_expiration (void *cls,
1090 PluginDatumProcessor proc,
1093 struct Plugin *plugin = cls;
1095 struct GNUNET_TIME_Absolute now;
1096 struct GNUNET_SQ_QueryParam params[] = {GNUNET_SQ_query_param_absolute_time (
1098 GNUNET_SQ_query_param_end};
1101 GNUNET_ERROR_TYPE_DEBUG,
1103 "Getting random block based on expiration and priority order.\n");
1104 now = GNUNET_TIME_absolute_get ();
1105 stmt = plugin->selExpi;
1106 if (GNUNET_OK != GNUNET_SQ_bind (stmt, params))
1108 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1111 execute_get (plugin, stmt, proc, proc_cls);
1116 * Get all of the keys in the datastore.
1118 * @param cls closure
1119 * @param proc function to call on each key
1120 * @param proc_cls closure for @a proc
1123 sqlite_plugin_get_keys (void *cls, PluginKeyProcessor proc, void *proc_cls)
1125 struct Plugin *plugin = cls;
1126 struct GNUNET_HashCode key;
1127 struct GNUNET_SQ_ResultSpec results[] =
1128 {GNUNET_SQ_result_spec_auto_from_type (&key), GNUNET_SQ_result_spec_end};
1132 GNUNET_assert (NULL != proc);
1133 if (SQLITE_OK != sq_prepare (plugin->dbh, "SELECT hash FROM gn091", &stmt))
1136 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1138 proc (proc_cls, NULL, 0);
1141 while (SQLITE_ROW == (ret = sqlite3_step (stmt)))
1143 if (GNUNET_OK == GNUNET_SQ_extract_result (stmt, results))
1144 proc (proc_cls, &key, 1);
1148 if (SQLITE_DONE != ret)
1149 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step");
1150 sqlite3_finalize (stmt);
1151 proc (proc_cls, NULL, 0);
1158 * @param cls our plugin context
1161 sqlite_plugin_drop (void *cls)
1163 struct Plugin *plugin = cls;
1165 plugin->drop_on_shutdown = GNUNET_YES;
1170 * Remove a particular key in the datastore.
1172 * @param cls closure
1173 * @param key key for the content
1174 * @param size number of bytes in data
1175 * @param data content stored
1176 * @param cont continuation called with success or failure status
1177 * @param cont_cls continuation closure for @a cont
1180 sqlite_plugin_remove_key (void *cls,
1181 const struct GNUNET_HashCode *key,
1184 PluginRemoveCont cont,
1187 struct Plugin *plugin = cls;
1188 struct GNUNET_SQ_QueryParam params[] =
1189 {GNUNET_SQ_query_param_auto_from_type (key),
1190 GNUNET_SQ_query_param_fixed_size (data, size),
1191 GNUNET_SQ_query_param_end};
1193 if (GNUNET_OK != GNUNET_SQ_bind (plugin->remove, params))
1195 cont (cont_cls, key, size, GNUNET_SYSERR, "bind failed");
1198 if (SQLITE_DONE != sqlite3_step (plugin->remove))
1201 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1203 GNUNET_SQ_reset (plugin->dbh, plugin->remove);
1204 cont (cont_cls, key, size, GNUNET_SYSERR, "sqlite3_step failed");
1207 int changes = sqlite3_changes (plugin->dbh);
1208 GNUNET_SQ_reset (plugin->dbh, plugin->remove);
1211 cont (cont_cls, key, size, GNUNET_NO, NULL);
1214 if (NULL != plugin->env->duc)
1215 plugin->env->duc (plugin->env->cls,
1216 -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
1217 cont (cont_cls, key, size, GNUNET_OK, NULL);
1222 * Get an estimate of how much space the database is
1225 * @param cls the `struct Plugin`
1226 * @return the size of the database on disk (estimate)
1229 sqlite_plugin_estimate_size (void *cls, unsigned long long *estimate)
1231 struct Plugin *plugin = cls;
1240 if (NULL == estimate)
1242 if (SQLITE_VERSION_NUMBER < 3006000)
1245 GNUNET_ERROR_TYPE_WARNING,
1247 _ ("sqlite version to old to determine size, assuming zero\n"));
1251 CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "VACUUM", NULL, NULL, ENULL));
1252 CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh,
1253 "PRAGMA auto_vacuum=INCREMENTAL",
1257 CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "PRAGMA page_count", &stmt));
1258 if (SQLITE_ROW == sqlite3_step (stmt))
1259 pages = sqlite3_column_int64 (stmt, 0);
1262 sqlite3_finalize (stmt);
1263 CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "PRAGMA page_size", &stmt));
1264 CHECK (SQLITE_ROW == sqlite3_step (stmt));
1265 page_size = sqlite3_column_int64 (stmt, 0);
1266 sqlite3_finalize (stmt);
1268 GNUNET_ERROR_TYPE_INFO,
1270 "Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"),
1271 (unsigned long long) pages,
1272 (unsigned long long) page_size);
1273 *estimate = pages * page_size;
1278 * Entry point for the plugin.
1280 * @param cls the `struct GNUNET_DATASTORE_PluginEnvironment *`
1281 * @return NULL on error, othrewise the plugin context
1284 libgnunet_plugin_datastore_sqlite_init (void *cls)
1286 static struct Plugin plugin;
1287 struct GNUNET_DATASTORE_PluginEnvironment *env = cls;
1288 struct GNUNET_DATASTORE_PluginFunctions *api;
1290 if (NULL != plugin.env)
1291 return NULL; /* can only initialize once! */
1292 memset (&plugin, 0, sizeof (struct Plugin));
1294 if (GNUNET_OK != database_setup (env->cfg, &plugin))
1296 database_shutdown (&plugin);
1299 api = GNUNET_new (struct GNUNET_DATASTORE_PluginFunctions);
1301 api->estimate_size = &sqlite_plugin_estimate_size;
1302 api->put = &sqlite_plugin_put;
1303 api->get_key = &sqlite_plugin_get_key;
1304 api->get_replication = &sqlite_plugin_get_replication;
1305 api->get_expiration = &sqlite_plugin_get_expiration;
1306 api->get_zero_anonymity = &sqlite_plugin_get_zero_anonymity;
1307 api->get_keys = &sqlite_plugin_get_keys;
1308 api->drop = &sqlite_plugin_drop;
1309 api->remove_key = &sqlite_plugin_remove_key;
1310 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
1312 _ ("Sqlite database running\n"));
1318 * Exit point from the plugin.
1320 * @param cls the plugin context (as returned by "init")
1321 * @return always NULL
1324 libgnunet_plugin_datastore_sqlite_done (void *cls)
1327 struct GNUNET_DATASTORE_PluginFunctions *api = cls;
1328 struct Plugin *plugin = api->cls;
1330 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1332 "sqlite plugin is done\n");
1334 if (plugin->drop_on_shutdown)
1335 fn = GNUNET_strdup (plugin->fn);
1336 database_shutdown (plugin);
1341 if (0 != unlink (fn))
1342 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
1348 /* end of plugin_datastore_sqlite.c */