GNUnet  0.10.x
plugin_datastore_sqlite.c
Go to the documentation of this file.
1 /*
2  * This file is part of GNUnet
3  * Copyright (C) 2009, 2011, 2017 GNUnet e.V.
4  *
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.
9  *
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.
14  *
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/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 
27 #include "platform.h"
29 #include "gnunet_sq_lib.h"
30 #include <sqlite3.h>
31 
32 
38 #define MAX_ITEM_SIZE 65536
39 
50 #define BUSY_TIMEOUT_MS 250
51 
52 
58 #define LOG_SQLITE(db, level, cmd) \
59  do \
60  { \
61  GNUNET_log_from(level, \
62  "sqlite", \
63  _("`%s' failed at %s:%d with error: %s\n"), \
64  cmd, \
65  __FILE__, \
66  __LINE__, \
67  sqlite3_errmsg(db->dbh)); \
68  } while (0)
69 
70 
76 #define LOG_SQLITE_MSG(db, msg, level, cmd) \
77  do \
78  { \
79  GNUNET_log_from(level, \
80  "sqlite", \
81  _("`%s' failed at %s:%d with error: %s\n"), \
82  cmd, \
83  __FILE__, \
84  __LINE__, \
85  sqlite3_errmsg(db->dbh)); \
86  GNUNET_asprintf(msg, \
87  _("`%s' failed at %s:%u with error: %s"), \
88  cmd, \
89  __FILE__, \
90  __LINE__, \
91  sqlite3_errmsg(db->dbh)); \
92  } while (0)
93 
94 
98 struct Plugin {
103 
107  char *fn;
108 
112  sqlite3 *dbh;
113 
117  sqlite3_stmt *remove;
118 
122  sqlite3_stmt *delRow;
123 
127  sqlite3_stmt *update;
128 
132  sqlite3_stmt *maxRepl;
133 
137  sqlite3_stmt *updRepl;
138 
142  sqlite3_stmt *selRepl;
143 
147  sqlite3_stmt *selExpi;
148 
152  sqlite3_stmt *selZeroAnon;
153 
157  sqlite3_stmt *insertContent;
158 
162  sqlite3_stmt *get[8];
163 
168 };
169 
170 
179 static int
180 sq_prepare(sqlite3 *dbh, const char *zSql, sqlite3_stmt **ppStmt)
181 {
182  char *dummy;
183  int result;
184 
185  result = sqlite3_prepare_v2(dbh,
186  zSql,
187  strlen(zSql),
188  ppStmt,
189  (const char **)&dummy);
191  "sqlite",
192  "Prepared `%s' / %p: %d\n",
193  zSql,
194  *ppStmt,
195  result);
196  return result;
197 }
198 
199 
205 static void
207 {
208  /* create indices */
209  if (
210  0 !=
211  (SQLITE_OK !=
212  sqlite3_exec(dbh,
213  "CREATE INDEX IF NOT EXISTS idx_hash ON gn091 (hash)",
214  NULL,
215  NULL,
216  NULL)) +
217  (SQLITE_OK !=
218  sqlite3_exec(
219  dbh,
220  "CREATE INDEX IF NOT EXISTS idx_anon_type ON gn091 (anonLevel ASC,type)",
221  NULL,
222  NULL,
223  NULL)) +
224  (SQLITE_OK !=
225  sqlite3_exec(dbh,
226  "CREATE INDEX IF NOT EXISTS idx_expire ON gn091 (expire ASC)",
227  NULL,
228  NULL,
229  NULL)) +
230  (SQLITE_OK !=
231  sqlite3_exec(
232  dbh,
233  "CREATE INDEX IF NOT EXISTS idx_repl_rvalue ON gn091 (repl,rvalue)",
234  NULL,
235  NULL,
236  NULL)))
238  "sqlite",
239  "Failed to create indices: %s\n",
240  sqlite3_errmsg(dbh));
241 }
242 
243 
244 #if 0
245 #define CHECK(a) GNUNET_break(a)
246 #define ENULL NULL
247 #else
248 #define ENULL &e
249 #define ENULL_DEFINED 1
250 #define CHECK(a) \
251  if (!(a)) \
252  { \
253  GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", e); \
254  sqlite3_free(e); \
255  }
256 #endif
257 
258 
268 static int
270  struct Plugin *plugin)
271 {
272  sqlite3_stmt *stmt;
273  char *afsdir;
274 
275 #if ENULL_DEFINED
276  char *e;
277 #endif
278 
280  "datastore-sqlite",
281  "FILENAME",
282  &afsdir))
283  {
285  "datastore-sqlite",
286  "FILENAME");
287  return GNUNET_SYSERR;
288  }
289  if (GNUNET_OK != GNUNET_DISK_file_test(afsdir))
290  {
292  {
293  GNUNET_break(0);
294  GNUNET_free(afsdir);
295  return GNUNET_SYSERR;
296  }
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);
300  }
301  /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */
302  plugin->fn = afsdir;
303 
304  /* Open database and precompile statements */
305  if (SQLITE_OK != sqlite3_open(plugin->fn, &plugin->dbh))
306  {
308  "sqlite",
309  _("Unable to initialize SQLite: %s.\n"),
310  sqlite3_errmsg(plugin->dbh));
311  return GNUNET_SYSERR;
312  }
313  CHECK(
314  SQLITE_OK ==
315  sqlite3_exec(plugin->dbh, "PRAGMA temp_store=MEMORY", NULL, NULL, ENULL));
316  CHECK(
317  SQLITE_OK ==
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",
321  NULL,
322  NULL,
323  ENULL));
324  CHECK(SQLITE_OK == sqlite3_exec(plugin->dbh,
325  "PRAGMA auto_vacuum=INCREMENTAL",
326  NULL,
327  NULL,
328  ENULL));
329  CHECK(SQLITE_OK == sqlite3_exec(plugin->dbh,
330  "PRAGMA locking_mode=EXCLUSIVE",
331  NULL,
332  NULL,
333  ENULL));
334  CHECK(
335  SQLITE_OK ==
336  sqlite3_exec(plugin->dbh, "PRAGMA page_size=4096", NULL, NULL, ENULL));
337 
338  CHECK(SQLITE_OK == sqlite3_busy_timeout(plugin->dbh, BUSY_TIMEOUT_MS));
339 
340 
341  /* We have to do it here, because otherwise precompiling SQL might fail */
342  CHECK(SQLITE_OK ==
343  sq_prepare(plugin->dbh,
344  "SELECT 1 FROM sqlite_master WHERE tbl_name = 'gn091'",
345  &stmt));
346 
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.
351  */
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 '')",
364  NULL,
365  NULL,
366  NULL)))
367  {
368  LOG_SQLITE(plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec");
369  sqlite3_finalize(stmt);
370  return GNUNET_SYSERR;
371  }
372  sqlite3_finalize(stmt);
373  create_indices(plugin->dbh);
374 
375 #define RESULT_COLUMNS \
376  "repl, type, prio, anonLevel, expire, hash, value, _ROWID_"
377  if (
378  (SQLITE_OK != sq_prepare(plugin->dbh,
379  "UPDATE gn091 "
380  "SET prio = prio + ?, "
381  "repl = repl + ?, "
382  "expire = MAX(expire, ?) "
383  "WHERE hash = ? AND vhash = ?",
384  &plugin->update)) ||
385  (SQLITE_OK != sq_prepare(plugin->dbh,
386  "UPDATE gn091 "
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 "
391  "WHERE repl=?2 AND "
392  " (rvalue>=?1 OR "
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)) ||
400  (SQLITE_OK !=
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 "
409  "anonLevel = 0 AND "
410  "type = ? "
411  "ORDER BY _ROWID_ ASC LIMIT 1",
412  &plugin->selZeroAnon)) ||
413  (SQLITE_OK !=
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",
422  &plugin->get[0])) ||
423  (SQLITE_OK != sq_prepare(plugin->dbh,
424  "SELECT " RESULT_COLUMNS " FROM gn091 "
425  "WHERE _ROWID_ >= ?1 AND "
426  "type = ?4 "
427  "ORDER BY _ROWID_ ASC LIMIT 1",
428  &plugin->get[1])) ||
429  (SQLITE_OK != sq_prepare(plugin->dbh,
430  "SELECT " RESULT_COLUMNS " FROM gn091 "
431  "WHERE _ROWID_ >= ?1 AND "
432  "hash = ?3 "
433  "ORDER BY _ROWID_ ASC LIMIT 1",
434  &plugin->get[2])) ||
435  (SQLITE_OK != sq_prepare(plugin->dbh,
436  "SELECT " RESULT_COLUMNS " FROM gn091 "
437  "WHERE _ROWID_ >= ?1 AND "
438  "hash = ?3 AND "
439  "type = ?4 "
440  "ORDER BY _ROWID_ ASC LIMIT 1",
441  &plugin->get[3])) ||
442  (SQLITE_OK != sq_prepare(plugin->dbh,
443  "SELECT " RESULT_COLUMNS " FROM gn091 "
444  "WHERE _ROWID_ >= ?1 AND "
445  "rvalue >= ?2 "
446  "ORDER BY _ROWID_ ASC LIMIT 1",
447  &plugin->get[4])) ||
448  (SQLITE_OK != sq_prepare(plugin->dbh,
449  "SELECT " RESULT_COLUMNS " FROM gn091 "
450  "WHERE _ROWID_ >= ?1 AND "
451  "rvalue >= ?2 AND "
452  "type = ?4 "
453  "ORDER BY _ROWID_ ASC LIMIT 1",
454  &plugin->get[5])) ||
455  (SQLITE_OK != sq_prepare(plugin->dbh,
456  "SELECT " RESULT_COLUMNS " FROM gn091 "
457  "WHERE _ROWID_ >= ?1 AND "
458  "rvalue >= ?2 AND "
459  "hash = ?3 "
460  "ORDER BY _ROWID_ ASC LIMIT 1",
461  &plugin->get[6])) ||
462  (SQLITE_OK != sq_prepare(plugin->dbh,
463  "SELECT " RESULT_COLUMNS " FROM gn091 "
464  "WHERE _ROWID_ >= ?1 AND "
465  "rvalue >= ?2 AND "
466  "hash = ?3 AND "
467  "type = ?4 "
468  "ORDER BY _ROWID_ ASC LIMIT 1",
469  &plugin->get[7])) ||
470  (SQLITE_OK != sq_prepare(plugin->dbh,
471  "DELETE FROM gn091 WHERE _ROWID_ = ?",
472  &plugin->delRow)) ||
473  (SQLITE_OK != sq_prepare(plugin->dbh,
474  "DELETE FROM gn091 "
475  "WHERE hash = ? AND "
476  "value = ? ",
477  &plugin->remove)) ||
478  false)
479  {
480  LOG_SQLITE(plugin, GNUNET_ERROR_TYPE_ERROR, "precompiling");
481  return GNUNET_SYSERR;
482  }
483  return GNUNET_OK;
484 }
485 
486 
493 static void
495 {
496  int result;
497 
498 #if SQLITE_VERSION_NUMBER >= 3007000
499  sqlite3_stmt *stmt;
500 #endif
501 
502  if (NULL != plugin->remove)
503  sqlite3_finalize(plugin->remove);
504  if (NULL != plugin->delRow)
505  sqlite3_finalize(plugin->delRow);
506  if (NULL != plugin->update)
507  sqlite3_finalize(plugin->update);
508  if (NULL != plugin->updRepl)
509  sqlite3_finalize(plugin->updRepl);
510  if (NULL != plugin->selRepl)
511  sqlite3_finalize(plugin->selRepl);
512  if (NULL != plugin->maxRepl)
513  sqlite3_finalize(plugin->maxRepl);
514  if (NULL != plugin->selExpi)
515  sqlite3_finalize(plugin->selExpi);
516  if (NULL != plugin->selZeroAnon)
517  sqlite3_finalize(plugin->selZeroAnon);
518  if (NULL != plugin->insertContent)
519  sqlite3_finalize(plugin->insertContent);
520  for (int i = 0; i < 8; ++i)
521  if (NULL != plugin->get[i])
522  sqlite3_finalize(plugin->get[i]);
523  result = sqlite3_close(plugin->dbh);
524 #if SQLITE_VERSION_NUMBER >= 3007000
525  if (result == SQLITE_BUSY)
526  {
529  "sqlite",
530  _(
531  "Tried to close sqlite without finalizing all prepared statements.\n"));
532  stmt = sqlite3_next_stmt(plugin->dbh, NULL);
533  while (NULL != stmt)
534  {
536  "sqlite",
537  "Closing statement %p\n",
538  stmt);
539  result = sqlite3_finalize(stmt);
540  if (result != SQLITE_OK)
542  "sqlite",
543  "Failed to close statement %p: %d\n",
544  stmt,
545  result);
546  stmt = sqlite3_next_stmt(plugin->dbh, NULL);
547  }
548  result = sqlite3_close(plugin->dbh);
549  }
550 #endif
551  if (SQLITE_OK != result)
552  LOG_SQLITE(plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close");
553  GNUNET_free_non_null(plugin->fn);
554 }
555 
556 
564 static int
565 delete_by_rowid(struct Plugin *plugin, uint64_t rid)
566 {
567  struct GNUNET_SQ_QueryParam params[] = { GNUNET_SQ_query_param_uint64(&rid),
569 
570  if (GNUNET_OK != GNUNET_SQ_bind(plugin->delRow, params))
571  return GNUNET_SYSERR;
572  if (SQLITE_DONE != sqlite3_step(plugin->delRow))
573  {
574  LOG_SQLITE(plugin,
576  "sqlite3_step");
577  GNUNET_SQ_reset(plugin->dbh, plugin->delRow);
578  return GNUNET_SYSERR;
579  }
580  GNUNET_SQ_reset(plugin->dbh, plugin->delRow);
581  return GNUNET_OK;
582 }
583 
584 
601 static void
603  const struct GNUNET_HashCode *key,
604  bool absent,
605  uint32_t size,
606  const void *data,
607  enum GNUNET_BLOCK_Type type,
608  uint32_t priority,
609  uint32_t anonymity,
610  uint32_t replication,
612  PluginPutCont cont,
613  void *cont_cls)
614 {
615  struct Plugin *plugin = cls;
616  struct GNUNET_HashCode vhash;
617  char *msg = NULL;
618 
619  GNUNET_CRYPTO_hash(data, size, &vhash);
620 
621  if (!absent)
622  {
623  struct GNUNET_SQ_QueryParam params[] =
624  { GNUNET_SQ_query_param_uint32(&priority),
625  GNUNET_SQ_query_param_uint32(&replication),
630 
631  if (GNUNET_OK != GNUNET_SQ_bind(plugin->update, params))
632  {
633  cont(cont_cls, key, size, GNUNET_SYSERR, _("sqlite bind failure"));
634  return;
635  }
636  if (SQLITE_DONE != sqlite3_step(plugin->update))
637  {
638  LOG_SQLITE_MSG(plugin,
639  &msg,
641  "sqlite3_step");
642  cont(cont_cls, key, size, GNUNET_SYSERR, msg);
644  return;
645  }
646  int changes = sqlite3_changes(plugin->dbh);
647  GNUNET_SQ_reset(plugin->dbh, plugin->update);
648  if (0 != changes)
649  {
650  cont(cont_cls, key, size, GNUNET_NO, NULL);
651  return;
652  }
653  }
654 
655  uint64_t rvalue;
656  uint32_t type32 = (uint32_t)type;
657  struct GNUNET_SQ_QueryParam params[] =
658  { GNUNET_SQ_query_param_uint32(&replication),
660  GNUNET_SQ_query_param_uint32(&priority),
661  GNUNET_SQ_query_param_uint32(&anonymity),
668  int n;
669  int ret;
670  sqlite3_stmt *stmt;
671 
672  if (size > MAX_ITEM_SIZE)
673  {
674  cont(cont_cls, key, size, GNUNET_SYSERR, _("Data too large"));
675  return;
676  }
679  "sqlite",
680  "Storing in database block with type %u/key `%s'/priority %u/expiration in %s (%s).\n",
681  type,
682  GNUNET_h2s(key),
683  priority,
685  expiration),
686  GNUNET_YES),
688  stmt = plugin->insertContent;
690  if (GNUNET_OK != GNUNET_SQ_bind(stmt, params))
691  {
692  cont(cont_cls, key, size, GNUNET_SYSERR, NULL);
693  return;
694  }
695  n = sqlite3_step(stmt);
696  switch (n)
697  {
698  case SQLITE_DONE:
699  if (NULL != plugin->env->duc)
700  plugin->env->duc(plugin->env->cls,
703  "sqlite",
704  "Stored new entry (%u bytes)\n",
706  ret = GNUNET_OK;
707  break;
708 
709  case SQLITE_BUSY:
710  GNUNET_break(0);
711  LOG_SQLITE_MSG(plugin,
712  &msg,
714  "sqlite3_step");
715  ret = GNUNET_SYSERR;
716  break;
717 
718  default:
719  LOG_SQLITE_MSG(plugin,
720  &msg,
722  "sqlite3_step");
723  GNUNET_SQ_reset(plugin->dbh, stmt);
724  database_shutdown(plugin);
725  database_setup(plugin->env->cfg, plugin);
726  cont(cont_cls, key, size, GNUNET_SYSERR, msg);
728  return;
729  }
730  GNUNET_SQ_reset(plugin->dbh, stmt);
731  cont(cont_cls, key, size, ret, msg);
733 }
734 
735 
745 static void
747  sqlite3_stmt *stmt,
749  void *proc_cls)
750 {
751  int n;
752  struct GNUNET_TIME_Absolute expiration;
753  uint32_t replication;
754  uint32_t type;
755  uint32_t priority;
756  uint32_t anonymity;
757  uint64_t rowid;
758  void *value;
759  size_t value_size;
760  struct GNUNET_HashCode key;
761  int ret;
762  struct GNUNET_SQ_ResultSpec rs[] =
763  { GNUNET_SQ_result_spec_uint32(&replication),
765  GNUNET_SQ_result_spec_uint32(&priority),
766  GNUNET_SQ_result_spec_uint32(&anonymity),
769  GNUNET_SQ_result_spec_variable_size(&value, &value_size),
772 
773  n = sqlite3_step(stmt);
774  switch (n)
775  {
776  case SQLITE_ROW:
777  if (GNUNET_OK != GNUNET_SQ_extract_result(stmt, rs))
778  {
779  GNUNET_break(0);
780  break;
781  }
783  "sqlite",
784  "Found reply in database with expiration %s\n",
786  ret = proc(proc_cls,
787  &key,
788  value_size,
789  value,
790  type,
791  priority,
792  anonymity,
793  replication,
794  expiration,
795  rowid);
797  GNUNET_SQ_reset(plugin->dbh, stmt);
798  if ((GNUNET_NO == ret) && (GNUNET_OK == delete_by_rowid(plugin, rowid)) &&
799  (NULL != plugin->env->duc))
800  plugin->env->duc(plugin->env->cls,
801  -(value_size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
802  return;
803 
804  case SQLITE_DONE:
805  /* database must be empty */
806  break;
807 
808  case SQLITE_BUSY:
809  case SQLITE_ERROR:
810  case SQLITE_MISUSE:
811  default:
812  LOG_SQLITE(plugin,
814  "sqlite3_step");
815  if (SQLITE_OK != sqlite3_reset(stmt))
816  LOG_SQLITE(plugin,
818  "sqlite3_reset");
819  GNUNET_break(0);
820  proc(proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
821  database_shutdown(plugin);
822  database_setup(plugin->env->cfg, plugin);
823  return;
824  }
825  GNUNET_SQ_reset(plugin->dbh, stmt);
826  proc(proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
827 }
828 
829 
842 static void
844  uint64_t next_uid,
845  enum GNUNET_BLOCK_Type type,
847  void *proc_cls)
848 {
849  struct Plugin *plugin = cls;
850  uint32_t type32 = type;
852  &next_uid),
854  &type32),
856 
858  if (GNUNET_OK != GNUNET_SQ_bind(plugin->selZeroAnon, params))
859  {
860  proc(proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
861  return;
862  }
863  execute_get(plugin, plugin->selZeroAnon, proc, proc_cls);
864 }
865 
866 
880 static void
882  uint64_t next_uid,
883  bool random,
884  const struct GNUNET_HashCode *key,
885  enum GNUNET_BLOCK_Type type,
887  void *proc_cls)
888 {
889  struct Plugin *plugin = cls;
890  uint64_t rvalue;
891  int use_rvalue = random;
892  uint32_t type32 = (uint32_t)type;
893  int use_type = GNUNET_BLOCK_TYPE_ANY != type;
894  int use_key = NULL != key;
895  sqlite3_stmt *stmt = plugin->get[use_rvalue * 4 + use_key * 2 + use_type];
896  struct GNUNET_SQ_QueryParam params[] =
897  { GNUNET_SQ_query_param_uint64(&next_uid),
902 
903  /* SQLite doesn't like it when you try to bind a parameter greater than the
904  * last numbered parameter, but unused parameters in the middle are OK.
905  */
906  if (!use_type)
907  {
908  params[3] = (struct GNUNET_SQ_QueryParam)GNUNET_SQ_query_param_end;
909  if (!use_key)
910  {
911  params[2] = (struct GNUNET_SQ_QueryParam)GNUNET_SQ_query_param_end;
912  if (!use_rvalue)
913  params[1] = (struct GNUNET_SQ_QueryParam)GNUNET_SQ_query_param_end;
914  }
915  }
916  if (random)
917  {
919  next_uid = 0;
920  }
921  else
922  rvalue = 0;
923 
924  if (GNUNET_OK != GNUNET_SQ_bind(stmt, params))
925  {
926  proc(proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
927  return;
928  }
929  execute_get(plugin, stmt, proc, proc_cls);
930 }
931 
932 
936 struct ReplCtx {
941 
945  void *proc_cls;
946 
950  uint64_t uid;
951 
955  int have_uid;
956 };
957 
958 
978 static int
979 repl_proc(void *cls,
980  const struct GNUNET_HashCode *key,
981  uint32_t size,
982  const void *data,
983  enum GNUNET_BLOCK_Type type,
984  uint32_t priority,
985  uint32_t anonymity,
986  uint32_t replication,
988  uint64_t uid)
989 {
990  struct ReplCtx *rc = cls;
991  int ret;
992 
993  if (GNUNET_SYSERR == rc->have_uid)
994  rc->have_uid = GNUNET_NO;
995  ret = rc->proc(rc->proc_cls,
996  key,
997  size,
998  data,
999  type,
1000  priority,
1001  anonymity,
1002  replication,
1003  expiration,
1004  uid);
1005  if (NULL != key)
1006  {
1007  rc->uid = uid;
1008  rc->have_uid = GNUNET_YES;
1009  }
1010  return ret;
1011 }
1012 
1013 
1024 static void
1027  void *proc_cls)
1028 {
1029  struct Plugin *plugin = cls;
1030  struct ReplCtx rc;
1031  uint64_t rvalue;
1032  uint32_t repl;
1033  struct GNUNET_SQ_QueryParam params_sel_repl[] =
1034  { GNUNET_SQ_query_param_uint64(&rvalue),
1037  struct GNUNET_SQ_QueryParam params_upd_repl[] =
1039 
1041  "datastore-sqlite",
1042  "Getting random block based on replication order.\n");
1043  if (SQLITE_ROW != sqlite3_step(plugin->maxRepl))
1044  {
1045  GNUNET_SQ_reset(plugin->dbh, plugin->maxRepl);
1046  /* DB empty */
1047  proc(proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1048  return;
1049  }
1050  repl = sqlite3_column_int(plugin->maxRepl, 0);
1051  GNUNET_SQ_reset(plugin->dbh, plugin->maxRepl);
1053  if (GNUNET_OK != GNUNET_SQ_bind(plugin->selRepl, params_sel_repl))
1054  {
1055  proc(proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1056  return;
1057  }
1058  rc.have_uid = GNUNET_SYSERR;
1059  rc.proc = proc;
1060  rc.proc_cls = proc_cls;
1061  execute_get(plugin, plugin->selRepl, &repl_proc, &rc);
1062  if (GNUNET_YES == rc.have_uid)
1063  {
1064  if (GNUNET_OK != GNUNET_SQ_bind(plugin->updRepl, params_upd_repl))
1065  {
1066  proc(proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1067  return;
1068  }
1069  if (SQLITE_DONE != sqlite3_step(plugin->updRepl))
1070  LOG_SQLITE(plugin,
1072  "sqlite3_step");
1073  GNUNET_SQ_reset(plugin->dbh, plugin->updRepl);
1074  }
1075  if (GNUNET_SYSERR == rc.have_uid)
1076  {
1077  /* proc was not called at all so far, do it now. */
1078  proc(proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1079  }
1080 }
1081 
1082 
1091 static void
1093  PluginDatumProcessor proc,
1094  void *proc_cls)
1095 {
1096  struct Plugin *plugin = cls;
1097  sqlite3_stmt *stmt;
1098  struct GNUNET_TIME_Absolute now;
1100  &now),
1102 
1105  "sqlite",
1106  "Getting random block based on expiration and priority order.\n");
1107  now = GNUNET_TIME_absolute_get();
1108  stmt = plugin->selExpi;
1109  if (GNUNET_OK != GNUNET_SQ_bind(stmt, params))
1110  {
1111  proc(proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1112  return;
1113  }
1114  execute_get(plugin, stmt, proc, proc_cls);
1115 }
1116 
1117 
1125 static void
1126 sqlite_plugin_get_keys(void *cls, PluginKeyProcessor proc, void *proc_cls)
1127 {
1128  struct Plugin *plugin = cls;
1129  struct GNUNET_HashCode key;
1130  struct GNUNET_SQ_ResultSpec results[] =
1132  sqlite3_stmt *stmt;
1133  int ret;
1134 
1135  GNUNET_assert(NULL != proc);
1136  if (SQLITE_OK != sq_prepare(plugin->dbh, "SELECT hash FROM gn091", &stmt))
1137  {
1138  LOG_SQLITE(plugin,
1140  "sqlite_prepare");
1141  proc(proc_cls, NULL, 0);
1142  return;
1143  }
1144  while (SQLITE_ROW == (ret = sqlite3_step(stmt)))
1145  {
1146  if (GNUNET_OK == GNUNET_SQ_extract_result(stmt, results))
1147  proc(proc_cls, &key, 1);
1148  else
1149  GNUNET_break(0);
1150  }
1151  if (SQLITE_DONE != ret)
1152  LOG_SQLITE(plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step");
1153  sqlite3_finalize(stmt);
1154  proc(proc_cls, NULL, 0);
1155 }
1156 
1157 
1163 static void
1165 {
1166  struct Plugin *plugin = cls;
1167 
1168  plugin->drop_on_shutdown = GNUNET_YES;
1169 }
1170 
1171 
1182 static void
1184  const struct GNUNET_HashCode *key,
1185  uint32_t size,
1186  const void *data,
1187  PluginRemoveCont cont,
1188  void *cont_cls)
1189 {
1190  struct Plugin *plugin = cls;
1191  struct GNUNET_SQ_QueryParam params[] =
1195 
1196  if (GNUNET_OK != GNUNET_SQ_bind(plugin->remove, params))
1197  {
1198  cont(cont_cls, key, size, GNUNET_SYSERR, "bind failed");
1199  return;
1200  }
1201  if (SQLITE_DONE != sqlite3_step(plugin->remove))
1202  {
1203  LOG_SQLITE(plugin,
1205  "sqlite3_step");
1206  GNUNET_SQ_reset(plugin->dbh, plugin->remove);
1207  cont(cont_cls, key, size, GNUNET_SYSERR, "sqlite3_step failed");
1208  return;
1209  }
1210  int changes = sqlite3_changes(plugin->dbh);
1211  GNUNET_SQ_reset(plugin->dbh, plugin->remove);
1212  if (0 == changes)
1213  {
1214  cont(cont_cls, key, size, GNUNET_NO, NULL);
1215  return;
1216  }
1217  if (NULL != plugin->env->duc)
1218  plugin->env->duc(plugin->env->cls,
1220  cont(cont_cls, key, size, GNUNET_OK, NULL);
1221 }
1222 
1223 
1231 static void
1232 sqlite_plugin_estimate_size(void *cls, unsigned long long *estimate)
1233 {
1234  struct Plugin *plugin = cls;
1235  sqlite3_stmt *stmt;
1236  uint64_t pages;
1237  uint64_t page_size;
1238 
1239 #if ENULL_DEFINED
1240  char *e;
1241 #endif
1242 
1243  if (NULL == estimate)
1244  return;
1245  if (SQLITE_VERSION_NUMBER < 3006000)
1246  {
1249  "datastore-sqlite",
1250  _("sqlite version to old to determine size, assuming zero\n"));
1251  *estimate = 0;
1252  return;
1253  }
1254  CHECK(SQLITE_OK == sqlite3_exec(plugin->dbh, "VACUUM", NULL, NULL, ENULL));
1255  CHECK(SQLITE_OK == sqlite3_exec(plugin->dbh,
1256  "PRAGMA auto_vacuum=INCREMENTAL",
1257  NULL,
1258  NULL,
1259  ENULL));
1260  CHECK(SQLITE_OK == sq_prepare(plugin->dbh, "PRAGMA page_count", &stmt));
1261  if (SQLITE_ROW == sqlite3_step(stmt))
1262  pages = sqlite3_column_int64(stmt, 0);
1263  else
1264  pages = 0;
1265  sqlite3_finalize(stmt);
1266  CHECK(SQLITE_OK == sq_prepare(plugin->dbh, "PRAGMA page_size", &stmt));
1267  CHECK(SQLITE_ROW == sqlite3_step(stmt));
1268  page_size = sqlite3_column_int64(stmt, 0);
1269  sqlite3_finalize(stmt);
1270  GNUNET_log(
1272  _(
1273  "Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"),
1274  (unsigned long long)pages,
1275  (unsigned long long)page_size);
1276  *estimate = pages * page_size;
1277 }
1278 
1279 
1286 void *
1288 {
1289  static struct Plugin plugin;
1292 
1293  if (NULL != plugin.env)
1294  return NULL; /* can only initialize once! */
1295  memset(&plugin, 0, sizeof(struct Plugin));
1296  plugin.env = env;
1297  if (GNUNET_OK != database_setup(env->cfg, &plugin))
1298  {
1299  database_shutdown(&plugin);
1300  return NULL;
1301  }
1303  api->cls = &plugin;
1305  api->put = &sqlite_plugin_put;
1311  api->drop = &sqlite_plugin_drop;
1314  "sqlite",
1315  _("Sqlite database running\n"));
1316  return api;
1317 }
1318 
1319 
1326 void *
1328 {
1329  char *fn;
1331  struct Plugin *plugin = api->cls;
1332 
1334  "sqlite",
1335  "sqlite plugin is done\n");
1336  fn = NULL;
1337  if (plugin->drop_on_shutdown)
1338  fn = GNUNET_strdup(plugin->fn);
1339  database_shutdown(plugin);
1340  plugin->env = NULL;
1341  GNUNET_free(api);
1342  if (NULL != fn)
1343  {
1344  if (0 != unlink(fn))
1346  GNUNET_free(fn);
1347  }
1348  return NULL;
1349 }
1350 
1351 /* end of plugin_datastore_sqlite.c */
int 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)...
Definition: disk.c:541
PluginGetKeys get_keys
Iterate over all keys in the database.
PluginPut put
Function to store an item in the datastore.
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...
int(* 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 * proc_cls
Closure for proc.
PluginGetType get_zero_anonymity
Get datum (of the specified type) with anonymity level zero.
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.
Description of a DB result cell.
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
#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 char * expiration
Credential TTL.
sqlite3_stmt * update
Precompiled SQL for update.
#define GNUNET_TIME_UNIT_ZERO_ABS
Absolute time zero.
struct GNUNET_SQ_ResultSpec GNUNET_SQ_result_spec_uint32(uint32_t *u32)
uint32_t expected.
int have_uid
Yes if UID was set.
Any type of block, used as a wildcard when searching.
GNUNET_BLOCK_Type
Blocks in the datastore and the datacache must have a unique type.
const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration to use.
uint64_t GNUNET_CRYPTO_random_u64(enum GNUNET_CRYPTO_Quality mode, uint64_t max)
Random on unsigned 64-bit values.
sqlite3_stmt * updRepl
Precompiled SQL for replication decrement.
static int sq_prepare(sqlite3 *dbh, const char *zSql, sqlite3_stmt **ppStmt)
Prepare a SQL statement.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_SQ_query_param_auto_from_type(x)
Generate fixed-size query parameter with size determined by variable type.
PluginRemoveKey remove_key
Function to remove an item from the database.
char * key
TLS key.
sqlite3_stmt * delRow
Precompiled SQL for deletion.
const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
static unsigned int replication
PluginEstimateSize estimate_size
Calculate the current on-disk size of the SQ store.
static struct Experiment * e
int GNUNET_DISK_directory_create_for_file(const char *filename)
Create the directory structure for storing a file.
Definition: disk.c:681
#define GNUNET_SQ_result_spec_end
End of result parameter specification.
#define GNUNET_NO
Definition: gnunet_common.h:78
const char * GNUNET_h2s(const struct GNUNET_HashCode *hc)
Convert a hash value to a string (for printing debug messages).
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define RESULT_COLUMNS
#define GNUNET_SQ_result_spec_auto_from_type(dst)
We expect a fixed-size result, with size determined by the type of * dst
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define CHECK(a)
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
void(* PluginPutCont)(void *cls, const struct GNUNET_HashCode *key, uint32_t size, int status, const char *msg)
Put continuation.
static void sqlite_plugin_get_replication(void *cls, PluginDatumProcessor proc, void *proc_cls)
Get a random item for replication.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
void * libgnunet_plugin_datastore_sqlite_init(void *cls)
Entry point for the plugin.
struct GNUNET_SQ_ResultSpec GNUNET_SQ_result_spec_absolute_time(struct GNUNET_TIME_Absolute *at)
Absolute time expected.
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition: block.c:46
#define LOG_SQLITE_MSG(db, msg, level, cmd)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; on file &#39;file...
sqlite3_stmt * insertContent
Precompiled SQL for insertion.
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
sqlite3_stmt * get[8]
Precompiled SQL for selection.
static void sqlite_plugin_get_keys(void *cls, PluginKeyProcessor proc, void *proc_cls)
Get all of the keys in the datastore.
int GNUNET_SQ_extract_result(sqlite3_stmt *result, struct GNUNET_SQ_ResultSpec *rs)
Extract results from a query result according to the given specification.
Definition: sq.c:82
PluginGetRandom get_replication
Function to get a random item with high replication score from the database, lowering the item&#39;s repl...
static void database_shutdown(struct Plugin *plugin)
Shutdown database connection and associate data structures.
PluginDrop drop
Delete the database.
struct GNUNET_SQ_QueryParam GNUNET_SQ_query_param_uint32(const uint32_t *x)
Generate query parameter for an uint32_t in host byte order.
static struct GNUNET_ATS_SolverFunctions * plugin
Our solver.
void * cls
Closure for conv and cleaner.
void GNUNET_SQ_cleanup_result(struct GNUNET_SQ_ResultSpec *rs)
Free all memory that was allocated in rs during GNUNET_SQ_extract_result().
Definition: sq.c:117
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().
static void sqlite_plugin_drop(void *cls)
Drop database.
void GNUNET_log_config_missing(enum GNUNET_ErrorType kind, const char *section, const char *option)
Log error message about missing configuration option.
static char * value
Value of the record to add/remove.
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition: crypto_hash.c:44
void(* PluginKeyProcessor)(void *cls, const struct GNUNET_HashCode *key, unsigned int count)
An processor over a set of keys stored in the datastore.
int drop_on_shutdown
Should the database be dropped on shutdown?
PluginGetRandom get_expiration
Function to get a random expired item or, if none are expired, either the oldest entry or one with a ...
struct GNUNET_DATACACHE_PluginEnvironment * env
Our execution environment.
Each plugin is required to return a pointer to a struct of this type as the return value from its ent...
const char * GNUNET_STRINGS_relative_time_to_string(struct GNUNET_TIME_Relative delta, int do_round)
Give relative time in human-readable fancy format.
Definition: strings.c:686
sqlite3_stmt * selZeroAnon
Precompiled SQL for expiration selection.
#define MAX_ITEM_SIZE
We allocate items on the stack at times.
struct GNUNET_SQ_ResultSpec GNUNET_SQ_result_spec_variable_size(void **dst, size_t *sptr)
Variable-size result expected.
static int result
Global testing status.
struct GNUNET_SQ_QueryParam GNUNET_SQ_query_param_absolute_time(const struct GNUNET_TIME_Absolute *x)
Generate query parameter for an absolute time value.
The datastore service will pass a pointer to a struct of this type as the first and only argument to ...
A 512-bit hashcode.
sqlite3_stmt * selRepl
Precompiled SQL for replication selection.
#define GNUNET_DATASTORE_ENTRY_OVERHEAD
How many bytes of overhead will we assume per entry in any DB (for reservations)? ...
int GNUNET_SQ_bind(sqlite3_stmt *stmt, const struct GNUNET_SQ_QueryParam *params)
Execute binding operations for a prepared statement.
Definition: sq.c:37
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:118
uint64_t uid
UID to use.
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
Context for repl_proc() function.
sqlite3_stmt * remove
Precompiled SQL for remove_key.
static void sqlite_plugin_estimate_size(void *cls, unsigned long long *estimate)
Get an estimate of how much space the database is currently using.
helper functions for Sqlite3 DB interactions
void(* PluginRemoveCont)(void *cls, const struct GNUNET_HashCode *key, uint32_t size, int status, const char *msg)
Remove continuation.
#define LOG_SQLITE(db, level, cmd)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; on file &#39;file...
Description of a DB query parameter.
Definition: gnunet_sq_lib.h:54
struct GNUNET_SQ_ResultSpec GNUNET_SQ_result_spec_uint64(uint64_t *u64)
uint64_t expected.
#define ENULL
static void create_indices(sqlite3 *dbh)
Create our database indices.
void * cls
Closure to use for all of the following callbacks (except "next_request").
char * fn
Filename used for the DB.
static struct in_addr dummy
Target "dummy" address of the packet we pretend to respond to.
void GNUNET_SQ_reset(sqlite3 *dbh, sqlite3_stmt *stmt)
Reset stmt and log error.
Definition: sq.c:132
struct GNUNET_SQ_QueryParam GNUNET_SQ_query_param_uint64(const uint64_t *x)
Generate query parameter for an uint16_t in host byte order.
unsigned long long size
Size of all values we&#39;re storing.
configuration data
Definition: configuration.c:83
Handle for a plugin.
Definition: block.c:37
PGconn * dbh
Native Postgres database handle.
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...
PluginDatumProcessor proc
Function to call for the result (or the NULL).
static void sqlite_plugin_get_expiration(void *cls, PluginDatumProcessor proc, void *proc_cls)
Get a random item that has expired or has low priority.
#define GNUNET_log(kind,...)
int 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.
static int delete_by_rowid(struct Plugin *plugin, uint64_t rid)
Delete the database entry with the given row identifier.
sqlite3_stmt * maxRepl
Get maximum repl value in database.
sqlite3_stmt * selExpi
Precompiled SQL for expiration selection.
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?
Definition: time.c:331
void * cls
Closure to use for callbacks.
enum GNUNET_TESTBED_UnderlayLinkModelType type
the type of this model
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.
Time for absolute times used by GNUnet, in microseconds.
#define GNUNET_YES
Definition: gnunet_common.h:77
static unsigned int anonymity
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.
#define GNUNET_SQ_query_param_end
End of query parameter specification.
Definition: gnunet_sq_lib.h:85
const char * GNUNET_STRINGS_absolute_time_to_string(struct GNUNET_TIME_Absolute t)
Like asctime, except for GNUnet time.
Definition: strings.c:741
#define GNUNET_log_from(kind, comp,...)
PluginGetKey get_key
Get a particular datum matching a given hash from the datastore.
uint32_t data
The data value.
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.
void * libgnunet_plugin_datastore_sqlite_done(void *cls)
Exit point from the plugin.
No good quality of the operation is needed (i.e., random numbers can be pseudo-random).
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.
const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration to use.
#define GNUNET_free(ptr)
Wrapper around free.