GNUnet  0.20.0
plugin_datacache_sqlite.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2006, 2009, 2015, 2022 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 
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
29 #include "gnunet_sq_lib.h"
30 #include <sqlite3.h>
31 
32 #define LOG(kind, ...) GNUNET_log_from (kind, "datacache-sqlite", __VA_ARGS__)
33 
34 #define LOG_STRERROR_FILE(kind, op, fn) \
35  GNUNET_log_from_strerror_file (kind, "datacache-sqlite", op, fn)
36 
37 
42 #define OVERHEAD (sizeof(struct GNUNET_HashCode) + 36)
43 
47 struct Plugin
48 {
53 
57  sqlite3 *dbh;
58 
62  char *fn;
63 
67  sqlite3_stmt *insert_stmt;
68 
72  sqlite3_stmt *get_count_stmt;
73 
77  sqlite3_stmt *get_count_any_stmt;
78 
82  sqlite3_stmt *get_stmt;
83 
87  sqlite3_stmt *get_any_stmt;
88 
92  sqlite3_stmt *del_select_stmt;
93 
97  sqlite3_stmt *del_expired_stmt;
98 
102  sqlite3_stmt *del_stmt;
103 
107  sqlite3_stmt *get_closest_stmt;
108 
112  unsigned int num_items;
113 };
114 
115 
124 #define LOG_SQLITE(db, level, cmd) \
125  do \
126  { \
127  LOG (level, \
128  _ ("`%s' failed at %s:%d with error: %s\n"), \
129  cmd, \
130  __FILE__, \
131  __LINE__, \
132  sqlite3_errmsg (db)); \
133  } while (0)
134 
135 
142 #define SQLITE3_EXEC(db, cmd) \
143  do \
144  { \
145  emsg = NULL; \
146  if (SQLITE_OK != \
147  sqlite3_exec (db, cmd, NULL, NULL, &emsg)) \
148  { \
149  LOG (GNUNET_ERROR_TYPE_ERROR, \
150  _ ("`%s' failed at %s:%d with error: %s\n"), \
151  "sqlite3_exec", \
152  __FILE__, \
153  __LINE__, \
154  emsg); \
155  sqlite3_free (emsg); \
156  } \
157  } while (0)
158 
159 
168 static int
169 sq_prepare (sqlite3 *dbh,
170  const char *zSql, /* SQL statement, UTF-8 encoded */
171  sqlite3_stmt **ppStmt)
172 { /* OUT: Statement handle */
173  char *dummy;
174 
175  return sqlite3_prepare (dbh,
176  zSql,
177  strlen (zSql),
178  ppStmt,
179  (const char **) &dummy);
180 }
181 
182 
191 static ssize_t
193  uint32_t xor_distance,
194  const struct GNUNET_DATACACHE_Block *block)
195 {
196  struct Plugin *plugin = cls;
197  uint32_t type32 = (uint32_t) block->type;
198  uint32_t ro32 = (uint32_t) block->ro;
199  struct GNUNET_SQ_QueryParam params[] = {
204  GNUNET_SQ_query_param_uint32 (&xor_distance),
206  block->data_size),
208  block->put_path_length
209  * sizeof(struct GNUNET_DHT_PathElement)),
212  };
213 
215  "Processing PUT of %u bytes with key `%s' and expiration %s\n",
216  (unsigned int) block->data_size,
217  GNUNET_h2s (&block->key),
220  block->expiration_time),
221  GNUNET_YES));
222  if (GNUNET_OK !=
223  GNUNET_SQ_bind (plugin->insert_stmt,
224  params))
225  {
226  LOG_SQLITE (plugin->dbh,
228  "sqlite3_bind_xxx");
229  GNUNET_SQ_reset (plugin->dbh,
230  plugin->insert_stmt);
231  return -1;
232  }
233  if (SQLITE_DONE !=
234  sqlite3_step (plugin->insert_stmt))
235  {
236  LOG_SQLITE (plugin->dbh,
238  "sqlite3_step");
239  GNUNET_SQ_reset (plugin->dbh,
240  plugin->insert_stmt);
241  return -1;
242  }
243  plugin->num_items++;
244  GNUNET_SQ_reset (plugin->dbh,
245  plugin->insert_stmt);
246  return block->data_size + OVERHEAD;
247 }
248 
249 
260 static unsigned int
261 get_any (void *cls,
262  const struct GNUNET_HashCode *key,
264  void *iter_cls)
265 {
266  struct Plugin *plugin = cls;
267  struct GNUNET_TIME_Absolute now;
268  unsigned int cnt;
269  uint32_t off;
270  uint32_t btype32;
271  uint32_t bro32;
272  unsigned int total;
273  struct GNUNET_DATACACHE_Block block;
274  void *path;
275  void *data;
276  size_t path_size;
277  struct GNUNET_SQ_QueryParam params_count[] = {
281  };
282  struct GNUNET_SQ_QueryParam params_select[] = {
287  };
288  struct GNUNET_SQ_ResultSpec rs[] = {
290  &block.data_size),
293  &path_size),
295  GNUNET_SQ_result_spec_uint32 (&btype32),
298  };
299 
300  now = GNUNET_TIME_absolute_get ();
302  "Processing GET for key `%s'\n",
303  GNUNET_h2s (key));
304 
305  if (GNUNET_OK !=
306  GNUNET_SQ_bind (plugin->get_count_any_stmt,
307  params_count))
308  {
309  LOG_SQLITE (plugin->dbh,
311  "sqlite3_bind_xxx");
312  GNUNET_SQ_reset (plugin->dbh,
313  plugin->get_count_any_stmt);
314  return 0;
315  }
316  if (SQLITE_ROW !=
317  sqlite3_step (plugin->get_count_any_stmt))
318  {
319  LOG_SQLITE (plugin->dbh,
321  "sqlite_step");
322  GNUNET_SQ_reset (plugin->dbh,
323  plugin->get_count_any_stmt);
325  "No content found when processing GET for key `%s'\n",
326  GNUNET_h2s (key));
327  return 0;
328  }
329  total = sqlite3_column_int (plugin->get_count_any_stmt,
330  0);
331  GNUNET_SQ_reset (plugin->dbh,
332  plugin->get_count_any_stmt);
333  if ( (0 == total) ||
334  (NULL == iter) )
335  {
336  if (0 == total)
338  "No content found when processing GET for key `%s'\n",
339  GNUNET_h2s (key));
340  return total;
341  }
342 
343  cnt = 0;
344  block.key = *key;
346  total);
347  while (cnt < total)
348  {
349  off = (off + 1) % total;
350  if (GNUNET_OK !=
351  GNUNET_SQ_bind (plugin->get_any_stmt,
352  params_select))
353  {
354  LOG_SQLITE (plugin->dbh,
356  "sqlite3_bind_xxx");
357  GNUNET_SQ_reset (plugin->dbh,
358  plugin->get_any_stmt);
359  return cnt;
360  }
361  if (SQLITE_ROW !=
362  sqlite3_step (plugin->get_any_stmt))
363  break;
364  if (GNUNET_OK !=
365  GNUNET_SQ_extract_result (plugin->get_any_stmt,
366  rs))
367  {
368  GNUNET_break (0);
369  GNUNET_SQ_reset (plugin->dbh,
370  plugin->get_any_stmt);
371  break;
372  }
373  if (0 != path_size % sizeof(struct GNUNET_DHT_PathElement))
374  {
375  GNUNET_break (0);
376  path_size = 0;
377  path = NULL;
378  }
379  block.data = data;
380  block.put_path = path;
381  block.put_path_length = path_size / sizeof(struct GNUNET_DHT_PathElement);
382  block.type = (enum GNUNET_BLOCK_Type) btype32;
383  block.ro = (enum GNUNET_DHT_RouteOption) bro32;
384  cnt++;
386  "Found %u-byte result when processing GET for key `%s'\n",
387  (unsigned int) block.data_size,
388  GNUNET_h2s (&block.key));
389  if (GNUNET_OK !=
390  iter (iter_cls,
391  &block))
392  {
394  GNUNET_SQ_reset (plugin->dbh,
395  plugin->get_any_stmt);
396  break;
397  }
399  GNUNET_SQ_reset (plugin->dbh,
400  plugin->get_any_stmt);
401  }
402  GNUNET_SQ_reset (plugin->dbh,
403  plugin->get_any_stmt);
404  return cnt;
405 }
406 
407 
419 static unsigned int
420 get_typed (void *cls,
421  const struct GNUNET_HashCode *key,
422  enum GNUNET_BLOCK_Type type,
424  void *iter_cls)
425 {
426  struct Plugin *plugin = cls;
427  uint32_t type32 = type;
428  struct GNUNET_TIME_Absolute now;
429  unsigned int cnt;
430  uint32_t off;
431  uint32_t bro32;
432  unsigned int total;
433  struct GNUNET_DATACACHE_Block block;
434  void *path;
435  void *data;
436  size_t path_size;
437  struct GNUNET_SQ_QueryParam params_count[] = {
442  };
443  struct GNUNET_SQ_QueryParam params_select[] = {
449  };
450  struct GNUNET_SQ_ResultSpec rs[] = {
452  &block.data_size),
455  &path_size),
459  };
460 
461  now = GNUNET_TIME_absolute_get ();
463  "Processing GET for key `%s'\n",
464  GNUNET_h2s (key));
465 
466  if (GNUNET_OK !=
467  GNUNET_SQ_bind (plugin->get_count_stmt,
468  params_count))
469  {
470  LOG_SQLITE (plugin->dbh,
472  "sqlite3_bind_xxx");
473  GNUNET_SQ_reset (plugin->dbh,
474  plugin->get_count_stmt);
475  return 0;
476  }
477  if (SQLITE_ROW !=
478  sqlite3_step (plugin->get_count_stmt))
479  {
480  LOG_SQLITE (plugin->dbh,
482  "sqlite_step");
483  GNUNET_SQ_reset (plugin->dbh,
484  plugin->get_count_stmt);
486  "No content found when processing GET for key `%s'\n",
487  GNUNET_h2s (key));
488  return 0;
489  }
490  total = sqlite3_column_int (plugin->get_count_stmt,
491  0);
492  GNUNET_SQ_reset (plugin->dbh,
493  plugin->get_count_stmt);
494  if ( (0 == total) ||
495  (NULL == iter) )
496  {
497  if (0 == total)
499  "No content found when processing GET for key `%s'\n",
500  GNUNET_h2s (key));
501  return total;
502  }
503 
504  cnt = 0;
505  block.key = *key;
507  total);
508  while (cnt < total)
509  {
510  off = (off + 1) % total;
511  if (GNUNET_OK !=
512  GNUNET_SQ_bind (plugin->get_stmt,
513  params_select))
514  {
515  LOG_SQLITE (plugin->dbh,
517  "sqlite3_bind_xxx");
518  GNUNET_SQ_reset (plugin->dbh,
519  plugin->get_stmt);
520  return cnt;
521  }
522  if (SQLITE_ROW !=
523  sqlite3_step (plugin->get_stmt))
524  break;
525  if (GNUNET_OK !=
526  GNUNET_SQ_extract_result (plugin->get_stmt,
527  rs))
528  {
529  GNUNET_break (0);
530  GNUNET_SQ_reset (plugin->dbh,
531  plugin->get_stmt);
532  break;
533  }
534  if (0 != path_size % sizeof(struct GNUNET_DHT_PathElement))
535  {
536  GNUNET_break (0);
537  path_size = 0;
538  path = NULL;
539  }
540  block.data = data;
541  block.put_path = path;
542  block.put_path_length = path_size / sizeof(struct GNUNET_DHT_PathElement);
543  block.type = type;
544  block.ro = (enum GNUNET_DHT_RouteOption) bro32;
545  cnt++;
547  "Found %u-byte result when processing GET for key `%s'\n",
548  (unsigned int) block.data_size,
549  GNUNET_h2s (&block.key));
550  if ( (NULL != iter) &&
551  (GNUNET_OK !=
552  iter (iter_cls,
553  &block)) )
554  {
556  GNUNET_SQ_reset (plugin->dbh,
557  plugin->get_stmt);
558  break;
559  }
561  GNUNET_SQ_reset (plugin->dbh,
562  plugin->get_stmt);
563  }
564  GNUNET_SQ_reset (plugin->dbh,
565  plugin->get_stmt);
566  return cnt;
567 }
568 
569 
581 static unsigned int
582 sqlite_plugin_get (void *cls,
583  const struct GNUNET_HashCode *key,
584  enum GNUNET_BLOCK_Type type,
586  void *iter_cls)
587 {
589  return get_any (cls,
590  key,
591  iter,
592  iter_cls);
593  return get_typed (cls,
594  key,
595  type,
596  iter,
597  iter_cls);
598 }
599 
600 
608 static enum GNUNET_GenericReturnValue
609 sqlite_plugin_del (void *cls)
610 {
611  struct Plugin *plugin = cls;
612  uint64_t rowid;
613  void *data;
614  size_t data_size;
615  struct GNUNET_HashCode hc;
616  struct GNUNET_TIME_Absolute now;
617  struct GNUNET_SQ_ResultSpec rs[] = {
621  &data_size),
623  };
624  struct GNUNET_SQ_QueryParam params[] = {
627  };
628  struct GNUNET_SQ_QueryParam time_params[] = {
631  };
632 
634  "Processing DEL\n");
635  now = GNUNET_TIME_absolute_get ();
636  if (GNUNET_OK !=
637  GNUNET_SQ_bind (plugin->del_expired_stmt,
638  time_params))
639  {
640  LOG_SQLITE (plugin->dbh,
642  "sqlite3_bind");
643  GNUNET_SQ_reset (plugin->dbh,
644  plugin->del_expired_stmt);
645  return GNUNET_SYSERR;
646  }
647  if ( (SQLITE_ROW !=
648  sqlite3_step (plugin->del_expired_stmt)) ||
649  (GNUNET_OK !=
650  GNUNET_SQ_extract_result (plugin->del_expired_stmt,
651  rs)))
652  {
653  GNUNET_SQ_reset (plugin->dbh,
654  plugin->del_expired_stmt);
655  if (SQLITE_ROW !=
656  sqlite3_step (plugin->del_select_stmt))
657  {
658  LOG_SQLITE (plugin->dbh,
660  "sqlite3_step");
661  GNUNET_SQ_reset (plugin->dbh,
662  plugin->del_select_stmt);
663  return GNUNET_SYSERR;
664  }
665  if (GNUNET_OK !=
666  GNUNET_SQ_extract_result (plugin->del_select_stmt,
667  rs))
668  {
669  GNUNET_SQ_reset (plugin->dbh,
670  plugin->del_select_stmt);
671  GNUNET_break (0);
672  return GNUNET_SYSERR;
673  }
674  }
676  GNUNET_SQ_reset (plugin->dbh,
677  plugin->del_select_stmt);
678  if (GNUNET_OK !=
679  GNUNET_SQ_bind (plugin->del_stmt,
680  params))
681  {
682  LOG_SQLITE (plugin->dbh,
684  "sqlite3_bind");
685  GNUNET_SQ_reset (plugin->dbh,
686  plugin->del_stmt);
687  return GNUNET_SYSERR;
688  }
689  if (SQLITE_DONE !=
690  sqlite3_step (plugin->del_stmt))
691  {
692  LOG_SQLITE (plugin->dbh,
694  "sqlite3_step");
695  GNUNET_SQ_reset (plugin->dbh,
696  plugin->del_stmt);
697  return GNUNET_SYSERR;
698  }
699  plugin->num_items--;
700  plugin->env->delete_notify (plugin->env->cls,
701  &hc,
702  data_size + OVERHEAD);
703  GNUNET_SQ_reset (plugin->dbh,
704  plugin->del_stmt);
705  return GNUNET_OK;
706 }
707 
708 
723 static unsigned int
725  const struct GNUNET_HashCode *key,
726  enum GNUNET_BLOCK_Type type,
727  unsigned int num_results,
729  void *iter_cls)
730 {
731  struct Plugin *plugin = cls;
732  uint32_t type32 = type;
733  uint32_t num_results32 = num_results;
734  struct GNUNET_TIME_Absolute now;
735  void *data;
736  void *path;
737  size_t path_size;
738  unsigned int cnt;
739  uint32_t bro32;
740  struct GNUNET_DATACACHE_Block block;
741  uint32_t rtype32;
742  struct GNUNET_SQ_QueryParam params[] = {
746  GNUNET_SQ_query_param_uint32 (&num_results32),
748  };
749  struct GNUNET_SQ_ResultSpec rs[] = {
751  &block.data_size),
754  &path_size),
756  GNUNET_SQ_result_spec_uint32 (&rtype32),
760  };
761 
762  now = GNUNET_TIME_absolute_get ();
764  "Processing GET_CLOSEST for key `%s'\n",
765  GNUNET_h2s (key));
766  if (GNUNET_OK !=
767  GNUNET_SQ_bind (plugin->get_closest_stmt,
768  params))
769  {
770  LOG_SQLITE (plugin->dbh,
772  "sqlite3_bind_xxx");
773  GNUNET_SQ_reset (plugin->dbh,
774  plugin->get_closest_stmt);
775  return 0;
776  }
777  cnt = 0;
778  while (SQLITE_ROW ==
779  sqlite3_step (plugin->get_closest_stmt))
780  {
781  if (GNUNET_OK !=
782  GNUNET_SQ_extract_result (plugin->get_closest_stmt,
783  rs))
784  {
785  GNUNET_break (0);
786  break;
787  }
788  if (0 != path_size % sizeof(struct GNUNET_DHT_PathElement))
789  {
790  GNUNET_break (0);
791  path_size = 0;
792  path = NULL;
793  }
794  block.put_path_length
795  = path_size / sizeof(struct GNUNET_DHT_PathElement);
796  block.put_path = path;
797  block.data = data;
798  block.type = (enum GNUNET_BLOCK_Type) rtype32;
799  block.ro = (enum GNUNET_DHT_RouteOption) bro32;
800  cnt++;
802  "Found %u-byte result at %s when processing GET_CLOSE\n",
803  (unsigned int) block.data_size,
804  GNUNET_h2s (&block.key));
805 
806  if (GNUNET_OK !=
807  iter (iter_cls,
808  &block))
809  {
811  break;
812  }
814  }
815  GNUNET_SQ_reset (plugin->dbh,
816  plugin->get_closest_stmt);
817  return cnt;
818 }
819 
820 
827 void *
829 {
832  struct Plugin *plugin;
833  char *fn;
834  char *fn_utf8;
835  sqlite3 *dbh;
836  char *emsg;
837 
838  if (GNUNET_YES ==
840  "datacache-sqlite",
841  "IN_MEMORY"))
842  {
843  if (SQLITE_OK !=
844  sqlite3_open (":memory:",
845  &dbh))
846  return NULL;
847  fn_utf8 = NULL;
848  }
849  else
850  {
851  fn = GNUNET_DISK_mktemp ("gnunet-datacache");
852  if (NULL == fn)
853  {
854  GNUNET_break (0);
855  return NULL;
856  }
857  /* fn should be UTF-8-encoded. If it isn't, it's a bug. */
858  fn_utf8 = GNUNET_strdup (fn);
859  if (SQLITE_OK !=
860  sqlite3_open (fn_utf8,
861  &dbh))
862  {
863  GNUNET_free (fn);
864  GNUNET_free (fn_utf8);
865  return NULL;
866  }
867  GNUNET_free (fn);
868  }
869 
870  SQLITE3_EXEC (dbh, "PRAGMA temp_store=MEMORY");
871  SQLITE3_EXEC (dbh, "PRAGMA locking_mode=EXCLUSIVE");
872  SQLITE3_EXEC (dbh, "PRAGMA journal_mode=OFF");
873  SQLITE3_EXEC (dbh, "PRAGMA synchronous=OFF");
874  SQLITE3_EXEC (dbh, "PRAGMA page_size=4092");
875  if (GNUNET_YES ==
877  "datacache-sqlite",
878  "IN_MEMORY"))
879  SQLITE3_EXEC (dbh, "PRAGMA sqlite_temp_store=3");
880 
881  SQLITE3_EXEC (dbh,
882  "CREATE TABLE ds180 ("
883  " type INTEGER NOT NULL DEFAULT 0,"
884  " ro INTEGER NOT NULL DEFAULT 0,"
885  " expire INTEGER NOT NULL,"
886  " key BLOB NOT NULL DEFAULT '',"
887  " prox INTEGER NOT NULL,"
888  " value BLOB NOT NULL,"
889  " trunc BLOB NOT NULL,"
890  " path BLOB DEFAULT '')");
891  SQLITE3_EXEC (dbh,
892  "CREATE INDEX idx_hashidx"
893  " ON ds180 (key,type,expire)");
894  SQLITE3_EXEC (dbh,
895  "CREATE INDEX idx_prox_expire"
896  " ON ds180 (prox,expire)");
897  SQLITE3_EXEC (dbh,
898  "CREATE INDEX idx_expire_only"
899  " ON ds180 (expire)");
900  plugin = GNUNET_new (struct Plugin);
901  plugin->env = env;
902  plugin->dbh = dbh;
903  plugin->fn = fn_utf8;
904 
905  if ((SQLITE_OK !=
906  sq_prepare (plugin->dbh,
907  "INSERT INTO ds180"
908  " (type, ro, expire, key, prox, value, path, trunc)"
909  " VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
910  &plugin->insert_stmt)) ||
911  (SQLITE_OK !=
912  sq_prepare (plugin->dbh,
913  "SELECT COUNT(*) FROM ds180 "
914  "WHERE key=?"
915  " AND type=?"
916  " AND expire >= ?",
917  &plugin->get_count_stmt)) ||
918  (SQLITE_OK !=
919  sq_prepare (plugin->dbh,
920  "SELECT COUNT(*) FROM ds180 "
921  "WHERE key=? AND expire >= ?",
922  &plugin->get_count_any_stmt)) ||
923  (SQLITE_OK !=
924  sq_prepare (plugin->dbh,
925  "SELECT value,expire,path,trunc,ro"
926  " FROM ds180"
927  " WHERE key=?"
928  " AND type=?"
929  " AND expire >= ?"
930  " LIMIT 1 OFFSET ?",
931  &plugin->get_stmt)) ||
932  (SQLITE_OK !=
933  sq_prepare (plugin->dbh,
934  "SELECT value,expire,path,trunc,type,ro"
935  " FROM ds180"
936  " WHERE key=?"
937  " AND expire >= ?"
938  " LIMIT 1 OFFSET ?",
939  &plugin->get_any_stmt)) ||
940  (SQLITE_OK !=
941  sq_prepare (plugin->dbh,
942  "SELECT _ROWID_,key,value FROM ds180"
943  " WHERE expire < ?1"
944  " ORDER BY expire ASC LIMIT 1",
945  &plugin->del_expired_stmt)) ||
946  (SQLITE_OK !=
947  sq_prepare (plugin->dbh,
948  "SELECT _ROWID_,key,value FROM ds180"
949  " ORDER BY prox ASC, expire ASC LIMIT 1",
950  &plugin->del_select_stmt)) ||
951  (SQLITE_OK !=
952  sq_prepare (plugin->dbh,
953  "DELETE FROM ds180 WHERE _ROWID_=?",
954  &plugin->del_stmt)) ||
955  (SQLITE_OK !=
956  sq_prepare (plugin->dbh,
957  "SELECT * FROM ("
958  " SELECT value,expire,path,trunc,type,ro,key"
959  " FROM ds180 "
960  " WHERE key>=?1 "
961  " AND expire >= ?2"
962  " AND ( (type=?3) or (0 == ?3) )"
963  " ORDER BY KEY ASC LIMIT ?4)"
964  "UNION "
965  "SELECT * FROM ("
966  " SELECT value,expire,path,trunc,type,ro,key"
967  " FROM ds180 "
968  " WHERE key<=?1 "
969  " AND expire >= ?2"
970  " AND ( (type=?3) or (0 == ?3) )"
971  " ORDER BY KEY DESC LIMIT ?4)",
972  &plugin->get_closest_stmt)))
973  {
974  LOG_SQLITE (plugin->dbh,
976  "sq_prepare");
977  GNUNET_break (SQLITE_OK ==
978  sqlite3_close (plugin->dbh));
980  return NULL;
981  }
982 
984  api->cls = plugin;
985  api->get = &sqlite_plugin_get;
986  api->put = &sqlite_plugin_put;
987  api->del = &sqlite_plugin_del;
988  api->get_closest = &sqlite_plugin_get_closest;
990  "Sqlite datacache running\n");
991  return api;
992 }
993 
994 
1001 void *
1003 {
1004  struct GNUNET_DATACACHE_PluginFunctions *api = cls;
1005  struct Plugin *plugin = api->cls;
1006  int result;
1007 
1008 #if SQLITE_VERSION_NUMBER >= 3007000
1009  sqlite3_stmt *stmt;
1010 #endif
1011 
1012 #if ! WINDOWS || defined(__CYGWIN__)
1013  if ( (NULL != plugin->fn) &&
1014  (0 != unlink (plugin->fn)) )
1016  "unlink",
1017  plugin->fn);
1018  GNUNET_free (plugin->fn);
1019 #endif
1020  sqlite3_finalize (plugin->insert_stmt);
1021  sqlite3_finalize (plugin->get_count_stmt);
1022  sqlite3_finalize (plugin->get_count_any_stmt);
1023  sqlite3_finalize (plugin->get_stmt);
1024  sqlite3_finalize (plugin->get_any_stmt);
1025  sqlite3_finalize (plugin->del_select_stmt);
1026  sqlite3_finalize (plugin->del_expired_stmt);
1027  sqlite3_finalize (plugin->del_stmt);
1028  sqlite3_finalize (plugin->get_closest_stmt);
1029  result = sqlite3_close (plugin->dbh);
1030 #if SQLITE_VERSION_NUMBER >= 3007000
1031  if (SQLITE_BUSY == result)
1032  {
1034  _ (
1035  "Tried to close sqlite without finalizing all prepared statements.\n"));
1036  stmt = sqlite3_next_stmt (plugin->dbh,
1037  NULL);
1038  while (NULL != stmt)
1039  {
1040  result = sqlite3_finalize (stmt);
1041  if (result != SQLITE_OK)
1043  "Failed to close statement %p: %d\n",
1044  stmt,
1045  result);
1046  stmt = sqlite3_next_stmt (plugin->dbh,
1047  NULL);
1048  }
1049  result = sqlite3_close (plugin->dbh);
1050  }
1051 #endif
1052  if (SQLITE_OK != result)
1053  LOG_SQLITE (plugin->dbh,
1055  "sqlite3_close");
1056 
1057  GNUNET_free (plugin);
1058  GNUNET_free (api);
1059  return NULL;
1060 }
1061 
1062 
1063 /* end of plugin_datacache_sqlite.c */
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
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.
static size_t data_size
Number of bytes in data.
Definition: gnunet-abd.c:187
struct TestcasePlugin * plugin
The process handle to the testbed service.
struct GNUNET_HashCode key
The key used in the DHT.
static struct in_addr dummy
Target "dummy" address of the packet we pretend to respond to.
uint32_t data
The data value.
static int result
Global testing status.
API for database backends for the datacache.
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.
Definition: sq.c:76
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:105
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.
Definition: sq.c:31
void GNUNET_SQ_reset(sqlite3 *dbh, sqlite3_stmt *stmt)
Reset stmt and log error.
Definition: sq.c:120
#define GNUNET_SQ_query_param_end
End of query parameter specification.
Definition: gnunet_sq_lib.h:87
#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_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
uint32_t GNUNET_CRYPTO_random_u32(enum GNUNET_CRYPTO_Quality mode, uint32_t i)
Produce a random value.
@ GNUNET_CRYPTO_QUALITY_WEAK
No good quality of the operation is needed (i.e., random numbers can be pseudo-random).
enum GNUNET_GenericReturnValue(* GNUNET_DATACACHE_Iterator)(void *cls, const struct GNUNET_DATACACHE_Block *block)
An iterator over a set of items stored in the datacache.
GNUNET_DHT_RouteOption
Options for routing.
char * GNUNET_DISK_mktemp(const char *t)
Create an (empty) temporary file on disk.
Definition: disk.c:380
GNUNET_GenericReturnValue
Named constants for return values.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_SYSERR
#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).
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_BULK
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#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?
Definition: time.c:405
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:111
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:569
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
static ssize_t sqlite_plugin_put(void *cls, uint32_t xor_distance, const struct GNUNET_DATACACHE_Block *block)
Store an item in the datastore.
#define OVERHEAD
How much overhead do we assume per entry in the datacache?
#define SQLITE3_EXEC(db, cmd)
Execute SQL statement.
void * libgnunet_plugin_datacache_sqlite_done(void *cls)
Exit point from the plugin.
#define LOG_SQLITE(db, level, cmd)
Log an error message at log-level level that indicates a failure of the command cmd with the error fr...
static unsigned int sqlite_plugin_get(void *cls, const struct GNUNET_HashCode *key, enum GNUNET_BLOCK_Type type, GNUNET_DATACACHE_Iterator iter, void *iter_cls)
Iterate over the results for a particular key in the datastore.
static int sq_prepare(sqlite3 *dbh, const char *zSql, sqlite3_stmt **ppStmt)
Prepare a SQL statement.
static enum GNUNET_GenericReturnValue sqlite_plugin_del(void *cls)
Delete the entry with the lowest expiration value from the datacache right now.
static unsigned int get_any(void *cls, const struct GNUNET_HashCode *key, GNUNET_DATACACHE_Iterator iter, void *iter_cls)
Iterate over the results for a particular key in the datastore.
#define LOG_STRERROR_FILE(kind, op, fn)
static unsigned int get_typed(void *cls, const struct GNUNET_HashCode *key, enum GNUNET_BLOCK_Type type, GNUNET_DATACACHE_Iterator iter, void *iter_cls)
Iterate over the results for a particular key in the datastore.
#define LOG(kind,...)
void * libgnunet_plugin_datacache_sqlite_init(void *cls)
Entry point for the plugin.
static unsigned int sqlite_plugin_get_closest(void *cls, const struct GNUNET_HashCode *key, enum GNUNET_BLOCK_Type type, unsigned int num_results, GNUNET_DATACACHE_Iterator iter, void *iter_cls)
Iterate over the results that are "close" to a particular key in the datacache.
void * cls
Closure for all of the callbacks.
Information about a block stored in the datacache.
const struct GNUNET_DHT_PathElement * put_path
PUT path taken by the block, array of peer identities.
enum GNUNET_BLOCK_Type type
Type of the block.
const void * data
Actual block data.
enum GNUNET_DHT_RouteOption ro
Options for routing for the block.
struct GNUNET_PeerIdentity trunc_peer
If the path was truncated, this is the peer ID at which the path was truncated.
struct GNUNET_HashCode key
Key of the block.
size_t data_size
Number of bytes in data.
unsigned int put_path_length
Length of the put_path array.
struct GNUNET_TIME_Absolute expiration_time
When does the block expire?
The datastore service will pass a pointer to a struct of this type as the first and only argument to ...
void * cls
Closure to use for callbacks.
struct returned by the initialization function of the plugin
void * cls
Closure to pass to all plugin functions.
A (signed) path tracking a block's flow through the DHT is represented by an array of path elements,...
A 512-bit hashcode.
Description of a DB query parameter.
Definition: gnunet_sq_lib.h:56
Description of a DB result cell.
Time for absolute times used by GNUnet, in microseconds.
Handle for a plugin.
Definition: block.c:38
sqlite3 * dbh
Handle to the sqlite database.
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition: block.c:47
sqlite3_stmt * get_any_stmt
Prepared statement for sqlite_plugin_get.
unsigned int num_items
Number of key-value pairs in the database.
sqlite3_stmt * get_stmt
Prepared statement for sqlite_plugin_get.
sqlite3_stmt * insert_stmt
Prepared statement for sqlite_plugin_put.
sqlite3_stmt * del_select_stmt
Prepared statement for sqlite_plugin_del.
sqlite3_stmt * get_count_stmt
Prepared statement for sqlite_plugin_get.
sqlite3_stmt * del_expired_stmt
Prepared statement for sqlite_plugin_del.
char * fn
Filename used for the DB.
sqlite3_stmt * get_closest_stmt
Prepared statement for sqlite_plugin_get_closest.
sqlite3_stmt * del_stmt
Prepared statement for sqlite_plugin_del.
struct GNUNET_DATACACHE_PluginEnvironment * env
Our execution environment.
sqlite3_stmt * get_count_any_stmt
Prepared statement for sqlite_plugin_get.
struct GNUNET_PQ_Context * dbh
Native Postgres database handle.
enum GNUNET_TESTBED_UnderlayLinkModelType type
the type of this model