GNUnet debian-0.24.3-29-g453fda2cf
 
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 struct GNUNET_SQ_QueryParam params_count[] = {
280 };
281 struct GNUNET_SQ_QueryParam params_select[] = {
286 };
287 struct GNUNET_SQ_ResultSpec rs[] = {
289 &block.data_size),
290 GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
292 &path_size),
293 GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
297 };
298
301 "Processing GET for key `%s'\n",
302 GNUNET_h2s (key));
303
304 if (GNUNET_OK !=
305 GNUNET_SQ_bind (plugin->get_count_any_stmt,
306 params_count))
307 {
308 LOG_SQLITE (plugin->dbh,
310 "sqlite3_bind_xxx");
312 plugin->get_count_any_stmt);
313 return 0;
314 }
315 if (SQLITE_ROW !=
316 sqlite3_step (plugin->get_count_any_stmt))
317 {
318 LOG_SQLITE (plugin->dbh,
320 "sqlite_step");
322 plugin->get_count_any_stmt);
324 "No content found when processing GET for key `%s'\n",
325 GNUNET_h2s (key));
326 return 0;
327 }
328 total = sqlite3_column_int (plugin->get_count_any_stmt,
329 0);
331 plugin->get_count_any_stmt);
332 if ( (0 == total) ||
333 (NULL == iter) )
334 {
335 if (0 == total)
337 "No content found when processing GET for key `%s'\n",
338 GNUNET_h2s (key));
339 return total;
340 }
341
342 cnt = 0;
343 block.key = *key;
345 total);
346 while (cnt < total)
347 {
348 off = (off + 1) % total;
349 if (GNUNET_OK !=
350 GNUNET_SQ_bind (plugin->get_any_stmt,
351 params_select))
352 {
353 LOG_SQLITE (plugin->dbh,
355 "sqlite3_bind_xxx");
357 plugin->get_any_stmt);
358 return cnt;
359 }
360 if (SQLITE_ROW !=
361 sqlite3_step (plugin->get_any_stmt))
362 break;
363 if (GNUNET_OK !=
364 GNUNET_SQ_extract_result (plugin->get_any_stmt,
365 rs))
366 {
367 GNUNET_break (0);
369 plugin->get_any_stmt);
370 break;
371 }
372 if (0 != path_size % sizeof(struct GNUNET_DHT_PathElement))
373 {
374 GNUNET_break (0);
375 path_size = 0;
376 path = NULL;
377 }
378 block.data = data;
379 block.put_path = path;
380 block.put_path_length = path_size / sizeof(struct GNUNET_DHT_PathElement);
381 block.type = (enum GNUNET_BLOCK_Type) btype32;
382 block.ro = (enum GNUNET_DHT_RouteOption) bro32;
383 cnt++;
385 "Found %u-byte result when processing GET for key `%s'\n",
386 (unsigned int) block.data_size,
387 GNUNET_h2s (&block.key));
388 if (GNUNET_OK !=
389 iter (iter_cls,
390 &block))
391 {
394 plugin->get_any_stmt);
395 break;
396 }
399 plugin->get_any_stmt);
400 }
402 plugin->get_any_stmt);
403 return cnt;
404}
405
406
418static unsigned int
419get_typed (void *cls,
420 const struct GNUNET_HashCode *key,
423 void *iter_cls)
424{
425 struct Plugin *plugin = cls;
426 uint32_t type32 = type;
427 struct GNUNET_TIME_Absolute now;
428 unsigned int cnt;
429 uint32_t off;
430 uint32_t bro32;
431 unsigned int total;
432 struct GNUNET_DATACACHE_Block block;
433 void *path;
434 void *data;
435 size_t path_size;
436 struct GNUNET_SQ_QueryParam params_count[] = {
441 };
442 struct GNUNET_SQ_QueryParam params_select[] = {
448 };
449 struct GNUNET_SQ_ResultSpec rs[] = {
451 &block.data_size),
452 GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
454 &path_size),
455 GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
458 };
459
462 "Processing GET for key `%s'\n",
463 GNUNET_h2s (key));
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 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 while (cnt < total)
508 {
509 off = (off + 1) % total;
510 if (GNUNET_OK !=
511 GNUNET_SQ_bind (plugin->get_stmt,
512 params_select))
513 {
514 LOG_SQLITE (plugin->dbh,
516 "sqlite3_bind_xxx");
518 plugin->get_stmt);
519 return cnt;
520 }
521 if (SQLITE_ROW !=
522 sqlite3_step (plugin->get_stmt))
523 break;
524 if (GNUNET_OK !=
526 rs))
527 {
528 GNUNET_break (0);
530 plugin->get_stmt);
531 break;
532 }
533 if (0 != path_size % sizeof(struct GNUNET_DHT_PathElement))
534 {
535 GNUNET_break (0);
536 path_size = 0;
537 path = NULL;
538 }
539 block.data = data;
540 block.put_path = path;
541 block.put_path_length = path_size / sizeof(struct GNUNET_DHT_PathElement);
542 block.type = type;
543 block.ro = (enum GNUNET_DHT_RouteOption) bro32;
544 cnt++;
546 "Found %u-byte result when processing GET for key `%s'\n",
547 (unsigned int) block.data_size,
548 GNUNET_h2s (&block.key));
549 if ( (NULL != iter) &&
550 (GNUNET_OK !=
551 iter (iter_cls,
552 &block)) )
553 {
556 plugin->get_stmt);
557 break;
558 }
561 plugin->get_stmt);
562 }
564 plugin->get_stmt);
565 return cnt;
566}
567
568
580static unsigned int
581sqlite_plugin_get (void *cls,
582 const struct GNUNET_HashCode *key,
585 void *iter_cls)
586{
588 return get_any (cls,
589 key,
590 iter,
591 iter_cls);
592 return get_typed (cls,
593 key,
594 type,
595 iter,
596 iter_cls);
597}
598
599
608sqlite_plugin_del (void *cls)
609{
610 struct Plugin *plugin = cls;
611 uint64_t rowid;
612 void *data;
613 size_t data_size;
614 struct GNUNET_HashCode hc;
615 struct GNUNET_TIME_Absolute now;
616 struct GNUNET_SQ_ResultSpec rs[] = {
620 &data_size),
622 };
623 struct GNUNET_SQ_QueryParam params[] = {
626 };
627 struct GNUNET_SQ_QueryParam time_params[] = {
630 };
631
633 "Processing DEL\n");
635 if (GNUNET_OK !=
636 GNUNET_SQ_bind (plugin->del_expired_stmt,
637 time_params))
638 {
639 LOG_SQLITE (plugin->dbh,
641 "sqlite3_bind");
643 plugin->del_expired_stmt);
644 return GNUNET_SYSERR;
645 }
646 if ( (SQLITE_ROW !=
647 sqlite3_step (plugin->del_expired_stmt)) ||
648 (GNUNET_OK !=
649 GNUNET_SQ_extract_result (plugin->del_expired_stmt,
650 rs)))
651 {
653 plugin->del_expired_stmt);
654 if (SQLITE_ROW !=
655 sqlite3_step (plugin->del_select_stmt))
656 {
657 LOG_SQLITE (plugin->dbh,
659 "sqlite3_step");
661 plugin->del_select_stmt);
662 return GNUNET_SYSERR;
663 }
664 if (GNUNET_OK !=
665 GNUNET_SQ_extract_result (plugin->del_select_stmt,
666 rs))
667 {
669 plugin->del_select_stmt);
670 GNUNET_break (0);
671 return GNUNET_SYSERR;
672 }
673 }
676 plugin->del_select_stmt);
677 if (GNUNET_OK !=
678 GNUNET_SQ_bind (plugin->del_stmt,
679 params))
680 {
681 LOG_SQLITE (plugin->dbh,
683 "sqlite3_bind");
685 plugin->del_stmt);
686 return GNUNET_SYSERR;
687 }
688 if (SQLITE_DONE !=
689 sqlite3_step (plugin->del_stmt))
690 {
691 LOG_SQLITE (plugin->dbh,
693 "sqlite3_step");
695 plugin->del_stmt);
696 return GNUNET_SYSERR;
697 }
698 plugin->num_items--;
699 plugin->env->delete_notify (plugin->env->cls,
700 &hc,
703 plugin->del_stmt);
704 return GNUNET_OK;
705}
706
707
722static unsigned int
724 const struct GNUNET_HashCode *key,
726 unsigned int num_results,
728 void *iter_cls)
729{
730 struct Plugin *plugin = cls;
731 uint32_t type32 = type;
732 uint32_t num_results32 = num_results;
733 struct GNUNET_TIME_Absolute now;
734 void *data;
735 void *path;
736 size_t path_size;
737 unsigned int cnt;
738 uint32_t bro32;
739 struct GNUNET_DATACACHE_Block block;
740 uint32_t rtype32;
741 struct GNUNET_SQ_QueryParam params[] = {
745 GNUNET_SQ_query_param_uint32 (&num_results32),
747 };
748 struct GNUNET_SQ_ResultSpec rs[] = {
750 &block.data_size),
751 GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
753 &path_size),
754 GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
759 };
760
763 "Processing GET_CLOSEST for key `%s'\n",
764 GNUNET_h2s (key));
765 if (GNUNET_OK !=
766 GNUNET_SQ_bind (plugin->get_closest_stmt,
767 params))
768 {
769 LOG_SQLITE (plugin->dbh,
771 "sqlite3_bind_xxx");
773 plugin->get_closest_stmt);
774 return 0;
775 }
776 cnt = 0;
777 while (SQLITE_ROW ==
778 sqlite3_step (plugin->get_closest_stmt))
779 {
780 if (GNUNET_OK !=
781 GNUNET_SQ_extract_result (plugin->get_closest_stmt,
782 rs))
783 {
784 GNUNET_break (0);
785 break;
786 }
787 if (0 != path_size % sizeof(struct GNUNET_DHT_PathElement))
788 {
789 GNUNET_break (0);
790 path_size = 0;
791 path = NULL;
792 }
793 block.put_path_length
794 = path_size / sizeof(struct GNUNET_DHT_PathElement);
795 block.put_path = path;
796 block.data = data;
797 block.type = (enum GNUNET_BLOCK_Type) rtype32;
798 block.ro = (enum GNUNET_DHT_RouteOption) bro32;
799 cnt++;
801 "Found %u-byte result at %s when processing GET_CLOSE\n",
802 (unsigned int) block.data_size,
803 GNUNET_h2s (&block.key));
804
805 if (GNUNET_OK !=
806 iter (iter_cls,
807 &block))
808 {
810 break;
811 }
813 }
815 plugin->get_closest_stmt);
816 return cnt;
817}
818
819void *
821
828void *
830{
833 struct Plugin *plugin;
834 char *fn;
835 char *fn_utf8;
836 sqlite3 *dbh;
837 char *emsg;
838
839 if (GNUNET_YES ==
841 "datacache-sqlite",
842 "IN_MEMORY"))
843 {
844 if (SQLITE_OK !=
845 sqlite3_open (":memory:",
846 &dbh))
847 return NULL;
848 fn_utf8 = NULL;
849 }
850 else
851 {
852 fn = GNUNET_DISK_mktemp ("gnunet-datacache");
853 if (NULL == fn)
854 {
855 GNUNET_break (0);
856 return NULL;
857 }
858 /* fn should be UTF-8-encoded. If it isn't, it's a bug. */
859 fn_utf8 = GNUNET_strdup (fn);
860 if (SQLITE_OK !=
861 sqlite3_open (fn_utf8,
862 &dbh))
863 {
864 GNUNET_free (fn);
865 GNUNET_free (fn_utf8);
866 return NULL;
867 }
868 GNUNET_free (fn);
869 }
870
871 SQLITE3_EXEC (dbh, "PRAGMA temp_store=MEMORY");
872 SQLITE3_EXEC (dbh, "PRAGMA locking_mode=EXCLUSIVE");
873 SQLITE3_EXEC (dbh, "PRAGMA journal_mode=OFF");
874 SQLITE3_EXEC (dbh, "PRAGMA synchronous=OFF");
875 SQLITE3_EXEC (dbh, "PRAGMA page_size=4092");
876 if (GNUNET_YES ==
878 "datacache-sqlite",
879 "IN_MEMORY"))
880 SQLITE3_EXEC (dbh, "PRAGMA sqlite_temp_store=3");
881
883 "CREATE TABLE ds180 ("
884 " type INTEGER NOT NULL DEFAULT 0,"
885 " ro INTEGER NOT NULL DEFAULT 0,"
886 " expire INTEGER NOT NULL,"
887 " key BLOB NOT NULL DEFAULT '',"
888 " prox INTEGER NOT NULL,"
889 " value BLOB NOT NULL,"
890 " trunc BLOB NOT NULL,"
891 " path BLOB DEFAULT '')");
893 "CREATE INDEX idx_hashidx"
894 " ON ds180 (key,type,expire)");
896 "CREATE INDEX idx_prox_expire"
897 " ON ds180 (prox,expire)");
899 "CREATE INDEX idx_expire_only"
900 " ON ds180 (expire)");
901 plugin = GNUNET_new (struct Plugin);
902 plugin->env = env;
903 plugin->dbh = dbh;
904 plugin->fn = fn_utf8;
905
906 if ((SQLITE_OK !=
907 sq_prepare (plugin->dbh,
908 "INSERT INTO ds180"
909 " (type, ro, expire, key, prox, value, path, trunc)"
910 " VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
911 &plugin->insert_stmt)) ||
912 (SQLITE_OK !=
913 sq_prepare (plugin->dbh,
914 "SELECT COUNT(*) FROM ds180 "
915 "WHERE key=?"
916 " AND type=?"
917 " AND expire >= ?",
918 &plugin->get_count_stmt)) ||
919 (SQLITE_OK !=
920 sq_prepare (plugin->dbh,
921 "SELECT COUNT(*) FROM ds180 "
922 "WHERE key=? AND expire >= ?",
923 &plugin->get_count_any_stmt)) ||
924 (SQLITE_OK !=
925 sq_prepare (plugin->dbh,
926 "SELECT value,expire,path,trunc,ro"
927 " FROM ds180"
928 " WHERE key=?"
929 " AND type=?"
930 " AND expire >= ?"
931 " LIMIT 1 OFFSET ?",
932 &plugin->get_stmt)) ||
933 (SQLITE_OK !=
934 sq_prepare (plugin->dbh,
935 "SELECT value,expire,path,trunc,type,ro"
936 " FROM ds180"
937 " WHERE key=?"
938 " AND expire >= ?"
939 " LIMIT 1 OFFSET ?",
940 &plugin->get_any_stmt)) ||
941 (SQLITE_OK !=
942 sq_prepare (plugin->dbh,
943 "SELECT _ROWID_,key,value FROM ds180"
944 " WHERE expire < ?1"
945 " ORDER BY expire ASC LIMIT 1",
946 &plugin->del_expired_stmt)) ||
947 (SQLITE_OK !=
948 sq_prepare (plugin->dbh,
949 "SELECT _ROWID_,key,value FROM ds180"
950 " ORDER BY prox ASC, expire ASC LIMIT 1",
951 &plugin->del_select_stmt)) ||
952 (SQLITE_OK !=
953 sq_prepare (plugin->dbh,
954 "DELETE FROM ds180 WHERE _ROWID_=?",
955 &plugin->del_stmt)) ||
956 (SQLITE_OK !=
957 sq_prepare (plugin->dbh,
958 "SELECT * FROM ("
959 " SELECT value,expire,path,trunc,type,ro,key"
960 " FROM ds180 "
961 " WHERE key>=?1 "
962 " AND expire >= ?2"
963 " AND ( (type=?3) or (0 == ?3) )"
964 " ORDER BY KEY ASC LIMIT ?4)"
965 "UNION "
966 "SELECT * FROM ("
967 " SELECT value,expire,path,trunc,type,ro,key"
968 " FROM ds180 "
969 " WHERE key<=?1 "
970 " AND expire >= ?2"
971 " AND ( (type=?3) or (0 == ?3) )"
972 " ORDER BY KEY DESC LIMIT ?4)",
973 &plugin->get_closest_stmt)))
974 {
975 LOG_SQLITE (plugin->dbh,
977 "sq_prepare");
978 GNUNET_break (SQLITE_OK ==
979 sqlite3_close (plugin->dbh));
981 return NULL;
982 }
983
985 api->cls = plugin;
986 api->get = &sqlite_plugin_get;
987 api->put = &sqlite_plugin_put;
988 api->del = &sqlite_plugin_del;
989 api->get_closest = &sqlite_plugin_get_closest;
991 "Sqlite datacache running\n");
992 return api;
993}
994
995void *
997
1004void *
1006{
1008 struct Plugin *plugin = api->cls;
1009 int result;
1010
1011#if SQLITE_VERSION_NUMBER >= 3007000
1012 sqlite3_stmt *stmt;
1013#endif
1014
1015#if ! WINDOWS || defined(__CYGWIN__)
1016 if ( (NULL != plugin->fn) &&
1017 (0 != unlink (plugin->fn)) )
1019 "unlink",
1020 plugin->fn);
1021 GNUNET_free (plugin->fn);
1022#endif
1023 sqlite3_finalize (plugin->insert_stmt);
1024 sqlite3_finalize (plugin->get_count_stmt);
1025 sqlite3_finalize (plugin->get_count_any_stmt);
1026 sqlite3_finalize (plugin->get_stmt);
1027 sqlite3_finalize (plugin->get_any_stmt);
1028 sqlite3_finalize (plugin->del_select_stmt);
1029 sqlite3_finalize (plugin->del_expired_stmt);
1030 sqlite3_finalize (plugin->del_stmt);
1031 sqlite3_finalize (plugin->get_closest_stmt);
1032 result = sqlite3_close (plugin->dbh);
1033#if SQLITE_VERSION_NUMBER >= 3007000
1034 if (SQLITE_BUSY == result)
1035 {
1037 _ (
1038 "Tried to close sqlite without finalizing all prepared statements.\n"));
1039 stmt = sqlite3_next_stmt (plugin->dbh,
1040 NULL);
1041 while (NULL != stmt)
1042 {
1043 result = sqlite3_finalize (stmt);
1044 if (result != SQLITE_OK)
1046 "Failed to close statement %p: %d\n",
1047 stmt,
1048 result);
1049 stmt = sqlite3_next_stmt (plugin->dbh,
1050 NULL);
1051 }
1052 result = sqlite3_close (plugin->dbh);
1053 }
1054#endif
1055 if (SQLITE_OK != result)
1056 LOG_SQLITE (plugin->dbh,
1058 "sqlite3_close");
1059
1061 GNUNET_free (api);
1062 return NULL;
1063}
1064
1065
1066/* 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 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),
291 GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
293 &path_size),
294 GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
298 };
299
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");
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");
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);
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");
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);
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 {
395 plugin->get_any_stmt);
396 break;
397 }
400 plugin->get_any_stmt);
401 }
403 plugin->get_any_stmt);
404 return cnt;
405}

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 420 of file plugin_datacache_sqlite.c.

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),
453 GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
455 &path_size),
456 GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
459 };
460
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");
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");
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 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");
519 plugin->get_stmt);
520 return cnt;
521 }
522 if (SQLITE_ROW !=
523 sqlite3_step (plugin->get_stmt))
524 break;
525 if (GNUNET_OK !=
527 rs))
528 {
529 GNUNET_break (0);
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 {
557 plugin->get_stmt);
558 break;
559 }
562 plugin->get_stmt);
563 }
565 plugin->get_stmt);
566 return cnt;
567}

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 582 of file plugin_datacache_sqlite.c.

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}

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 609 of file plugin_datacache_sqlite.c.

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");
636 if (GNUNET_OK !=
637 GNUNET_SQ_bind (plugin->del_expired_stmt,
638 time_params))
639 {
640 LOG_SQLITE (plugin->dbh,
642 "sqlite3_bind");
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 {
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");
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 {
670 plugin->del_select_stmt);
671 GNUNET_break (0);
672 return GNUNET_SYSERR;
673 }
674 }
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");
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");
696 plugin->del_stmt);
697 return GNUNET_SYSERR;
698 }
699 plugin->num_items--;
700 plugin->env->delete_notify (plugin->env->cls,
701 &hc,
704 plugin->del_stmt);
705 return GNUNET_OK;
706}

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 724 of file plugin_datacache_sqlite.c.

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),
752 GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
754 &path_size),
755 GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
760 };
761
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");
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 }
816 plugin->get_closest_stmt);
817 return cnt;
818}

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 830 of file plugin_datacache_sqlite.c.

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

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 1006 of file plugin_datacache_sqlite.c.

1007{
1009 struct Plugin *plugin = api->cls;
1010 int result;
1011
1012#if SQLITE_VERSION_NUMBER >= 3007000
1013 sqlite3_stmt *stmt;
1014#endif
1015
1016#if ! WINDOWS || defined(__CYGWIN__)
1017 if ( (NULL != plugin->fn) &&
1018 (0 != unlink (plugin->fn)) )
1020 "unlink",
1021 plugin->fn);
1022 GNUNET_free (plugin->fn);
1023#endif
1024 sqlite3_finalize (plugin->insert_stmt);
1025 sqlite3_finalize (plugin->get_count_stmt);
1026 sqlite3_finalize (plugin->get_count_any_stmt);
1027 sqlite3_finalize (plugin->get_stmt);
1028 sqlite3_finalize (plugin->get_any_stmt);
1029 sqlite3_finalize (plugin->del_select_stmt);
1030 sqlite3_finalize (plugin->del_expired_stmt);
1031 sqlite3_finalize (plugin->del_stmt);
1032 sqlite3_finalize (plugin->get_closest_stmt);
1033 result = sqlite3_close (plugin->dbh);
1034#if SQLITE_VERSION_NUMBER >= 3007000
1035 if (SQLITE_BUSY == result)
1036 {
1038 _ (
1039 "Tried to close sqlite without finalizing all prepared statements.\n"));
1040 stmt = sqlite3_next_stmt (plugin->dbh,
1041 NULL);
1042 while (NULL != stmt)
1043 {
1044 result = sqlite3_finalize (stmt);
1045 if (result != SQLITE_OK)
1047 "Failed to close statement %p: %d\n",
1048 stmt,
1049 result);
1050 stmt = sqlite3_next_stmt (plugin->dbh,
1051 NULL);
1052 }
1053 result = sqlite3_close (plugin->dbh);
1054 }
1055#endif
1056 if (SQLITE_OK != result)
1057 LOG_SQLITE (plugin->dbh,
1059 "sqlite3_close");
1060
1062 GNUNET_free (api);
1063 return NULL;
1064}

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.