GNUnet 0.25.2-11-g84e94e98c
 
Loading...
Searching...
No Matches
plugin_datacache_sqlite.c File Reference

sqlite for an implementation of a database backend for the datacache More...

#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_datacache_plugin.h"
#include "gnunet_sq_lib.h"
#include <sqlite3.h>
Include dependency graph for plugin_datacache_sqlite.c:

Go to the source code of this file.

Data Structures

struct  Plugin
 Handle for a plugin. More...
 

Macros

#define LOG(kind, ...)   GNUNET_log_from (kind, "datacache-sqlite", __VA_ARGS__)
 
#define LOG_STRERROR_FILE(kind, op, fn)    GNUNET_log_from_strerror_file (kind, "datacache-sqlite", op, fn)
 
#define OVERHEAD   (sizeof(struct GNUNET_HashCode) + 36)
 How much overhead do we assume per entry in the datacache?
 
#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 from the database db.
 
#define SQLITE3_EXEC(db, cmd)
 Execute SQL statement.
 

Functions

static int sq_prepare (sqlite3 *dbh, const char *zSql, sqlite3_stmt **ppStmt)
 Prepare a SQL statement.
 
static ssize_t sqlite_plugin_put (void *cls, uint32_t xor_distance, const struct GNUNET_DATACACHE_Block *block)
 Store an item in the datastore.
 
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.
 
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.
 
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 enum GNUNET_GenericReturnValue sqlite_plugin_del (void *cls)
 Delete the entry with the lowest expiration value from the datacache right now.
 
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 * libgnunet_plugin_datacache_sqlite_init (void *cls)
 Entry point for the plugin.
 
void * libgnunet_plugin_datacache_sqlite_done (void *cls)
 Exit point from the plugin.
 

Detailed Description

sqlite for an implementation of a database backend for the datacache

Author
Christian Grothoff

Definition in file plugin_datacache_sqlite.c.

Macro Definition Documentation

◆ LOG

#define LOG (   kind,
  ... 
)    GNUNET_log_from (kind, "datacache-sqlite", __VA_ARGS__)

Definition at line 32 of file plugin_datacache_sqlite.c.

◆ LOG_STRERROR_FILE

#define LOG_STRERROR_FILE (   kind,
  op,
  fn 
)     GNUNET_log_from_strerror_file (kind, "datacache-sqlite", op, fn)

Definition at line 34 of file plugin_datacache_sqlite.c.

47{
52
56 sqlite3 *dbh;
57
61 char *fn;
62
66 sqlite3_stmt *insert_stmt;
67
71 sqlite3_stmt *get_count_stmt;
72
76 sqlite3_stmt *get_count_any_stmt;
77
81 sqlite3_stmt *get_stmt;
82
86 sqlite3_stmt *get_any_stmt;
87
91 sqlite3_stmt *del_select_stmt;
92
96 sqlite3_stmt *del_expired_stmt;
97
101 sqlite3_stmt *del_stmt;
102
106 sqlite3_stmt *get_closest_stmt;
107
111 unsigned int num_items;
112};
113
114
123#define LOG_SQLITE(db, level, cmd) \
124 do \
125 { \
126 LOG (level, \
127 _ ("`%s' failed at %s:%d with error: %s\n"), \
128 cmd, \
129 __FILE__, \
130 __LINE__, \
131 sqlite3_errmsg (db)); \
132 } while (0)
133
134
141#define SQLITE3_EXEC(db, cmd) \
142 do \
143 { \
144 emsg = NULL; \
145 if (SQLITE_OK != \
146 sqlite3_exec (db, cmd, NULL, NULL, &emsg)) \
147 { \
148 LOG (GNUNET_ERROR_TYPE_ERROR, \
149 _ ("`%s' failed at %s:%d with error: %s\n"), \
150 "sqlite3_exec", \
151 __FILE__, \
152 __LINE__, \
153 emsg); \
154 sqlite3_free (emsg); \
155 } \
156 } while (0)
157
158
167static int
168sq_prepare (sqlite3 *dbh,
169 const char *zSql, /* SQL statement, UTF-8 encoded */
170 sqlite3_stmt **ppStmt)
171{ /* OUT: Statement handle */
172 char *dummy;
173
174 return sqlite3_prepare (dbh,
175 zSql,
176 strlen (zSql),
177 ppStmt,
178 (const char **) &dummy);
179}
180
181
190static ssize_t
192 uint32_t xor_distance,
193 const struct GNUNET_DATACACHE_Block *block)
194{
195 struct Plugin *plugin = cls;
196 uint32_t type32 = (uint32_t) block->type;
197 uint32_t ro32 = (uint32_t) block->ro;
198 struct GNUNET_SQ_QueryParam params[] = {
201 GNUNET_SQ_query_param_absolute_time (&block->expiration_time),
203 GNUNET_SQ_query_param_uint32 (&xor_distance),
205 block->data_size),
206 GNUNET_SQ_query_param_fixed_size (block->put_path,
207 block->put_path_length
208 * sizeof(struct GNUNET_DHT_PathElement)),
209 GNUNET_SQ_query_param_auto_from_type (&block->trunc_peer),
211 };
212
214 "Processing PUT of %u bytes with key `%s' and expiration %s\n",
215 (unsigned int) block->data_size,
216 GNUNET_h2s (&block->key),
219 block->expiration_time),
220 GNUNET_YES));
221 if (GNUNET_OK !=
222 GNUNET_SQ_bind (plugin->insert_stmt,
223 params))
224 {
225 LOG_SQLITE (plugin->dbh,
227 "sqlite3_bind_xxx");
229 plugin->insert_stmt);
230 return -1;
231 }
232 if (SQLITE_DONE !=
233 sqlite3_step (plugin->insert_stmt))
234 {
235 LOG_SQLITE (plugin->dbh,
237 "sqlite3_step");
239 plugin->insert_stmt);
240 return -1;
241 }
242 plugin->num_items++;
244 plugin->insert_stmt);
245 return block->data_size + OVERHEAD;
246}
247
248
259static unsigned int
260get_any (void *cls,
261 const struct GNUNET_HashCode *key,
263 void *iter_cls)
264{
265 struct Plugin *plugin = cls;
266 struct GNUNET_TIME_Absolute now;
267 unsigned int cnt;
268 uint32_t off;
269 uint32_t btype32;
270 uint32_t bro32;
271 unsigned int total;
272 struct GNUNET_DATACACHE_Block block;
273 void *path;
274 void *data;
275 size_t path_size;
276
278 {
279 struct GNUNET_SQ_QueryParam params_count[] = {
283 };
285 "Processing GET for key `%s'\n",
286 GNUNET_h2s (key));
287
288 if (GNUNET_OK !=
289 GNUNET_SQ_bind (plugin->get_count_any_stmt,
290 params_count))
291 {
292 LOG_SQLITE (plugin->dbh,
294 "sqlite3_bind_xxx");
296 plugin->get_count_any_stmt);
297 return 0;
298 }
299 if (SQLITE_ROW !=
300 sqlite3_step (plugin->get_count_any_stmt))
301 {
302 LOG_SQLITE (plugin->dbh,
304 "sqlite_step");
306 plugin->get_count_any_stmt);
308 "No content found when processing GET for key `%s'\n",
309 GNUNET_h2s (key));
310 return 0;
311 }
312 total = sqlite3_column_int (plugin->get_count_any_stmt,
313 0);
315 plugin->get_count_any_stmt);
316 if ( (0 == total) ||
317 (NULL == iter) )
318 {
319 if (0 == total)
321 "No content found when processing GET for key `%s'\n",
322 GNUNET_h2s (key));
323 return total;
324 }
325 }
326 cnt = 0;
327 block.key = *key;
329 total);
330 {
331 struct GNUNET_SQ_QueryParam params_select[] = {
336 };
337 struct GNUNET_SQ_ResultSpec rs[] = {
339 &block.data_size),
340 GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
342 &path_size),
343 GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
347 };
348
349 while (cnt < total)
350 {
351 off = (off + 1) % total;
352 if (GNUNET_OK !=
353 GNUNET_SQ_bind (plugin->get_any_stmt,
354 params_select))
355 {
356 LOG_SQLITE (plugin->dbh,
358 "sqlite3_bind_xxx");
360 plugin->get_any_stmt);
361 return cnt;
362 }
363 if (SQLITE_ROW !=
364 sqlite3_step (plugin->get_any_stmt))
365 break;
366 if (GNUNET_OK !=
367 GNUNET_SQ_extract_result (plugin->get_any_stmt,
368 rs))
369 {
370 GNUNET_break (0);
372 plugin->get_any_stmt);
373 break;
374 }
375 if (0 != path_size % sizeof(struct GNUNET_DHT_PathElement))
376 {
377 GNUNET_break (0);
378 path_size = 0;
379 path = NULL;
380 }
381 block.data = data;
382 block.put_path = path;
383 block.put_path_length = path_size / sizeof(struct GNUNET_DHT_PathElement);
384 block.type = (enum GNUNET_BLOCK_Type) btype32;
385 block.ro = (enum GNUNET_DHT_RouteOption) bro32;
386 cnt++;
388 "Found %u-byte result when processing GET for key `%s'\n",
389 (unsigned int) block.data_size,
390 GNUNET_h2s (&block.key));
391 if (GNUNET_OK !=
392 iter (iter_cls,
393 &block))
394 {
397 plugin->get_any_stmt);
398 break;
399 }
402 plugin->get_any_stmt);
403 }
405 plugin->get_any_stmt);
406 }
407
408 return cnt;
409}
410
411
423static unsigned int
424get_typed (void *cls,
425 const struct GNUNET_HashCode *key,
428 void *iter_cls)
429{
430 struct Plugin *plugin = cls;
431 uint32_t type32 = type;
432 struct GNUNET_TIME_Absolute now;
433 unsigned int cnt;
434 uint32_t off;
435 uint32_t bro32;
436 unsigned int total;
437 struct GNUNET_DATACACHE_Block block;
438 void *path;
439 void *data;
440 size_t path_size;
441 struct GNUNET_SQ_ResultSpec rs[] = {
443 &block.data_size),
444 GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
446 &path_size),
447 GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
450 };
451
454 "Processing GET for key `%s'\n",
455 GNUNET_h2s (key));
456 {
457 struct GNUNET_SQ_QueryParam params_count[] = {
462 };
463
464 if (GNUNET_OK !=
465 GNUNET_SQ_bind (plugin->get_count_stmt,
466 params_count))
467 {
468 LOG_SQLITE (plugin->dbh,
470 "sqlite3_bind_xxx");
472 plugin->get_count_stmt);
473 return 0;
474 }
475 }
476 if (SQLITE_ROW !=
477 sqlite3_step (plugin->get_count_stmt))
478 {
479 LOG_SQLITE (plugin->dbh,
481 "sqlite_step");
483 plugin->get_count_stmt);
485 "No content found when processing GET for key `%s'\n",
486 GNUNET_h2s (key));
487 return 0;
488 }
489 total = sqlite3_column_int (plugin->get_count_stmt,
490 0);
492 plugin->get_count_stmt);
493 if ( (0 == total) ||
494 (NULL == iter) )
495 {
496 if (0 == total)
498 "No content found when processing GET for key `%s'\n",
499 GNUNET_h2s (key));
500 return total;
501 }
502
503 cnt = 0;
504 block.key = *key;
506 total);
507 {
508 struct GNUNET_SQ_QueryParam params_select[] = {
514 };
515 while (cnt < total)
516 {
517 off = (off + 1) % total;
518 if (GNUNET_OK !=
519 GNUNET_SQ_bind (plugin->get_stmt,
520 params_select))
521 {
522 LOG_SQLITE (plugin->dbh,
524 "sqlite3_bind_xxx");
526 plugin->get_stmt);
527 return cnt;
528 }
529 if (SQLITE_ROW !=
530 sqlite3_step (plugin->get_stmt))
531 break;
532 if (GNUNET_OK !=
534 rs))
535 {
536 GNUNET_break (0);
538 plugin->get_stmt);
539 break;
540 }
541 if (0 != path_size % sizeof(struct GNUNET_DHT_PathElement))
542 {
543 GNUNET_break (0);
544 path_size = 0;
545 path = NULL;
546 }
547 block.data = data;
548 block.put_path = path;
549 block.put_path_length = path_size / sizeof(struct GNUNET_DHT_PathElement);
550 block.type = type;
551 block.ro = (enum GNUNET_DHT_RouteOption) bro32;
552 cnt++;
554 "Found %u-byte result when processing GET for key `%s'\n",
555 (unsigned int) block.data_size,
556 GNUNET_h2s (&block.key));
557 if ( (NULL != iter) &&
558 (GNUNET_OK !=
559 iter (iter_cls,
560 &block)) )
561 {
564 plugin->get_stmt);
565 break;
566 }
569 plugin->get_stmt);
570 }
572 plugin->get_stmt);
573 }
574 return cnt;
575}
576
577
589static unsigned int
590sqlite_plugin_get (void *cls,
591 const struct GNUNET_HashCode *key,
594 void *iter_cls)
595{
597 return get_any (cls,
598 key,
599 iter,
600 iter_cls);
601 return get_typed (cls,
602 key,
603 type,
604 iter,
605 iter_cls);
606}
607
608
617sqlite_plugin_del (void *cls)
618{
619 struct Plugin *plugin = cls;
620 uint64_t rowid;
621 void *data;
622 size_t data_size;
623 struct GNUNET_HashCode hc;
624 struct GNUNET_TIME_Absolute now;
625 struct GNUNET_SQ_ResultSpec rs[] = {
629 &data_size),
631 };
632 struct GNUNET_SQ_QueryParam params[] = {
635 };
637 "Processing DEL\n");
639 {
640 struct GNUNET_SQ_QueryParam time_params[] = {
643 };
644
645 if (GNUNET_OK !=
646 GNUNET_SQ_bind (plugin->del_expired_stmt,
647 time_params))
648 {
649 LOG_SQLITE (plugin->dbh,
651 "sqlite3_bind");
653 plugin->del_expired_stmt);
654 return GNUNET_SYSERR;
655 }
656 }
657 if ( (SQLITE_ROW !=
658 sqlite3_step (plugin->del_expired_stmt)) ||
659 (GNUNET_OK !=
660 GNUNET_SQ_extract_result (plugin->del_expired_stmt,
661 rs)))
662 {
664 plugin->del_expired_stmt);
665 if (SQLITE_ROW !=
666 sqlite3_step (plugin->del_select_stmt))
667 {
668 LOG_SQLITE (plugin->dbh,
670 "sqlite3_step");
672 plugin->del_select_stmt);
673 return GNUNET_SYSERR;
674 }
675 if (GNUNET_OK !=
676 GNUNET_SQ_extract_result (plugin->del_select_stmt,
677 rs))
678 {
680 plugin->del_select_stmt);
681 GNUNET_break (0);
682 return GNUNET_SYSERR;
683 }
684 }
687 plugin->del_select_stmt);
688 if (GNUNET_OK !=
689 GNUNET_SQ_bind (plugin->del_stmt,
690 params))
691 {
692 LOG_SQLITE (plugin->dbh,
694 "sqlite3_bind");
696 plugin->del_stmt);
697 return GNUNET_SYSERR;
698 }
699 if (SQLITE_DONE !=
700 sqlite3_step (plugin->del_stmt))
701 {
702 LOG_SQLITE (plugin->dbh,
704 "sqlite3_step");
706 plugin->del_stmt);
707 return GNUNET_SYSERR;
708 }
709 plugin->num_items--;
710 plugin->env->delete_notify (plugin->env->cls,
711 &hc,
714 plugin->del_stmt);
715 return GNUNET_OK;
716}
717
718
733static unsigned int
735 const struct GNUNET_HashCode *key,
737 unsigned int num_results,
739 void *iter_cls)
740{
741 struct Plugin *plugin = cls;
742 uint32_t type32 = type;
743 uint32_t num_results32 = num_results;
744 struct GNUNET_TIME_Absolute now;
745 void *data;
746 void *path;
747 size_t path_size;
748 unsigned int cnt;
749 uint32_t bro32;
750 struct GNUNET_DATACACHE_Block block;
751 uint32_t rtype32;
752 struct GNUNET_SQ_ResultSpec rs[] = {
754 &block.data_size),
755 GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
757 &path_size),
758 GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
763 };
764
767 "Processing GET_CLOSEST for key `%s'\n",
768 GNUNET_h2s (key));
769 {
770 struct GNUNET_SQ_QueryParam params[] = {
774 GNUNET_SQ_query_param_uint32 (&num_results32),
776 };
777 if (GNUNET_OK !=
778 GNUNET_SQ_bind (plugin->get_closest_stmt,
779 params))
780 {
781 LOG_SQLITE (plugin->dbh,
783 "sqlite3_bind_xxx");
785 plugin->get_closest_stmt);
786 return 0;
787 }
788 }
789 cnt = 0;
790 while (SQLITE_ROW ==
791 sqlite3_step (plugin->get_closest_stmt))
792 {
793 if (GNUNET_OK !=
794 GNUNET_SQ_extract_result (plugin->get_closest_stmt,
795 rs))
796 {
797 GNUNET_break (0);
798 break;
799 }
800 if (0 != path_size % sizeof(struct GNUNET_DHT_PathElement))
801 {
802 GNUNET_break (0);
803 path_size = 0;
804 path = NULL;
805 }
806 block.put_path_length
807 = path_size / sizeof(struct GNUNET_DHT_PathElement);
808 block.put_path = path;
809 block.data = data;
810 block.type = (enum GNUNET_BLOCK_Type) rtype32;
811 block.ro = (enum GNUNET_DHT_RouteOption) bro32;
812 cnt++;
814 "Found %u-byte result at %s when processing GET_CLOSE\n",
815 (unsigned int) block.data_size,
816 GNUNET_h2s (&block.key));
817
818 if (GNUNET_OK !=
819 iter (iter_cls,
820 &block))
821 {
823 break;
824 }
826 }
828 plugin->get_closest_stmt);
829 return cnt;
830}
831
832
833void *
835
842void *
844{
847 struct Plugin *plugin;
848 char *fn;
849 char *fn_utf8;
850 sqlite3 *dbh;
851 char *emsg;
852
853 if (GNUNET_YES ==
855 "datacache-sqlite",
856 "IN_MEMORY"))
857 {
858 if (SQLITE_OK !=
859 sqlite3_open (":memory:",
860 &dbh))
861 return NULL;
862 fn_utf8 = NULL;
863 }
864 else
865 {
866 fn = GNUNET_DISK_mktemp ("gnunet-datacache");
867 if (NULL == fn)
868 {
869 GNUNET_break (0);
870 return NULL;
871 }
872 /* fn should be UTF-8-encoded. If it isn't, it's a bug. */
873 fn_utf8 = GNUNET_strdup (fn);
874 if (SQLITE_OK !=
875 sqlite3_open (fn_utf8,
876 &dbh))
877 {
878 GNUNET_free (fn);
879 GNUNET_free (fn_utf8);
880 return NULL;
881 }
882 GNUNET_free (fn);
883 }
884
885 SQLITE3_EXEC (dbh, "PRAGMA temp_store=MEMORY");
886 SQLITE3_EXEC (dbh, "PRAGMA locking_mode=EXCLUSIVE");
887 SQLITE3_EXEC (dbh, "PRAGMA journal_mode=OFF");
888 SQLITE3_EXEC (dbh, "PRAGMA synchronous=OFF");
889 SQLITE3_EXEC (dbh, "PRAGMA page_size=4092");
890 if (GNUNET_YES ==
892 "datacache-sqlite",
893 "IN_MEMORY"))
894 SQLITE3_EXEC (dbh, "PRAGMA sqlite_temp_store=3");
895
897 "CREATE TABLE ds180 ("
898 " type INTEGER NOT NULL DEFAULT 0,"
899 " ro INTEGER NOT NULL DEFAULT 0,"
900 " expire INTEGER NOT NULL,"
901 " key BLOB NOT NULL DEFAULT '',"
902 " prox INTEGER NOT NULL,"
903 " value BLOB NOT NULL,"
904 " trunc BLOB NOT NULL,"
905 " path BLOB DEFAULT '')");
907 "CREATE INDEX idx_hashidx"
908 " ON ds180 (key,type,expire)");
910 "CREATE INDEX idx_prox_expire"
911 " ON ds180 (prox,expire)");
913 "CREATE INDEX idx_expire_only"
914 " ON ds180 (expire)");
915 plugin = GNUNET_new (struct Plugin);
916 plugin->env = env;
917 plugin->dbh = dbh;
918 plugin->fn = fn_utf8;
919
920 if ((SQLITE_OK !=
921 sq_prepare (plugin->dbh,
922 "INSERT INTO ds180"
923 " (type, ro, expire, key, prox, value, path, trunc)"
924 " VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
925 &plugin->insert_stmt)) ||
926 (SQLITE_OK !=
927 sq_prepare (plugin->dbh,
928 "SELECT COUNT(*) FROM ds180 "
929 "WHERE key=?"
930 " AND type=?"
931 " AND expire >= ?",
932 &plugin->get_count_stmt)) ||
933 (SQLITE_OK !=
934 sq_prepare (plugin->dbh,
935 "SELECT COUNT(*) FROM ds180 "
936 "WHERE key=? AND expire >= ?",
937 &plugin->get_count_any_stmt)) ||
938 (SQLITE_OK !=
939 sq_prepare (plugin->dbh,
940 "SELECT value,expire,path,trunc,ro"
941 " FROM ds180"
942 " WHERE key=?"
943 " AND type=?"
944 " AND expire >= ?"
945 " LIMIT 1 OFFSET ?",
946 &plugin->get_stmt)) ||
947 (SQLITE_OK !=
948 sq_prepare (plugin->dbh,
949 "SELECT value,expire,path,trunc,type,ro"
950 " FROM ds180"
951 " WHERE key=?"
952 " AND expire >= ?"
953 " LIMIT 1 OFFSET ?",
954 &plugin->get_any_stmt)) ||
955 (SQLITE_OK !=
956 sq_prepare (plugin->dbh,
957 "SELECT _ROWID_,key,value FROM ds180"
958 " WHERE expire < ?1"
959 " ORDER BY expire ASC LIMIT 1",
960 &plugin->del_expired_stmt)) ||
961 (SQLITE_OK !=
962 sq_prepare (plugin->dbh,
963 "SELECT _ROWID_,key,value FROM ds180"
964 " ORDER BY prox ASC, expire ASC LIMIT 1",
965 &plugin->del_select_stmt)) ||
966 (SQLITE_OK !=
967 sq_prepare (plugin->dbh,
968 "DELETE FROM ds180 WHERE _ROWID_=?",
969 &plugin->del_stmt)) ||
970 (SQLITE_OK !=
971 sq_prepare (plugin->dbh,
972 "SELECT * FROM ("
973 " SELECT value,expire,path,trunc,type,ro,key"
974 " FROM ds180 "
975 " WHERE key>=?1 "
976 " AND expire >= ?2"
977 " AND ( (type=?3) or (0 == ?3) )"
978 " ORDER BY KEY ASC LIMIT ?4)"
979 "UNION "
980 "SELECT * FROM ("
981 " SELECT value,expire,path,trunc,type,ro,key"
982 " FROM ds180 "
983 " WHERE key<=?1 "
984 " AND expire >= ?2"
985 " AND ( (type=?3) or (0 == ?3) )"
986 " ORDER BY KEY DESC LIMIT ?4)",
987 &plugin->get_closest_stmt)))
988 {
989 LOG_SQLITE (plugin->dbh,
991 "sq_prepare");
992 GNUNET_break (SQLITE_OK ==
993 sqlite3_close (plugin->dbh));
995 return NULL;
996 }
997
999 api->cls = plugin;
1000 api->get = &sqlite_plugin_get;
1001 api->put = &sqlite_plugin_put;
1002 api->del = &sqlite_plugin_del;
1003 api->get_closest = &sqlite_plugin_get_closest;
1005 "Sqlite datacache running\n");
1006 return api;
1007}
1008
1009
1010void *
1012
1019void *
1021{
1023 struct Plugin *plugin = api->cls;
1024 int result;
1025
1026#if SQLITE_VERSION_NUMBER >= 3007000
1027 sqlite3_stmt *stmt;
1028#endif
1029
1030#if ! WINDOWS || defined(__CYGWIN__)
1031 if ( (NULL != plugin->fn) &&
1032 (0 != unlink (plugin->fn)) )
1034 "unlink",
1035 plugin->fn);
1036 GNUNET_free (plugin->fn);
1037#endif
1038 sqlite3_finalize (plugin->insert_stmt);
1039 sqlite3_finalize (plugin->get_count_stmt);
1040 sqlite3_finalize (plugin->get_count_any_stmt);
1041 sqlite3_finalize (plugin->get_stmt);
1042 sqlite3_finalize (plugin->get_any_stmt);
1043 sqlite3_finalize (plugin->del_select_stmt);
1044 sqlite3_finalize (plugin->del_expired_stmt);
1045 sqlite3_finalize (plugin->del_stmt);
1046 sqlite3_finalize (plugin->get_closest_stmt);
1047 result = sqlite3_close (plugin->dbh);
1048#if SQLITE_VERSION_NUMBER >= 3007000
1049 if (SQLITE_BUSY == result)
1050 {
1052 _ (
1053 "Tried to close sqlite without finalizing all prepared statements.\n"));
1054 stmt = sqlite3_next_stmt (plugin->dbh,
1055 NULL);
1056 while (NULL != stmt)
1057 {
1058 result = sqlite3_finalize (stmt);
1059 if (result != SQLITE_OK)
1061 "Failed to close statement %p: %d\n",
1062 stmt,
1063 result);
1064 stmt = sqlite3_next_stmt (plugin->dbh,
1065 NULL);
1066 }
1067 result = sqlite3_close (plugin->dbh);
1068 }
1069#endif
1070 if (SQLITE_OK != result)
1071 LOG_SQLITE (plugin->dbh,
1073 "sqlite3_close");
1074
1076 GNUNET_free (api);
1077 return NULL;
1078}
1079
1080
1081/* end of plugin_datacache_sqlite.c */
struct GNUNET_MQ_Envelope * env
Definition 005.c:1
static struct GNUNET_TESTING_PluginFunctions * plugin
Plugin to dynamically load a test case.
static char * data
The data to insert into the dht.
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.
static uint32_t type
Type string converted to DNS type value.
static size_t data_size
Number of bytes in data.
static int result
Global testing status.
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.
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:75
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:104
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:30
void GNUNET_SQ_reset(sqlite3 *dbh, sqlite3_stmt *stmt)
Reset stmt and log error.
Definition sq.c:119
#define GNUNET_SQ_query_param_end
End of query parameter specification.
#define GNUNET_SQ_result_spec_auto_from_type(dst)
We expect a fixed-size result, with size determined by the type of * dst
struct GNUNET_SQ_ResultSpec GNUNET_SQ_result_spec_uint64(uint64_t *u64)
uint64_t expected.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_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:431
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:406
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:599
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition time.c:111
#define _(String)
GNU gettext support macro.
Definition platform.h:179
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_init(void *cls)
Entry point for 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.
void * libgnunet_plugin_datacache_sqlite_done(void *cls)
Exit point from the plugin.
#define LOG(kind,...)
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.
enum GNUNET_BLOCK_Type type
Type of the block.
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.
Description of a DB result cell.
void * cls
Closure to pass to start_testcase.
Time for absolute times used by GNUnet, in microseconds.
Handle for a plugin.
Definition block.c:38
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition block.c:47
char * fn
Filename used for the DB.
struct GNUNET_PQ_Context * dbh
Native Postgres database handle.

◆ OVERHEAD

#define OVERHEAD   (sizeof(struct GNUNET_HashCode) + 36)

How much overhead do we assume per entry in the datacache?

Definition at line 42 of file plugin_datacache_sqlite.c.

◆ LOG_SQLITE

#define LOG_SQLITE (   db,
  level,
  cmd 
)
Value:
do \
{ \
LOG (level, \
_ ("`%s' failed at %s:%d with error: %s\n"), \
cmd, \
__FILE__, \
__LINE__, \
sqlite3_errmsg (db)); \
} while (0)
static struct GNUNET_FS_DirectoryBuilder * db

Log an error message at log-level level that indicates a failure of the command cmd with the error from the database db.

Parameters
dbdatabase handle
levellog level
cmdfailed command

Definition at line 124 of file plugin_datacache_sqlite.c.

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)

◆ SQLITE3_EXEC

#define SQLITE3_EXEC (   db,
  cmd 
)
Value:
do \
{ \
emsg = NULL; \
if (SQLITE_OK != \
sqlite3_exec (db, cmd, NULL, NULL, &emsg)) \
{ \
_ ("`%s' failed at %s:%d with error: %s\n"), \
"sqlite3_exec", \
__FILE__, \
__LINE__, \
emsg); \
sqlite3_free (emsg); \
} \
} while (0)

Execute SQL statement.

Parameters
dbdatabase handle
cmdSQL command to execute

Definition at line 142 of file plugin_datacache_sqlite.c.

144 { \
145 emsg = NULL; \
146 if (SQLITE_OK != \
147 sqlite3_exec (db, cmd, NULL, NULL, &emsg)) \
148 { \
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)

Function Documentation

◆ sq_prepare()

static int sq_prepare ( sqlite3 *  dbh,
const char *  zSql,
sqlite3_stmt **  ppStmt 
)
static

Prepare a SQL statement.

Parameters
dbhdatabase handle
zSqlSQL statement text
[out]ppStmtset to the prepared statement
Returns
0 on success

Definition at line 169 of file plugin_datacache_sqlite.c.

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}

References dummy.

Referenced by libgnunet_plugin_datacache_sqlite_init().

Here is the caller graph for this function:

◆ sqlite_plugin_put()

static ssize_t sqlite_plugin_put ( void *  cls,
uint32_t  xor_distance,
const struct GNUNET_DATACACHE_Block block 
)
static

Store an item in the datastore.

Parameters
clsclosure (our struct Plugin)
xor_distancehow close is key to our PID?
blockdata to store
Returns
0 if duplicate, -1 on error, number of bytes used otherwise

Definition at line 192 of file plugin_datacache_sqlite.c.

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");
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");
240 plugin->insert_stmt);
241 return -1;
242 }
243 plugin->num_items++;
245 plugin->insert_stmt);
246 return block->data_size + OVERHEAD;
247}
const struct GNUNET_DHT_PathElement * put_path
PUT path taken by the block, array of peer identities.
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?

References GNUNET_DATACACHE_Block::data, GNUNET_DATACACHE_Block::data_size, GNUNET_DATACACHE_Block::expiration_time, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_h2s(), GNUNET_OK, GNUNET_SQ_bind(), GNUNET_SQ_query_param_absolute_time(), GNUNET_SQ_query_param_auto_from_type, GNUNET_SQ_query_param_end, GNUNET_SQ_query_param_fixed_size(), GNUNET_SQ_query_param_uint32(), GNUNET_SQ_reset(), GNUNET_STRINGS_relative_time_to_string(), GNUNET_TIME_absolute_get_remaining(), GNUNET_YES, GNUNET_DATACACHE_Block::key, LOG, LOG_SQLITE, OVERHEAD, plugin, GNUNET_DATACACHE_Block::put_path, GNUNET_DATACACHE_Block::put_path_length, GNUNET_DATACACHE_Block::ro, GNUNET_DATACACHE_Block::trunc_peer, and GNUNET_DATACACHE_Block::type.

Referenced by libgnunet_plugin_datacache_sqlite_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_any()

static unsigned int get_any ( void *  cls,
const struct GNUNET_HashCode key,
GNUNET_DATACACHE_Iterator  iter,
void *  iter_cls 
)
static

Iterate over the results for a particular key in the datastore.

Parameters
clsclosure (our struct Plugin)
key
itermaybe NULL (to just count)
iter_clsclosure for iter
Returns
the number of results found

Definition at line 261 of file plugin_datacache_sqlite.c.

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
279 {
280 struct GNUNET_SQ_QueryParam params_count[] = {
284 };
286 "Processing GET for key `%s'\n",
287 GNUNET_h2s (key));
288
289 if (GNUNET_OK !=
290 GNUNET_SQ_bind (plugin->get_count_any_stmt,
291 params_count))
292 {
293 LOG_SQLITE (plugin->dbh,
295 "sqlite3_bind_xxx");
297 plugin->get_count_any_stmt);
298 return 0;
299 }
300 if (SQLITE_ROW !=
301 sqlite3_step (plugin->get_count_any_stmt))
302 {
303 LOG_SQLITE (plugin->dbh,
305 "sqlite_step");
307 plugin->get_count_any_stmt);
309 "No content found when processing GET for key `%s'\n",
310 GNUNET_h2s (key));
311 return 0;
312 }
313 total = sqlite3_column_int (plugin->get_count_any_stmt,
314 0);
316 plugin->get_count_any_stmt);
317 if ( (0 == total) ||
318 (NULL == iter) )
319 {
320 if (0 == total)
322 "No content found when processing GET for key `%s'\n",
323 GNUNET_h2s (key));
324 return total;
325 }
326 }
327 cnt = 0;
328 block.key = *key;
330 total);
331 {
332 struct GNUNET_SQ_QueryParam params_select[] = {
337 };
338 struct GNUNET_SQ_ResultSpec rs[] = {
340 &block.data_size),
341 GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
343 &path_size),
344 GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
348 };
349
350 while (cnt < total)
351 {
352 off = (off + 1) % total;
353 if (GNUNET_OK !=
354 GNUNET_SQ_bind (plugin->get_any_stmt,
355 params_select))
356 {
357 LOG_SQLITE (plugin->dbh,
359 "sqlite3_bind_xxx");
361 plugin->get_any_stmt);
362 return cnt;
363 }
364 if (SQLITE_ROW !=
365 sqlite3_step (plugin->get_any_stmt))
366 break;
367 if (GNUNET_OK !=
368 GNUNET_SQ_extract_result (plugin->get_any_stmt,
369 rs))
370 {
371 GNUNET_break (0);
373 plugin->get_any_stmt);
374 break;
375 }
376 if (0 != path_size % sizeof(struct GNUNET_DHT_PathElement))
377 {
378 GNUNET_break (0);
379 path_size = 0;
380 path = NULL;
381 }
382 block.data = data;
383 block.put_path = path;
384 block.put_path_length = path_size / sizeof(struct GNUNET_DHT_PathElement);
385 block.type = (enum GNUNET_BLOCK_Type) btype32;
386 block.ro = (enum GNUNET_DHT_RouteOption) bro32;
387 cnt++;
389 "Found %u-byte result when processing GET for key `%s'\n",
390 (unsigned int) block.data_size,
391 GNUNET_h2s (&block.key));
392 if (GNUNET_OK !=
393 iter (iter_cls,
394 &block))
395 {
398 plugin->get_any_stmt);
399 break;
400 }
403 plugin->get_any_stmt);
404 }
406 plugin->get_any_stmt);
407 }
408
409 return cnt;
410}

References data, GNUNET_DATACACHE_Block::data, GNUNET_DATACACHE_Block::data_size, GNUNET_DATACACHE_Block::expiration_time, GNUNET_break, GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CRYPTO_random_u32(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_h2s(), GNUNET_OK, GNUNET_SQ_bind(), GNUNET_SQ_cleanup_result(), GNUNET_SQ_extract_result(), GNUNET_SQ_query_param_absolute_time(), GNUNET_SQ_query_param_auto_from_type, GNUNET_SQ_query_param_end, GNUNET_SQ_query_param_uint32(), GNUNET_SQ_reset(), GNUNET_SQ_result_spec_absolute_time(), GNUNET_SQ_result_spec_auto_from_type, GNUNET_SQ_result_spec_end, GNUNET_SQ_result_spec_uint32(), GNUNET_SQ_result_spec_variable_size(), GNUNET_TIME_absolute_get(), key, GNUNET_DATACACHE_Block::key, LOG, LOG_SQLITE, plugin, GNUNET_DATACACHE_Block::put_path, GNUNET_DATACACHE_Block::put_path_length, GNUNET_DATACACHE_Block::ro, GNUNET_DATACACHE_Block::trunc_peer, and GNUNET_DATACACHE_Block::type.

Referenced by sqlite_plugin_get().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_typed()

static unsigned int get_typed ( void *  cls,
const struct GNUNET_HashCode key,
enum GNUNET_BLOCK_Type  type,
GNUNET_DATACACHE_Iterator  iter,
void *  iter_cls 
)
static

Iterate over the results for a particular key in the datastore.

Parameters
clsclosure (our struct Plugin)
key
typeentries of which type are relevant?
itermaybe NULL (to just count)
iter_clsclosure for iter
Returns
the number of results found

Definition at line 425 of file plugin_datacache_sqlite.c.

430{
431 struct Plugin *plugin = cls;
432 uint32_t type32 = type;
433 struct GNUNET_TIME_Absolute now;
434 unsigned int cnt;
435 uint32_t off;
436 uint32_t bro32;
437 unsigned int total;
438 struct GNUNET_DATACACHE_Block block;
439 void *path;
440 void *data;
441 size_t path_size;
442 struct GNUNET_SQ_ResultSpec rs[] = {
444 &block.data_size),
445 GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
447 &path_size),
448 GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
451 };
452
455 "Processing GET for key `%s'\n",
456 GNUNET_h2s (key));
457 {
458 struct GNUNET_SQ_QueryParam params_count[] = {
463 };
464
465 if (GNUNET_OK !=
466 GNUNET_SQ_bind (plugin->get_count_stmt,
467 params_count))
468 {
469 LOG_SQLITE (plugin->dbh,
471 "sqlite3_bind_xxx");
473 plugin->get_count_stmt);
474 return 0;
475 }
476 }
477 if (SQLITE_ROW !=
478 sqlite3_step (plugin->get_count_stmt))
479 {
480 LOG_SQLITE (plugin->dbh,
482 "sqlite_step");
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);
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 {
509 struct GNUNET_SQ_QueryParam params_select[] = {
515 };
516 while (cnt < total)
517 {
518 off = (off + 1) % total;
519 if (GNUNET_OK !=
520 GNUNET_SQ_bind (plugin->get_stmt,
521 params_select))
522 {
523 LOG_SQLITE (plugin->dbh,
525 "sqlite3_bind_xxx");
527 plugin->get_stmt);
528 return cnt;
529 }
530 if (SQLITE_ROW !=
531 sqlite3_step (plugin->get_stmt))
532 break;
533 if (GNUNET_OK !=
535 rs))
536 {
537 GNUNET_break (0);
539 plugin->get_stmt);
540 break;
541 }
542 if (0 != path_size % sizeof(struct GNUNET_DHT_PathElement))
543 {
544 GNUNET_break (0);
545 path_size = 0;
546 path = NULL;
547 }
548 block.data = data;
549 block.put_path = path;
550 block.put_path_length = path_size / sizeof(struct GNUNET_DHT_PathElement);
551 block.type = type;
552 block.ro = (enum GNUNET_DHT_RouteOption) bro32;
553 cnt++;
555 "Found %u-byte result when processing GET for key `%s'\n",
556 (unsigned int) block.data_size,
557 GNUNET_h2s (&block.key));
558 if ( (NULL != iter) &&
559 (GNUNET_OK !=
560 iter (iter_cls,
561 &block)) )
562 {
565 plugin->get_stmt);
566 break;
567 }
570 plugin->get_stmt);
571 }
573 plugin->get_stmt);
574 }
575 return cnt;
576}

References data, GNUNET_DATACACHE_Block::data, GNUNET_DATACACHE_Block::data_size, GNUNET_DATACACHE_Block::expiration_time, GNUNET_break, GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CRYPTO_random_u32(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_h2s(), GNUNET_OK, GNUNET_SQ_bind(), GNUNET_SQ_cleanup_result(), GNUNET_SQ_extract_result(), GNUNET_SQ_query_param_absolute_time(), GNUNET_SQ_query_param_auto_from_type, GNUNET_SQ_query_param_end, GNUNET_SQ_query_param_uint32(), GNUNET_SQ_reset(), GNUNET_SQ_result_spec_absolute_time(), GNUNET_SQ_result_spec_auto_from_type, GNUNET_SQ_result_spec_end, GNUNET_SQ_result_spec_uint32(), GNUNET_SQ_result_spec_variable_size(), GNUNET_TIME_absolute_get(), key, GNUNET_DATACACHE_Block::key, LOG, LOG_SQLITE, plugin, GNUNET_DATACACHE_Block::put_path, GNUNET_DATACACHE_Block::put_path_length, GNUNET_DATACACHE_Block::ro, GNUNET_DATACACHE_Block::trunc_peer, type, and GNUNET_DATACACHE_Block::type.

Referenced by sqlite_plugin_get().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sqlite_plugin_get()

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

Iterate over the results for a particular key in the datastore.

Parameters
clsclosure (our struct Plugin)
key
typeentries of which type are relevant?
itermaybe NULL (to just count)
iter_clsclosure for iter
Returns
the number of results found

Definition at line 591 of file plugin_datacache_sqlite.c.

596{
598 return get_any (cls,
599 key,
600 iter,
601 iter_cls);
602 return get_typed (cls,
603 key,
604 type,
605 iter,
606 iter_cls);
607}

References get_any(), get_typed(), GNUNET_BLOCK_TYPE_ANY, key, and type.

Referenced by libgnunet_plugin_datacache_sqlite_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sqlite_plugin_del()

static enum GNUNET_GenericReturnValue sqlite_plugin_del ( void *  cls)
static

Delete the entry with the lowest expiration value from the datacache right now.

Parameters
clsclosure (our struct Plugin)
Returns
GNUNET_OK on success, GNUNET_SYSERR on error

Definition at line 618 of file plugin_datacache_sqlite.c.

619{
620 struct Plugin *plugin = cls;
621 uint64_t rowid;
622 void *data;
623 size_t data_size;
624 struct GNUNET_HashCode hc;
625 struct GNUNET_TIME_Absolute now;
626 struct GNUNET_SQ_ResultSpec rs[] = {
630 &data_size),
632 };
633 struct GNUNET_SQ_QueryParam params[] = {
636 };
638 "Processing DEL\n");
640 {
641 struct GNUNET_SQ_QueryParam time_params[] = {
644 };
645
646 if (GNUNET_OK !=
647 GNUNET_SQ_bind (plugin->del_expired_stmt,
648 time_params))
649 {
650 LOG_SQLITE (plugin->dbh,
652 "sqlite3_bind");
654 plugin->del_expired_stmt);
655 return GNUNET_SYSERR;
656 }
657 }
658 if ( (SQLITE_ROW !=
659 sqlite3_step (plugin->del_expired_stmt)) ||
660 (GNUNET_OK !=
661 GNUNET_SQ_extract_result (plugin->del_expired_stmt,
662 rs)))
663 {
665 plugin->del_expired_stmt);
666 if (SQLITE_ROW !=
667 sqlite3_step (plugin->del_select_stmt))
668 {
669 LOG_SQLITE (plugin->dbh,
671 "sqlite3_step");
673 plugin->del_select_stmt);
674 return GNUNET_SYSERR;
675 }
676 if (GNUNET_OK !=
677 GNUNET_SQ_extract_result (plugin->del_select_stmt,
678 rs))
679 {
681 plugin->del_select_stmt);
682 GNUNET_break (0);
683 return GNUNET_SYSERR;
684 }
685 }
688 plugin->del_select_stmt);
689 if (GNUNET_OK !=
690 GNUNET_SQ_bind (plugin->del_stmt,
691 params))
692 {
693 LOG_SQLITE (plugin->dbh,
695 "sqlite3_bind");
697 plugin->del_stmt);
698 return GNUNET_SYSERR;
699 }
700 if (SQLITE_DONE !=
701 sqlite3_step (plugin->del_stmt))
702 {
703 LOG_SQLITE (plugin->dbh,
705 "sqlite3_step");
707 plugin->del_stmt);
708 return GNUNET_SYSERR;
709 }
710 plugin->num_items--;
711 plugin->env->delete_notify (plugin->env->cls,
712 &hc,
715 plugin->del_stmt);
716 return GNUNET_OK;
717}

References GNUNET_TESTING_PluginFunctions::cls, data, data_size, GNUNET_break, GNUNET_ERROR_TYPE_BULK, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_OK, GNUNET_SQ_bind(), GNUNET_SQ_cleanup_result(), GNUNET_SQ_extract_result(), GNUNET_SQ_query_param_absolute_time(), GNUNET_SQ_query_param_end, GNUNET_SQ_query_param_uint64(), GNUNET_SQ_reset(), GNUNET_SQ_result_spec_auto_from_type, GNUNET_SQ_result_spec_end, GNUNET_SQ_result_spec_uint64(), GNUNET_SQ_result_spec_variable_size(), GNUNET_SYSERR, GNUNET_TIME_absolute_get(), LOG, LOG_SQLITE, OVERHEAD, and plugin.

Referenced by libgnunet_plugin_datacache_sqlite_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sqlite_plugin_get_closest()

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

Iterate over the results that are "close" to a particular key in the datacache.

"close" is defined as numerically larger than key (when interpreted as a circular address space), with small distance.

Parameters
clsclosure (internal context for the plugin)
keyarea of the keyspace to look into
typedesired block type for the replies
num_resultsnumber of results that should be returned to iter
itermaybe NULL (to just count)
iter_clsclosure for iter
Returns
the number of results found

Definition at line 735 of file plugin_datacache_sqlite.c.

741{
742 struct Plugin *plugin = cls;
743 uint32_t type32 = type;
744 uint32_t num_results32 = num_results;
745 struct GNUNET_TIME_Absolute now;
746 void *data;
747 void *path;
748 size_t path_size;
749 unsigned int cnt;
750 uint32_t bro32;
751 struct GNUNET_DATACACHE_Block block;
752 uint32_t rtype32;
753 struct GNUNET_SQ_ResultSpec rs[] = {
755 &block.data_size),
756 GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
758 &path_size),
759 GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
764 };
765
768 "Processing GET_CLOSEST for key `%s'\n",
769 GNUNET_h2s (key));
770 {
771 struct GNUNET_SQ_QueryParam params[] = {
775 GNUNET_SQ_query_param_uint32 (&num_results32),
777 };
778 if (GNUNET_OK !=
779 GNUNET_SQ_bind (plugin->get_closest_stmt,
780 params))
781 {
782 LOG_SQLITE (plugin->dbh,
784 "sqlite3_bind_xxx");
786 plugin->get_closest_stmt);
787 return 0;
788 }
789 }
790 cnt = 0;
791 while (SQLITE_ROW ==
792 sqlite3_step (plugin->get_closest_stmt))
793 {
794 if (GNUNET_OK !=
795 GNUNET_SQ_extract_result (plugin->get_closest_stmt,
796 rs))
797 {
798 GNUNET_break (0);
799 break;
800 }
801 if (0 != path_size % sizeof(struct GNUNET_DHT_PathElement))
802 {
803 GNUNET_break (0);
804 path_size = 0;
805 path = NULL;
806 }
807 block.put_path_length
808 = path_size / sizeof(struct GNUNET_DHT_PathElement);
809 block.put_path = path;
810 block.data = data;
811 block.type = (enum GNUNET_BLOCK_Type) rtype32;
812 block.ro = (enum GNUNET_DHT_RouteOption) bro32;
813 cnt++;
815 "Found %u-byte result at %s when processing GET_CLOSE\n",
816 (unsigned int) block.data_size,
817 GNUNET_h2s (&block.key));
818
819 if (GNUNET_OK !=
820 iter (iter_cls,
821 &block))
822 {
824 break;
825 }
827 }
829 plugin->get_closest_stmt);
830 return cnt;
831}

References data, GNUNET_DATACACHE_Block::data, GNUNET_DATACACHE_Block::data_size, GNUNET_DATACACHE_Block::expiration_time, GNUNET_break, GNUNET_ERROR_TYPE_BULK, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_h2s(), GNUNET_OK, GNUNET_SQ_bind(), GNUNET_SQ_cleanup_result(), GNUNET_SQ_extract_result(), GNUNET_SQ_query_param_absolute_time(), GNUNET_SQ_query_param_auto_from_type, GNUNET_SQ_query_param_end, GNUNET_SQ_query_param_uint32(), GNUNET_SQ_reset(), GNUNET_SQ_result_spec_absolute_time(), GNUNET_SQ_result_spec_auto_from_type, GNUNET_SQ_result_spec_end, GNUNET_SQ_result_spec_uint32(), GNUNET_SQ_result_spec_variable_size(), GNUNET_TIME_absolute_get(), key, GNUNET_DATACACHE_Block::key, LOG, LOG_SQLITE, plugin, GNUNET_DATACACHE_Block::put_path, GNUNET_DATACACHE_Block::put_path_length, GNUNET_DATACACHE_Block::ro, GNUNET_DATACACHE_Block::trunc_peer, type, and GNUNET_DATACACHE_Block::type.

Referenced by libgnunet_plugin_datacache_sqlite_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ libgnunet_plugin_datacache_sqlite_init()

void * libgnunet_plugin_datacache_sqlite_init ( void *  cls)

Entry point for the plugin.

Parameters
clsclosure (the struct GNUNET_DATACACHE_PluginEnvironment)
Returns
the plugin's closure (our struct Plugin)

Definition at line 844 of file plugin_datacache_sqlite.c.

845{
848 struct Plugin *plugin;
849 char *fn;
850 char *fn_utf8;
851 sqlite3 *dbh;
852 char *emsg;
853
854 if (GNUNET_YES ==
856 "datacache-sqlite",
857 "IN_MEMORY"))
858 {
859 if (SQLITE_OK !=
860 sqlite3_open (":memory:",
861 &dbh))
862 return NULL;
863 fn_utf8 = NULL;
864 }
865 else
866 {
867 fn = GNUNET_DISK_mktemp ("gnunet-datacache");
868 if (NULL == fn)
869 {
870 GNUNET_break (0);
871 return NULL;
872 }
873 /* fn should be UTF-8-encoded. If it isn't, it's a bug. */
874 fn_utf8 = GNUNET_strdup (fn);
875 if (SQLITE_OK !=
876 sqlite3_open (fn_utf8,
877 &dbh))
878 {
879 GNUNET_free (fn);
880 GNUNET_free (fn_utf8);
881 return NULL;
882 }
883 GNUNET_free (fn);
884 }
885
886 SQLITE3_EXEC (dbh, "PRAGMA temp_store=MEMORY");
887 SQLITE3_EXEC (dbh, "PRAGMA locking_mode=EXCLUSIVE");
888 SQLITE3_EXEC (dbh, "PRAGMA journal_mode=OFF");
889 SQLITE3_EXEC (dbh, "PRAGMA synchronous=OFF");
890 SQLITE3_EXEC (dbh, "PRAGMA page_size=4092");
891 if (GNUNET_YES ==
893 "datacache-sqlite",
894 "IN_MEMORY"))
895 SQLITE3_EXEC (dbh, "PRAGMA sqlite_temp_store=3");
896
898 "CREATE TABLE ds180 ("
899 " type INTEGER NOT NULL DEFAULT 0,"
900 " ro INTEGER NOT NULL DEFAULT 0,"
901 " expire INTEGER NOT NULL,"
902 " key BLOB NOT NULL DEFAULT '',"
903 " prox INTEGER NOT NULL,"
904 " value BLOB NOT NULL,"
905 " trunc BLOB NOT NULL,"
906 " path BLOB DEFAULT '')");
908 "CREATE INDEX idx_hashidx"
909 " ON ds180 (key,type,expire)");
911 "CREATE INDEX idx_prox_expire"
912 " ON ds180 (prox,expire)");
914 "CREATE INDEX idx_expire_only"
915 " ON ds180 (expire)");
916 plugin = GNUNET_new (struct Plugin);
917 plugin->env = env;
918 plugin->dbh = dbh;
919 plugin->fn = fn_utf8;
920
921 if ((SQLITE_OK !=
922 sq_prepare (plugin->dbh,
923 "INSERT INTO ds180"
924 " (type, ro, expire, key, prox, value, path, trunc)"
925 " VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
926 &plugin->insert_stmt)) ||
927 (SQLITE_OK !=
928 sq_prepare (plugin->dbh,
929 "SELECT COUNT(*) FROM ds180 "
930 "WHERE key=?"
931 " AND type=?"
932 " AND expire >= ?",
933 &plugin->get_count_stmt)) ||
934 (SQLITE_OK !=
935 sq_prepare (plugin->dbh,
936 "SELECT COUNT(*) FROM ds180 "
937 "WHERE key=? AND expire >= ?",
938 &plugin->get_count_any_stmt)) ||
939 (SQLITE_OK !=
940 sq_prepare (plugin->dbh,
941 "SELECT value,expire,path,trunc,ro"
942 " FROM ds180"
943 " WHERE key=?"
944 " AND type=?"
945 " AND expire >= ?"
946 " LIMIT 1 OFFSET ?",
947 &plugin->get_stmt)) ||
948 (SQLITE_OK !=
949 sq_prepare (plugin->dbh,
950 "SELECT value,expire,path,trunc,type,ro"
951 " FROM ds180"
952 " WHERE key=?"
953 " AND expire >= ?"
954 " LIMIT 1 OFFSET ?",
955 &plugin->get_any_stmt)) ||
956 (SQLITE_OK !=
957 sq_prepare (plugin->dbh,
958 "SELECT _ROWID_,key,value FROM ds180"
959 " WHERE expire < ?1"
960 " ORDER BY expire ASC LIMIT 1",
961 &plugin->del_expired_stmt)) ||
962 (SQLITE_OK !=
963 sq_prepare (plugin->dbh,
964 "SELECT _ROWID_,key,value FROM ds180"
965 " ORDER BY prox ASC, expire ASC LIMIT 1",
966 &plugin->del_select_stmt)) ||
967 (SQLITE_OK !=
968 sq_prepare (plugin->dbh,
969 "DELETE FROM ds180 WHERE _ROWID_=?",
970 &plugin->del_stmt)) ||
971 (SQLITE_OK !=
972 sq_prepare (plugin->dbh,
973 "SELECT * FROM ("
974 " SELECT value,expire,path,trunc,type,ro,key"
975 " FROM ds180 "
976 " WHERE key>=?1 "
977 " AND expire >= ?2"
978 " AND ( (type=?3) or (0 == ?3) )"
979 " ORDER BY KEY ASC LIMIT ?4)"
980 "UNION "
981 "SELECT * FROM ("
982 " SELECT value,expire,path,trunc,type,ro,key"
983 " FROM ds180 "
984 " WHERE key<=?1 "
985 " AND expire >= ?2"
986 " AND ( (type=?3) or (0 == ?3) )"
987 " ORDER BY KEY DESC LIMIT ?4)",
988 &plugin->get_closest_stmt)))
989 {
990 LOG_SQLITE (plugin->dbh,
992 "sq_prepare");
993 GNUNET_break (SQLITE_OK ==
994 sqlite3_close (plugin->dbh));
996 return NULL;
997 }
998
1000 api->cls = plugin;
1001 api->get = &sqlite_plugin_get;
1002 api->put = &sqlite_plugin_put;
1003 api->del = &sqlite_plugin_del;
1004 api->get_closest = &sqlite_plugin_get_closest;
1006 "Sqlite datacache running\n");
1007 return api;
1008}

References Plugin::api, GNUNET_BLOCK_PluginFunctions::cls, GNUNET_DATACACHE_PluginEnvironment::cls, Plugin::dbh, env, Plugin::fn, GNUNET_break, GNUNET_CONFIGURATION_get_value_yesno(), GNUNET_DISK_mktemp(), GNUNET_ERROR_TYPE_BULK, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_INFO, GNUNET_free, GNUNET_new, GNUNET_strdup, GNUNET_YES, LOG, LOG_SQLITE, plugin, sq_prepare(), SQLITE3_EXEC, sqlite_plugin_del(), sqlite_plugin_get(), sqlite_plugin_get_closest(), and sqlite_plugin_put().

Here is the call graph for this function:

◆ libgnunet_plugin_datacache_sqlite_done()

void * libgnunet_plugin_datacache_sqlite_done ( void *  cls)

Exit point from the plugin.

Parameters
clsclosure (our struct Plugin)
Returns
NULL

Definition at line 1021 of file plugin_datacache_sqlite.c.

1022{
1024 struct Plugin *plugin = api->cls;
1025 int result;
1026
1027#if SQLITE_VERSION_NUMBER >= 3007000
1028 sqlite3_stmt *stmt;
1029#endif
1030
1031#if ! WINDOWS || defined(__CYGWIN__)
1032 if ( (NULL != plugin->fn) &&
1033 (0 != unlink (plugin->fn)) )
1035 "unlink",
1036 plugin->fn);
1037 GNUNET_free (plugin->fn);
1038#endif
1039 sqlite3_finalize (plugin->insert_stmt);
1040 sqlite3_finalize (plugin->get_count_stmt);
1041 sqlite3_finalize (plugin->get_count_any_stmt);
1042 sqlite3_finalize (plugin->get_stmt);
1043 sqlite3_finalize (plugin->get_any_stmt);
1044 sqlite3_finalize (plugin->del_select_stmt);
1045 sqlite3_finalize (plugin->del_expired_stmt);
1046 sqlite3_finalize (plugin->del_stmt);
1047 sqlite3_finalize (plugin->get_closest_stmt);
1048 result = sqlite3_close (plugin->dbh);
1049#if SQLITE_VERSION_NUMBER >= 3007000
1050 if (SQLITE_BUSY == result)
1051 {
1053 _ (
1054 "Tried to close sqlite without finalizing all prepared statements.\n"));
1055 stmt = sqlite3_next_stmt (plugin->dbh,
1056 NULL);
1057 while (NULL != stmt)
1058 {
1059 result = sqlite3_finalize (stmt);
1060 if (result != SQLITE_OK)
1062 "Failed to close statement %p: %d\n",
1063 stmt,
1064 result);
1065 stmt = sqlite3_next_stmt (plugin->dbh,
1066 NULL);
1067 }
1068 result = sqlite3_close (plugin->dbh);
1069 }
1070#endif
1071 if (SQLITE_OK != result)
1072 LOG_SQLITE (plugin->dbh,
1074 "sqlite3_close");
1075
1077 GNUNET_free (api);
1078 return NULL;
1079}

References _, Plugin::api, GNUNET_BLOCK_PluginFunctions::cls, GNUNET_DATACACHE_PluginFunctions::cls, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, LOG, LOG_SQLITE, LOG_STRERROR_FILE, plugin, and result.