aboutsummaryrefslogtreecommitdiff
path: root/src/datacache
diff options
context:
space:
mode:
Diffstat (limited to 'src/datacache')
-rw-r--r--src/datacache/.gitignore6
-rw-r--r--src/datacache/Makefile.am198
-rw-r--r--src/datacache/datacache.c361
-rw-r--r--src/datacache/datacache.conf2
-rw-r--r--src/datacache/perf_datacache.c174
-rw-r--r--src/datacache/perf_datacache_data_heap.conf5
-rw-r--r--src/datacache/perf_datacache_data_postgres.conf8
-rw-r--r--src/datacache/perf_datacache_data_sqlite.conf4
-rw-r--r--src/datacache/plugin_datacache_heap.c530
-rw-r--r--src/datacache/plugin_datacache_postgres.c634
-rw-r--r--src/datacache/plugin_datacache_sqlite.c1063
-rw-r--r--src/datacache/plugin_datacache_template.c172
-rw-r--r--src/datacache/test_datacache.c205
-rw-r--r--src/datacache/test_datacache_data_heap.conf4
-rw-r--r--src/datacache/test_datacache_data_postgres.conf7
-rw-r--r--src/datacache/test_datacache_data_sqlite.conf5
-rw-r--r--src/datacache/test_datacache_quota.c193
17 files changed, 0 insertions, 3571 deletions
diff --git a/src/datacache/.gitignore b/src/datacache/.gitignore
deleted file mode 100644
index 8e42aa103..000000000
--- a/src/datacache/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
1test_datacache_heap
2test_datacache_postgres
3test_datacache_quota_heap
4test_datacache_quota_postgres
5test_datacache_quota_sqlite
6test_datacache_sqlite
diff --git a/src/datacache/Makefile.am b/src/datacache/Makefile.am
deleted file mode 100644
index 4789706ff..000000000
--- a/src/datacache/Makefile.am
+++ /dev/null
@@ -1,198 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6pkgcfgdir= $(pkgdatadir)/config.d/
7
8dist_pkgcfg_DATA = \
9 datacache.conf
10
11if USE_COVERAGE
12 AM_CFLAGS = --coverage -O0
13 XLIBS = -lgcov
14endif
15
16if HAVE_SQLITE
17 SQLITE_PLUGIN = libgnunet_plugin_datacache_sqlite.la
18endif
19if HAVE_POSTGRESQL
20 POSTGRES_PLUGIN = libgnunet_plugin_datacache_postgres.la
21endif
22
23lib_LTLIBRARIES = \
24 libgnunetdatacache.la
25
26libgnunetdatacache_la_SOURCES = \
27 datacache.c
28libgnunetdatacache_la_LIBADD = \
29 $(top_builddir)/src/statistics/libgnunetstatistics.la \
30 $(top_builddir)/src/util/libgnunetutil.la \
31 $(GN_LIBINTL)
32libgnunetdatacache_la_LDFLAGS = \
33 $(GN_LIB_LDFLAGS) \
34 -version-info 0:1:0
35
36
37plugin_LTLIBRARIES = \
38 $(SQLITE_PLUGIN) \
39 $(POSTGRES_PLUGIN) \
40 libgnunet_plugin_datacache_heap.la
41
42# Real plugins should of course go into
43# plugin_LTLIBRARIES
44noinst_LTLIBRARIES = \
45 libgnunet_plugin_datacache_template.la
46
47
48libgnunet_plugin_datacache_sqlite_la_SOURCES = \
49 plugin_datacache_sqlite.c
50libgnunet_plugin_datacache_sqlite_la_LIBADD = \
51 $(top_builddir)/src/statistics/libgnunetstatistics.la \
52 $(top_builddir)/src/sq/libgnunetsq.la \
53 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
54 $(LTLIBINTL)
55libgnunet_plugin_datacache_sqlite_la_LDFLAGS = \
56 $(GN_PLUGIN_LDFLAGS)
57
58libgnunet_plugin_datacache_heap_la_SOURCES = \
59 plugin_datacache_heap.c
60libgnunet_plugin_datacache_heap_la_LIBADD = \
61 $(top_builddir)/src/statistics/libgnunetstatistics.la \
62 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
63 $(LTLIBINTL)
64libgnunet_plugin_datacache_heap_la_LDFLAGS = \
65 $(GN_PLUGIN_LDFLAGS)
66
67libgnunet_plugin_datacache_postgres_la_SOURCES = \
68 plugin_datacache_postgres.c
69libgnunet_plugin_datacache_postgres_la_LIBADD = \
70 $(top_builddir)/src/pq/libgnunetpq.la \
71 $(top_builddir)/src/statistics/libgnunetstatistics.la \
72 $(top_builddir)/src/util/libgnunetutil.la \
73 $(GN_PLUGIN_LDFLAGS) -lpq
74libgnunet_plugin_datacache_postgres_la_CPPFLAGS = \
75 $(POSTGRESQL_CPPFLAGS) $(AM_CPPFLAGS)
76libgnunet_plugin_datacache_postgres_la_LDFLAGS = \
77 $(GN_PLUGIN_LDFLAGS) $(POSTGRESQL_LDFLAGS)
78
79libgnunet_plugin_datacache_template_la_SOURCES = \
80 plugin_datacache_template.c
81libgnunet_plugin_datacache_template_la_LIBADD = \
82 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
83 $(LTLIBINTL)
84libgnunet_plugin_datacache_template_la_LDFLAGS = \
85 $(GN_PLUGIN_LDFLAGS)
86
87
88if HAVE_SQLITE
89if HAVE_BENCHMARKS
90 SQLITE_BENCHMARKS = \
91 perf_datacache_sqlite
92endif
93SQLITE_TESTS = \
94 test_datacache_sqlite \
95 test_datacache_quota_sqlite \
96 $(SQLITE_BENCHMARKS)
97
98if HAVE_BENCHMARKS
99 HEAP_BENCHMARKS = \
100 perf_datacache_heap
101endif
102HEAP_TESTS = \
103 test_datacache_heap \
104 test_datacache_quota_heap \
105 $(HEAP_BENCHMARKS)
106
107if HAVE_POSTGRESQL
108if HAVE_BENCHMARKS
109 POSTGRES_BENCHMARKS = \
110 perf_datacache_postgres
111endif
112POSTGRES_TESTS = \
113 test_datacache_postgres \
114 test_datacache_quota_postgres \
115 $(POSTGRES_BENCHMARKS)
116endif
117endif
118
119check_PROGRAMS = \
120 $(SQLITE_TESTS) \
121 $(HEAP_TESTS) \
122 $(POSTGRES_TESTS)
123
124if ENABLE_TEST_RUN
125AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
126TESTS = $(check_PROGRAMS)
127endif
128
129test_datacache_sqlite_SOURCES = \
130 test_datacache.c
131test_datacache_sqlite_LDADD = \
132 $(top_builddir)/src/testing/libgnunettesting.la \
133 libgnunetdatacache.la \
134 $(top_builddir)/src/util/libgnunetutil.la
135
136test_datacache_quota_sqlite_SOURCES = \
137 test_datacache_quota.c
138test_datacache_quota_sqlite_LDADD = \
139 $(top_builddir)/src/testing/libgnunettesting.la \
140 libgnunetdatacache.la \
141 $(top_builddir)/src/util/libgnunetutil.la
142
143perf_datacache_sqlite_SOURCES = \
144 perf_datacache.c
145perf_datacache_sqlite_LDADD = \
146 $(top_builddir)/src/testing/libgnunettesting.la \
147 libgnunetdatacache.la \
148 $(top_builddir)/src/util/libgnunetutil.la
149
150test_datacache_heap_SOURCES = \
151 test_datacache.c
152test_datacache_heap_LDADD = \
153 $(top_builddir)/src/testing/libgnunettesting.la \
154 libgnunetdatacache.la \
155 $(top_builddir)/src/util/libgnunetutil.la
156
157test_datacache_quota_heap_SOURCES = \
158 test_datacache_quota.c
159test_datacache_quota_heap_LDADD = \
160 $(top_builddir)/src/testing/libgnunettesting.la \
161 libgnunetdatacache.la \
162 $(top_builddir)/src/util/libgnunetutil.la
163
164perf_datacache_heap_SOURCES = \
165 perf_datacache.c
166perf_datacache_heap_LDADD = \
167 $(top_builddir)/src/testing/libgnunettesting.la \
168 libgnunetdatacache.la \
169 $(top_builddir)/src/util/libgnunetutil.la
170
171test_datacache_postgres_SOURCES = \
172 test_datacache.c
173test_datacache_postgres_LDADD = \
174 $(top_builddir)/src/testing/libgnunettesting.la \
175 libgnunetdatacache.la \
176 $(top_builddir)/src/util/libgnunetutil.la
177
178test_datacache_quota_postgres_SOURCES = \
179 test_datacache_quota.c
180test_datacache_quota_postgres_LDADD = \
181 $(top_builddir)/src/testing/libgnunettesting.la \
182 libgnunetdatacache.la \
183 $(top_builddir)/src/util/libgnunetutil.la
184
185perf_datacache_postgres_SOURCES = \
186 perf_datacache.c
187perf_datacache_postgres_LDADD = \
188 $(top_builddir)/src/testing/libgnunettesting.la \
189 libgnunetdatacache.la \
190 $(top_builddir)/src/util/libgnunetutil.la
191
192EXTRA_DIST = \
193 test_datacache_data_sqlite.conf \
194 perf_datacache_data_sqlite.conf \
195 test_datacache_data_heap.conf \
196 perf_datacache_data_heap.conf \
197 test_datacache_data_postgres.conf \
198 perf_datacache_data_postgres.conf
diff --git a/src/datacache/datacache.c b/src/datacache/datacache.c
deleted file mode 100644
index c93ed58d6..000000000
--- a/src/datacache/datacache.c
+++ /dev/null
@@ -1,361 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2004-2010, 2015, 2022 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file datacache/datacache.c
22 * @brief datacache API implementation
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_datacache_lib.h"
28#include "gnunet_statistics_service.h"
29#include "gnunet_datacache_plugin.h"
30
31
32#define LOG(kind, ...) GNUNET_log_from (kind, "datacache", __VA_ARGS__)
33
34#define LOG_STRERROR_FILE(kind, op, fn) \
35 GNUNET_log_from_strerror_file (kind, "datacache", op, fn)
36
37/**
38 * Internal state of the datacache library.
39 */
40struct GNUNET_DATACACHE_Handle
41{
42 /**
43 * Bloomfilter to quickly tell if we don't have the content.
44 */
45 struct GNUNET_CONTAINER_BloomFilter *filter;
46
47 /**
48 * Our configuration.
49 */
50 const struct GNUNET_CONFIGURATION_Handle *cfg;
51
52 /**
53 * Opaque handle for the statistics service.
54 */
55 struct GNUNET_STATISTICS_Handle *stats;
56
57 /**
58 * Configuration section to use.
59 */
60 char *section;
61
62 /**
63 * API of the transport as returned by the plugin's
64 * initialization function.
65 */
66 struct GNUNET_DATACACHE_PluginFunctions *api;
67
68 /**
69 * Short name for the plugin (e.g. "sqlite").
70 */
71 char *short_name;
72
73 /**
74 * Name of the library (e.g. "gnunet_plugin_datacache_sqlite").
75 */
76 char *lib_name;
77
78 /**
79 * Name for the bloom filter file.
80 */
81 char *bloom_name;
82
83 /**
84 * Environment provided to our plugin.
85 */
86 struct GNUNET_DATACACHE_PluginEnvironment env;
87
88 /**
89 * How much space is in use right now?
90 */
91 unsigned long long utilization;
92};
93
94
95/**
96 * Function called by plugins to notify the datacache
97 * about content deletions.
98 *
99 * @param cls closure
100 * @param key key of the content that was deleted
101 * @param size number of bytes that were made available
102 */
103static void
104env_delete_notify (void *cls,
105 const struct GNUNET_HashCode *key,
106 size_t size)
107{
108 struct GNUNET_DATACACHE_Handle *h = cls;
109
110 LOG (GNUNET_ERROR_TYPE_DEBUG,
111 "Content under key `%s' discarded\n",
112 GNUNET_h2s (key));
113 GNUNET_assert (h->utilization >= size);
114 h->utilization -= size;
115 GNUNET_CONTAINER_bloomfilter_remove (h->filter, key);
116 GNUNET_STATISTICS_update (h->stats,
117 "# bytes stored",
118 -(long long) size,
119 GNUNET_NO);
120 GNUNET_STATISTICS_update (h->stats,
121 "# items stored",
122 -1,
123 GNUNET_NO);
124}
125
126
127struct GNUNET_DATACACHE_Handle *
128GNUNET_DATACACHE_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
129 const char *section)
130{
131 unsigned int bf_size;
132 unsigned long long quota;
133 struct GNUNET_DATACACHE_Handle *ret;
134 char *libname;
135 char *name;
136 const struct GNUNET_OS_ProjectData *pd;
137
138 if (GNUNET_OK !=
139 GNUNET_CONFIGURATION_get_value_size (cfg,
140 section,
141 "QUOTA",
142 &quota))
143 {
144 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
145 section,
146 "QUOTA");
147 return NULL;
148 }
149 if (GNUNET_OK !=
150 GNUNET_CONFIGURATION_get_value_string (cfg,
151 section,
152 "DATABASE",
153 &name))
154 {
155 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
156 section,
157 "DATABASE");
158 return NULL;
159 }
160 bf_size = quota / 32; /* 8 bit per entry, 1 bit per 32 kb in DB */
161
162 ret = GNUNET_new (struct GNUNET_DATACACHE_Handle);
163
164 if (GNUNET_YES !=
165 GNUNET_CONFIGURATION_get_value_yesno (cfg,
166 section,
167 "DISABLE_BF"))
168 {
169 if (GNUNET_YES !=
170 GNUNET_CONFIGURATION_get_value_yesno (cfg,
171 section,
172 "DISABLE_BF_RC"))
173 {
174 ret->bloom_name = GNUNET_DISK_mktemp ("gnunet-datacachebloom");
175 }
176 if (NULL != ret->bloom_name)
177 {
178 ret->filter = GNUNET_CONTAINER_bloomfilter_load (
179 ret->bloom_name,
180 quota / 1024, /* 8 bit per entry in DB, expect 1k entries */
181 5);
182 }
183 if (NULL == ret->filter)
184 {
185 ret->filter =
186 GNUNET_CONTAINER_bloomfilter_init (NULL,
187 bf_size,
188 5); /* approx. 3% false positives at max use */
189 }
190 }
191 ret->stats = GNUNET_STATISTICS_create ("datacache",
192 cfg);
193 ret->section = GNUNET_strdup (section);
194 ret->env.cfg = cfg;
195 ret->env.delete_notify = &env_delete_notify;
196 ret->env.section = ret->section;
197 ret->env.cls = ret;
198 ret->env.delete_notify = &env_delete_notify;
199 ret->env.quota = quota;
200 LOG (GNUNET_ERROR_TYPE_INFO,
201 "Loading `%s' datacache plugin\n",
202 name);
203 GNUNET_asprintf (&libname,
204 "libgnunet_plugin_datacache_%s",
205 name);
206 ret->short_name = name;
207 ret->lib_name = libname;
208 /* Load the plugin within GNUnet's default context */
209 pd = GNUNET_OS_project_data_get ();
210 GNUNET_OS_init (GNUNET_OS_project_data_default ());
211 ret->api = GNUNET_PLUGIN_load (libname,
212 &ret->env);
213 GNUNET_OS_init (pd);
214 if (NULL == ret->api)
215 {
216 /* Try to load the plugin within the application's context
217 This normally happens when the application is not GNUnet itself but a
218 third party; inside GNUnet this is effectively a double failure. */
219 ret->api = GNUNET_PLUGIN_load (libname,
220 &ret->env);
221 if (NULL == ret->api)
222 {
223 LOG (GNUNET_ERROR_TYPE_ERROR,
224 "Failed to load datacache plugin for `%s'\n",
225 name);
226 GNUNET_DATACACHE_destroy (ret);
227 return NULL;
228 }
229 }
230 return ret;
231}
232
233
234void
235GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h)
236{
237 if (NULL != h->filter)
238 GNUNET_CONTAINER_bloomfilter_free (h->filter);
239 if (NULL != h->api)
240 GNUNET_break (NULL ==
241 GNUNET_PLUGIN_unload (h->lib_name,
242 h->api));
243 GNUNET_free (h->lib_name);
244 GNUNET_free (h->short_name);
245 GNUNET_free (h->section);
246 if (NULL != h->bloom_name)
247 {
248 if (0 != unlink (h->bloom_name))
249 GNUNET_log_from_strerror_file (GNUNET_ERROR_TYPE_WARNING,
250 "datacache",
251 "unlink",
252 h->bloom_name);
253 GNUNET_free (h->bloom_name);
254 }
255 GNUNET_STATISTICS_destroy (h->stats, GNUNET_NO);
256 GNUNET_free (h);
257}
258
259
260enum GNUNET_GenericReturnValue
261GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h,
262 uint32_t xor_distance,
263 const struct GNUNET_DATACACHE_Block *block)
264{
265 ssize_t used;
266
267 used = h->api->put (h->api->cls,
268 xor_distance,
269 block);
270 if (-1 == used)
271 {
272 GNUNET_break (0);
273 return GNUNET_SYSERR;
274 }
275 if (0 == used)
276 {
277 /* duplicate */
278 return GNUNET_NO;
279 }
280 LOG (GNUNET_ERROR_TYPE_DEBUG,
281 "Stored data under key `%s' in cache\n",
282 GNUNET_h2s (&block->key));
283 if (NULL != h->filter)
284 GNUNET_CONTAINER_bloomfilter_add (h->filter,
285 &block->key);
286 GNUNET_STATISTICS_update (h->stats,
287 "# bytes stored",
288 used,
289 GNUNET_NO);
290 GNUNET_STATISTICS_update (h->stats,
291 "# items stored",
292 1,
293 GNUNET_NO);
294 while (h->utilization + used > h->env.quota)
295 GNUNET_assert (GNUNET_OK ==
296 h->api->del (h->api->cls));
297 h->utilization += used;
298 return GNUNET_OK;
299}
300
301
302unsigned int
303GNUNET_DATACACHE_get (struct GNUNET_DATACACHE_Handle *h,
304 const struct GNUNET_HashCode *key,
305 enum GNUNET_BLOCK_Type type,
306 GNUNET_DATACACHE_Iterator iter,
307 void *iter_cls)
308{
309 GNUNET_STATISTICS_update (h->stats,
310 "# requests received",
311 1,
312 GNUNET_NO);
313 LOG (GNUNET_ERROR_TYPE_DEBUG,
314 "Processing request for key `%s'\n",
315 GNUNET_h2s (key));
316 if ( (NULL != h->filter) &&
317 (GNUNET_OK !=
318 GNUNET_CONTAINER_bloomfilter_test (h->filter,
319 key)) )
320 {
321 GNUNET_STATISTICS_update (h->stats,
322 "# requests filtered by bloom filter",
323 1,
324 GNUNET_NO);
325 LOG (GNUNET_ERROR_TYPE_DEBUG,
326 "Bloomfilter filters request for key `%s'\n",
327 GNUNET_h2s (key));
328 return 0; /* can not be present */
329 }
330 return h->api->get (h->api->cls,
331 key,
332 type,
333 iter, iter_cls);
334}
335
336
337unsigned int
338GNUNET_DATACACHE_get_closest (struct GNUNET_DATACACHE_Handle *h,
339 const struct GNUNET_HashCode *key,
340 enum GNUNET_BLOCK_Type type,
341 unsigned int num_results,
342 GNUNET_DATACACHE_Iterator iter,
343 void *iter_cls)
344{
345 GNUNET_STATISTICS_update (h->stats,
346 "# proximity search requests received",
347 1,
348 GNUNET_NO);
349 LOG (GNUNET_ERROR_TYPE_DEBUG,
350 "Processing proximity search at `%s'\n",
351 GNUNET_h2s (key));
352 return h->api->get_closest (h->api->cls,
353 key,
354 type,
355 num_results,
356 iter,
357 iter_cls);
358}
359
360
361/* end of datacache.c */
diff --git a/src/datacache/datacache.conf b/src/datacache/datacache.conf
deleted file mode 100644
index f9c718eb0..000000000
--- a/src/datacache/datacache.conf
+++ /dev/null
@@ -1,2 +0,0 @@
1[datacache-postgres]
2CONFIG = postgres:///gnunet
diff --git a/src/datacache/perf_datacache.c b/src/datacache/perf_datacache.c
deleted file mode 100644
index 84bc4a852..000000000
--- a/src/datacache/perf_datacache.c
+++ /dev/null
@@ -1,174 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2009, 2010 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/*
21 * @file datacache/perf_datacache.c
22 * @brief Performance evaluation for the datacache implementations.
23 * @author Nils Durner
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_datacache_lib.h"
28#include "gnunet_testing_lib.h"
29#include <gauger.h>
30
31
32#define ASSERT(x) do { if (! (x)) { printf ("Error at %s:%d\n", __FILE__, \
33 __LINE__); goto FAILURE; \
34 } } while (0)
35
36#define ITERATIONS 10000
37
38static int ok;
39
40static unsigned int found;
41
42/**
43 * Name of plugin under test.
44 */
45static const char *plugin_name;
46
47
48static int
49checkIt (void *cls,
50 const struct GNUNET_HashCode *key,
51 size_t size,
52 const char *data,
53 enum GNUNET_BLOCK_Type type,
54 struct GNUNET_TIME_Absolute exp,
55 unsigned int path_len,
56 const struct GNUNET_DHT_PathElement *path)
57{
58 if ( (size == sizeof(struct GNUNET_HashCode)) &&
59 (0 == memcmp (data,
60 cls,
61 size)) )
62 found++;
63 return GNUNET_OK;
64}
65
66
67static void
68run (void *cls,
69 char *const *args,
70 const char *cfgfile,
71 const struct GNUNET_CONFIGURATION_Handle *cfg)
72{
73 struct GNUNET_DATACACHE_Handle *h;
74 struct GNUNET_HashCode k;
75 struct GNUNET_HashCode n;
76 struct GNUNET_TIME_Absolute exp;
77 struct GNUNET_TIME_Absolute start;
78 unsigned int i;
79 char gstr[128];
80
81 ok = 0;
82 h = GNUNET_DATACACHE_create (cfg, "perfcache");
83
84 if (h == NULL)
85 {
86 fprintf (stderr, "%s",
87 "Failed to initialize datacache. Database likely not setup, skipping test.\n");
88 ok = 77; /* mark test as skipped */
89 return;
90 }
91 exp = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS);
92 start = GNUNET_TIME_absolute_get ();
93 memset (&k, 0, sizeof(struct GNUNET_HashCode));
94 for (i = 0; i < ITERATIONS; i++)
95 {
96 if (0 == i % (ITERATIONS / 80))
97 fprintf (stderr, "%s", ".");
98 GNUNET_CRYPTO_hash (&k, sizeof(struct GNUNET_HashCode), &n);
99 ASSERT (GNUNET_OK ==
100 GNUNET_DATACACHE_put (h, &k, sizeof(struct GNUNET_HashCode),
101 (const char *) &n, 1 + i % 16, exp,
102 0, NULL));
103 k = n;
104 }
105 fprintf (stderr, "%s", "\n");
106 fprintf (stdout, "Stored %u items in %s\n", ITERATIONS,
107 GNUNET_STRINGS_relative_time_to_string (
108 GNUNET_TIME_absolute_get_duration (start), GNUNET_YES));
109 GNUNET_snprintf (gstr, sizeof(gstr), "DATACACHE-%s", plugin_name);
110 GAUGER (gstr, "Time to PUT item in datacache",
111 GNUNET_TIME_absolute_get_duration (start).rel_value_us / 1000LL
112 / ITERATIONS,
113 "ms/item");
114 start = GNUNET_TIME_absolute_get ();
115 memset (&k, 0, sizeof(struct GNUNET_HashCode));
116 for (i = 0; i < ITERATIONS; i++)
117 {
118 if (0 == i % (ITERATIONS / 80))
119 fprintf (stderr, "%s", ".");
120 GNUNET_CRYPTO_hash (&k, sizeof(struct GNUNET_HashCode), &n);
121 GNUNET_DATACACHE_get (h, &k, 1 + i % 16, &checkIt, &n);
122 k = n;
123 }
124 fprintf (stderr, "%s", "\n");
125 fprintf (stdout,
126 "Found %u/%u items in %s (%u were deleted during storage processing)\n",
127 found, ITERATIONS,
128 GNUNET_STRINGS_relative_time_to_string (
129 GNUNET_TIME_absolute_get_duration (start), GNUNET_YES),
130 ITERATIONS - found);
131 if (found > 0)
132 GAUGER (gstr, "Time to GET item from datacache",
133 GNUNET_TIME_absolute_get_duration (start).rel_value_us / 1000LL
134 / found,
135 "ms/item");
136 GNUNET_DATACACHE_destroy (h);
137 ASSERT (ok == 0);
138 return;
139FAILURE:
140 if (h != NULL)
141 GNUNET_DATACACHE_destroy (h);
142 ok = GNUNET_SYSERR;
143}
144
145
146int
147main (int argc, char *argv[])
148{
149 char cfg_name[PATH_MAX];
150 char *const xargv[] = {
151 "perf-datacache",
152 "-c",
153 cfg_name,
154 NULL
155 };
156 struct GNUNET_GETOPT_CommandLineOption options[] = {
157 GNUNET_GETOPT_OPTION_END
158 };
159
160 GNUNET_log_setup ("perf-datacache",
161 "WARNING",
162 NULL);
163 plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
164 GNUNET_snprintf (cfg_name, sizeof(cfg_name), "perf_datacache_data_%s.conf",
165 plugin_name);
166 GNUNET_PROGRAM_run ((sizeof(xargv) / sizeof(char *)) - 1, xargv,
167 "perf-datacache", "nohelp", options, &run, NULL);
168 if ((0 != ok) && (77 != ok))
169 fprintf (stderr, "Missed some perfcases: %d\n", ok);
170 return ok;
171}
172
173
174/* end of perf_datacache.c */
diff --git a/src/datacache/perf_datacache_data_heap.conf b/src/datacache/perf_datacache_data_heap.conf
deleted file mode 100644
index 3680c020b..000000000
--- a/src/datacache/perf_datacache_data_heap.conf
+++ /dev/null
@@ -1,5 +0,0 @@
1[perfcache]
2QUOTA = 500 KB
3DATABASE = heap
4
5
diff --git a/src/datacache/perf_datacache_data_postgres.conf b/src/datacache/perf_datacache_data_postgres.conf
deleted file mode 100644
index c92f52a04..000000000
--- a/src/datacache/perf_datacache_data_postgres.conf
+++ /dev/null
@@ -1,8 +0,0 @@
1[perfcache]
2QUOTA = 500 KB
3DATABASE = postgres
4
5[datacache-postgres]
6CONFIG = connect_timeout=10; dbname=gnunetcheck
7
8
diff --git a/src/datacache/perf_datacache_data_sqlite.conf b/src/datacache/perf_datacache_data_sqlite.conf
deleted file mode 100644
index 9d0dbbdba..000000000
--- a/src/datacache/perf_datacache_data_sqlite.conf
+++ /dev/null
@@ -1,4 +0,0 @@
1[perfcache]
2QUOTA = 500 KB
3DATABASE = sqlite
4
diff --git a/src/datacache/plugin_datacache_heap.c b/src/datacache/plugin_datacache_heap.c
deleted file mode 100644
index 0dd8e47f8..000000000
--- a/src/datacache/plugin_datacache_heap.c
+++ /dev/null
@@ -1,530 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2012, 2015, 2022 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file datacache/plugin_datacache_heap.c
23 * @brief heap-only implementation of a database backend for the datacache
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_datacache_plugin.h"
29
30#define LOG(kind, ...) GNUNET_log_from (kind, "datacache-heap", __VA_ARGS__)
31
32#define LOG_STRERROR_FILE(kind, op, fn) GNUNET_log_from_strerror_file (kind, \
33 "datacache-heap", \
34 op, fn)
35
36#define NUM_HEAPS 24
37
38/**
39 * Context for all functions in this plugin.
40 */
41struct Plugin
42{
43 /**
44 * Our execution environment.
45 */
46 struct GNUNET_DATACACHE_PluginEnvironment *env;
47
48 /**
49 * Our hash map.
50 */
51 struct GNUNET_CONTAINER_MultiHashMap *map;
52
53 /**
54 * Heaps sorted by distance.
55 */
56 struct GNUNET_CONTAINER_Heap *heaps[NUM_HEAPS];
57};
58
59
60/**
61 * Entry in the hash map.
62 */
63struct Value
64{
65 /**
66 * Block data.
67 */
68 struct GNUNET_DATACACHE_Block block;
69
70 /**
71 * Corresponding node in the heap.
72 */
73 struct GNUNET_CONTAINER_HeapNode *hn;
74
75 /**
76 * Put path as a non-const pointer.
77 */
78 struct GNUNET_DHT_PathElement *put_path;
79
80 /**
81 * How close is the hash to us? Determines which heap we are in!
82 */
83 uint32_t distance;
84
85};
86
87
88#define OVERHEAD (sizeof(struct Value) + 64)
89
90
91/**
92 * Closure for #put_cb().
93 */
94struct PutContext
95{
96 /**
97 * Block data.
98 */
99 const struct GNUNET_DATACACHE_Block *block;
100
101 /**
102 * Value to set to true if an equivalent block was found.
103 */
104 bool found;
105};
106
107
108/**
109 * Function called during PUT to detect if an equivalent block
110 * already exists.
111 *
112 * @param cls the `struct PutContext`
113 * @param key the key for the value(s)
114 * @param value an existing value
115 * @return #GNUNET_YES if not found (to continue to iterate)
116 */
117static enum GNUNET_GenericReturnValue
118put_cb (void *cls,
119 const struct GNUNET_HashCode *key,
120 void *value)
121{
122 struct PutContext *put_ctx = cls;
123 struct Value *val = value;
124
125 if ((val->block.data_size == put_ctx->block->data_size) &&
126 (val->block.type == put_ctx->block->type) &&
127 (0 == memcmp (val->block.data,
128 put_ctx->block->data,
129 put_ctx->block->data_size)))
130 {
131 put_ctx->found = true;
132 val->block.expiration_time
133 = GNUNET_TIME_absolute_max (val->block.expiration_time,
134 put_ctx->block->expiration_time);
135 /* replace old path with new path */
136 GNUNET_free (val->put_path);
137 val->put_path = GNUNET_memdup (put_ctx->block->put_path,
138 put_ctx->block->put_path_length
139 * sizeof (struct GNUNET_DHT_PathElement));
140 val->block.put_path = val->put_path;
141 val->block.put_path_length = put_ctx->block->put_path_length;
142 GNUNET_CONTAINER_heap_update_cost (val->hn,
143 val->block.expiration_time.abs_value_us);
144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
145 "Got same value for key %s and type %u (size %u vs %u)\n",
146 GNUNET_h2s (key),
147 (unsigned int) val->block.type,
148 (unsigned int) val->block.data_size,
149 (unsigned int) put_ctx->block->data_size);
150 return GNUNET_NO;
151 }
152 return GNUNET_YES;
153}
154
155
156/**
157 * Store an item in the datastore.
158 *
159 * @param cls closure (our `struct Plugin`)
160 * @param xor_distance how close is @a key to our PID?
161 * @param block data to store
162 * @return 0 if duplicate, -1 on error, number of bytes used otherwise
163 */
164static ssize_t
165heap_plugin_put (void *cls,
166 uint32_t xor_distance,
167 const struct GNUNET_DATACACHE_Block *block)
168{
169 struct Plugin *plugin = cls;
170 struct Value *val;
171 struct PutContext put_ctx = {
172 .block = block,
173 .found = false
174 };
175
176 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
177 "Storing %u bytes under key %s with path length %u\n",
178 (unsigned int) block->data_size,
179 GNUNET_h2s (&block->key),
180 block->put_path_length);
181 GNUNET_CONTAINER_multihashmap_get_multiple (plugin->map,
182 &block->key,
183 &put_cb,
184 &put_ctx);
185 if (GNUNET_YES == put_ctx.found)
186 return 0;
187 val = GNUNET_malloc (sizeof(struct Value)
188 + block->data_size);
189 GNUNET_memcpy (&val[1],
190 block->data,
191 block->data_size);
192 val->block = *block;
193 val->block.data = &val[1];
194 if (xor_distance >= NUM_HEAPS)
195 val->distance = NUM_HEAPS - 1;
196 else
197 val->distance = xor_distance;
198 if (0 != block->put_path_length)
199 {
200 val->put_path
201 = GNUNET_memdup (block->put_path,
202 block->put_path_length
203 * sizeof (struct GNUNET_DHT_PathElement));
204 val->block.put_path = val->put_path;
205 }
206 (void) GNUNET_CONTAINER_multihashmap_put (plugin->map,
207 &val->block.key,
208 val,
209 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
210 val->hn = GNUNET_CONTAINER_heap_insert (
211 plugin->heaps[val->distance],
212 val,
213 val->block.expiration_time.abs_value_us);
214 return val->block.data_size + OVERHEAD;
215}
216
217
218/**
219 * Closure for #get_cb().
220 */
221struct GetContext
222{
223 /**
224 * Function to call for each result.
225 */
226 GNUNET_DATACACHE_Iterator iter;
227
228 /**
229 * Closure for @e iter.
230 */
231 void *iter_cls;
232
233 /**
234 * Number of results found.
235 */
236 unsigned int cnt;
237
238 /**
239 * Block type requested.
240 */
241 enum GNUNET_BLOCK_Type type;
242};
243
244
245/**
246 * Function called during GET to find matching blocks.
247 * Only matches by type.
248 *
249 * @param cls the `struct GetContext`
250 * @param key the key for the value(s)
251 * @param value an existing value
252 * @return #GNUNET_YES to continue to iterate
253 */
254static enum GNUNET_GenericReturnValue
255get_cb (void *cls,
256 const struct GNUNET_HashCode *key,
257 void *value)
258{
259 struct GetContext *get_ctx = cls;
260 struct Value *val = value;
261 enum GNUNET_GenericReturnValue ret;
262
263 if ( (get_ctx->type != val->block.type) &&
264 (GNUNET_BLOCK_TYPE_ANY != get_ctx->type) )
265 {
266 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
267 "Result for key %s does not match block type %d\n",
268 GNUNET_h2s (key),
269 get_ctx->type);
270 return GNUNET_OK;
271 }
272 if (GNUNET_TIME_absolute_is_past (val->block.expiration_time))
273 {
274 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
275 "Result for key %s is expired\n",
276 GNUNET_h2s (key));
277 return GNUNET_OK;
278 }
279 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
280 "Found result for key %s\n",
281 GNUNET_h2s (key));
282 if (NULL != get_ctx->iter)
283 ret = get_ctx->iter (get_ctx->iter_cls,
284 &val->block);
285 else
286 ret = GNUNET_YES;
287 get_ctx->cnt++;
288 return ret;
289}
290
291
292/**
293 * Iterate over the results for a particular key
294 * in the datastore.
295 *
296 * @param cls closure (our `struct Plugin`)
297 * @param key
298 * @param type entries of which type are relevant?
299 * @param iter maybe NULL (to just count)
300 * @param iter_cls closure for @a iter
301 * @return the number of results found
302 */
303static unsigned int
304heap_plugin_get (void *cls,
305 const struct GNUNET_HashCode *key,
306 enum GNUNET_BLOCK_Type type,
307 GNUNET_DATACACHE_Iterator iter,
308 void *iter_cls)
309{
310 struct Plugin *plugin = cls;
311 struct GetContext get_ctx;
312
313 get_ctx.type = type;
314 get_ctx.iter = iter;
315 get_ctx.iter_cls = iter_cls;
316 get_ctx.cnt = 0;
317 GNUNET_CONTAINER_multihashmap_get_multiple (plugin->map,
318 key,
319 &get_cb,
320 &get_ctx);
321 return get_ctx.cnt;
322}
323
324
325/**
326 * Delete the entry with the lowest expiration value
327 * from the datacache right now.
328 *
329 * @param cls closure (our `struct Plugin`)
330 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
331 */
332static enum GNUNET_GenericReturnValue
333heap_plugin_del (void *cls)
334{
335 struct Plugin *plugin = cls;
336 struct Value *val;
337
338 for (unsigned int i = 0; i < NUM_HEAPS; i++)
339 {
340 val = GNUNET_CONTAINER_heap_remove_root (plugin->heaps[i]);
341 if (NULL != val)
342 break;
343 }
344 if (NULL == val)
345 return GNUNET_SYSERR;
346 GNUNET_assert (GNUNET_YES ==
347 GNUNET_CONTAINER_multihashmap_remove (plugin->map,
348 &val->block.key,
349 val));
350 plugin->env->delete_notify (plugin->env->cls,
351 &val->block.key,
352 val->block.data_size + OVERHEAD);
353 GNUNET_free (val->put_path);
354 GNUNET_free (val);
355 return GNUNET_OK;
356}
357
358
359/**
360 * Closure for #find_closest().
361 */
362struct GetClosestContext
363{
364 struct Value **values;
365
366 const struct GNUNET_HashCode *key;
367
368 enum GNUNET_BLOCK_Type type;
369
370 unsigned int num_results;
371
372};
373
374
375static enum GNUNET_GenericReturnValue
376find_closest (void *cls,
377 const struct GNUNET_HashCode *key,
378 void *value)
379{
380 struct GetClosestContext *gcc = cls;
381 struct Value *val = value;
382 unsigned int j;
383
384 if (1 != GNUNET_CRYPTO_hash_cmp (key,
385 gcc->key))
386 return GNUNET_OK; /* useless */
387 if ( (val->block.type != gcc->type) &&
388 (GNUNET_BLOCK_TYPE_ANY != gcc->type) )
389 return GNUNET_OK; /* useless */
390 j = gcc->num_results;
391 for (unsigned int i = 0; i < gcc->num_results; i++)
392 {
393 if (NULL == gcc->values[i])
394 {
395 j = i;
396 break;
397 }
398 if (1 ==
399 GNUNET_CRYPTO_hash_cmp (&gcc->values[i]->block.key,
400 key))
401 {
402 j = i;
403 break;
404 }
405 }
406 if (j == gcc->num_results)
407 return GNUNET_OK;
408 gcc->values[j] = val;
409 return GNUNET_OK;
410}
411
412
413/**
414 * Iterate over the results that are "close" to a particular key in
415 * the datacache. "close" is defined as numerically larger than @a
416 * key (when interpreted as a circular address space), with small
417 * distance.
418 *
419 * @param cls closure (internal context for the plugin)
420 * @param key area of the keyspace to look into
421 * @param type desired block type for the replies
422 * @param num_results number of results that should be returned to @a iter
423 * @param iter maybe NULL (to just count)
424 * @param iter_cls closure for @a iter
425 * @return the number of results found
426 */
427static unsigned int
428heap_plugin_get_closest (void *cls,
429 const struct GNUNET_HashCode *key,
430 enum GNUNET_BLOCK_Type type,
431 unsigned int num_results,
432 GNUNET_DATACACHE_Iterator iter,
433 void *iter_cls)
434{
435 struct Plugin *plugin = cls;
436 struct Value *values[num_results];
437 struct GetClosestContext gcc = {
438 .values = values,
439 .type = type,
440 .num_results = num_results * 2,
441 .key = key
442 };
443
444 GNUNET_CONTAINER_multihashmap_iterate (plugin->map,
445 &find_closest,
446 &gcc);
447 for (unsigned int i = 0; i < num_results * 2; i++)
448 {
449 if (NULL == values[i])
450 return i;
451 if ( (NULL != iter) &&
452 (GNUNET_SYSERR ==
453 iter (iter_cls,
454 &values[i]->block)) )
455 {
456 LOG (GNUNET_ERROR_TYPE_DEBUG,
457 "Ending iteration (client error)\n");
458 return i;
459 }
460 }
461 return num_results * 2;
462}
463
464
465/**
466 * Entry point for the plugin.
467 *
468 * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironmnet`)
469 * @return the plugin's closure (our `struct Plugin`)
470 */
471void *
472libgnunet_plugin_datacache_heap_init (void *cls)
473{
474 struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
475 struct GNUNET_DATACACHE_PluginFunctions *api;
476 struct Plugin *plugin;
477
478 plugin = GNUNET_new (struct Plugin);
479 plugin->map = GNUNET_CONTAINER_multihashmap_create (1024, /* FIXME: base on quota! */
480 GNUNET_YES);
481 for (unsigned int i = 0; i < NUM_HEAPS; i++)
482 plugin->heaps[i] = GNUNET_CONTAINER_heap_create (
483 GNUNET_CONTAINER_HEAP_ORDER_MIN);
484 plugin->env = env;
485 api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
486 api->cls = plugin;
487 api->get = &heap_plugin_get;
488 api->put = &heap_plugin_put;
489 api->del = &heap_plugin_del;
490 api->get_closest = &heap_plugin_get_closest;
491 LOG (GNUNET_ERROR_TYPE_INFO,
492 _ ("Heap datacache running\n"));
493 return api;
494}
495
496
497/**
498 * Exit point from the plugin.
499 *
500 * @param cls closure (our "struct Plugin")
501 * @return NULL
502 */
503void *
504libgnunet_plugin_datacache_heap_done (void *cls)
505{
506 struct GNUNET_DATACACHE_PluginFunctions *api = cls;
507 struct Plugin *plugin = api->cls;
508 struct Value *val;
509
510 for (unsigned int i = 0; i < NUM_HEAPS; i++)
511 {
512 while (NULL != (val = GNUNET_CONTAINER_heap_remove_root (plugin->heaps[i])))
513 {
514 GNUNET_assert (GNUNET_YES ==
515 GNUNET_CONTAINER_multihashmap_remove (plugin->map,
516 &val->block.key,
517 val));
518 GNUNET_free (val->put_path);
519 GNUNET_free (val);
520 }
521 GNUNET_CONTAINER_heap_destroy (plugin->heaps[i]);
522 }
523 GNUNET_CONTAINER_multihashmap_destroy (plugin->map);
524 GNUNET_free (plugin);
525 GNUNET_free (api);
526 return NULL;
527}
528
529
530/* end of plugin_datacache_heap.c */
diff --git a/src/datacache/plugin_datacache_postgres.c b/src/datacache/plugin_datacache_postgres.c
deleted file mode 100644
index b1f9a1b8e..000000000
--- a/src/datacache/plugin_datacache_postgres.c
+++ /dev/null
@@ -1,634 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2006, 2009, 2010, 2012, 2015, 2017, 2018, 2022 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file datacache/plugin_datacache_postgres.c
23 * @brief postgres for an implementation of a database backend for the datacache
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_pq_lib.h"
29#include "gnunet_datacache_plugin.h"
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "datacache-postgres", __VA_ARGS__)
32
33/**
34 * Per-entry overhead estimate
35 */
36#define OVERHEAD (sizeof(struct GNUNET_HashCode) + 24)
37
38/**
39 * Context for all functions in this plugin.
40 */
41struct Plugin
42{
43 /**
44 * Our execution environment.
45 */
46 struct GNUNET_DATACACHE_PluginEnvironment *env;
47
48 /**
49 * Native Postgres database handle.
50 */
51 struct GNUNET_PQ_Context *dbh;
52
53 /**
54 * Number of key-value pairs in the database.
55 */
56 unsigned int num_items;
57};
58
59
60/**
61 * @brief Get a database handle
62 *
63 * @param plugin global context
64 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
65 */
66static enum GNUNET_GenericReturnValue
67init_connection (struct Plugin *plugin)
68{
69 struct GNUNET_PQ_ExecuteStatement es[] = {
70 GNUNET_PQ_make_try_execute (
71 "CREATE TEMPORARY SEQUENCE IF NOT EXISTS gn180dc_oid_seq"),
72 GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS gn180dc ("
73 " oid OID NOT NULL DEFAULT nextval('gn180dc_oid_seq'),"
74 " type INT4 NOT NULL,"
75 " ro INT4 NOT NULL,"
76 " prox INT4 NOT NULL,"
77 " expiration_time INT8 NOT NULL,"
78 " key BYTEA NOT NULL CHECK(LENGTH(key)=64),"
79 " trunc BYTEA NOT NULL CHECK(LENGTH(trunc)=32),"
80 " value BYTEA NOT NULL,"
81 " path BYTEA DEFAULT NULL)"),
82 GNUNET_PQ_make_try_execute (
83 "ALTER SEQUENCE gnu011dc_oid_seq OWNED BY gn180dc.oid"),
84 GNUNET_PQ_make_try_execute (
85 "CREATE INDEX IF NOT EXISTS idx_oid ON gn180dc (oid)"),
86 GNUNET_PQ_make_try_execute (
87 "CREATE INDEX IF NOT EXISTS idx_key ON gn180dc (key)"),
88 GNUNET_PQ_make_try_execute (
89 "CREATE INDEX IF NOT EXISTS idx_dt ON gn180dc (expiration_time)"),
90 GNUNET_PQ_make_execute (
91 "ALTER TABLE gn180dc ALTER value SET STORAGE EXTERNAL"),
92 GNUNET_PQ_make_execute ("ALTER TABLE gn180dc ALTER key SET STORAGE PLAIN"),
93 GNUNET_PQ_EXECUTE_STATEMENT_END
94 };
95 struct GNUNET_PQ_PreparedStatement ps[] = {
96 GNUNET_PQ_make_prepare ("getkt",
97 "SELECT expiration_time,type,ro,value,trunc,path FROM gn180dc "
98 "WHERE key=$1 AND type=$2 AND expiration_time >= $3",
99 3),
100 GNUNET_PQ_make_prepare ("getk",
101 "SELECT expiration_time,type,ro,value,trunc,path FROM gn180dc "
102 "WHERE key=$1 AND expiration_time >= $2",
103 2),
104 GNUNET_PQ_make_prepare ("getex",
105 "SELECT LENGTH(value) AS len,oid,key FROM gn180dc"
106 " WHERE expiration_time < $1"
107 " ORDER BY expiration_time ASC LIMIT 1",
108 1),
109 GNUNET_PQ_make_prepare ("getm",
110 "SELECT LENGTH(value) AS len,oid,key FROM gn180dc"
111 " ORDER BY prox ASC, expiration_time ASC LIMIT 1",
112 0),
113 GNUNET_PQ_make_prepare ("get_closest",
114 "(SELECT expiration_time,type,ro,value,trunc,path,key FROM gn180dc"
115 " WHERE key >= $1"
116 " AND expiration_time >= $2"
117 " AND ( (type = $3) OR ( 0 = $3) )"
118 " ORDER BY key ASC"
119 " LIMIT $4)"
120 " UNION "
121 "(SELECT expiration_time,type,ro,value,trunc,path,key FROM gn180dc"
122 " WHERE key <= $1"
123 " AND expiration_time >= $2"
124 " AND ( (type = $3) OR ( 0 = $3) )"
125 " ORDER BY key DESC"
126 " LIMIT $4)",
127 4),
128 GNUNET_PQ_make_prepare ("delrow",
129 "DELETE FROM gn180dc WHERE oid=$1",
130 1),
131 GNUNET_PQ_make_prepare ("put",
132 "INSERT INTO gn180dc"
133 " (type, ro, prox, expiration_time, key, value, trunc, path) "
134 "VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
135 8),
136 GNUNET_PQ_PREPARED_STATEMENT_END
137 };
138
139 plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->env->cfg,
140 "datacache-postgres",
141 NULL,
142 es,
143 ps);
144 if (NULL == plugin->dbh)
145 return GNUNET_SYSERR;
146 return GNUNET_OK;
147}
148
149
150/**
151 * Store an item in the datastore.
152 *
153 * @param cls closure (our `struct Plugin`)
154 * @param prox proximity of @a key to my PID
155 * @param block data to store
156 * @return 0 if duplicate, -1 on error, number of bytes used otherwise
157 */
158static ssize_t
159postgres_plugin_put (void *cls,
160 uint32_t prox,
161 const struct GNUNET_DATACACHE_Block *block)
162{
163 struct Plugin *plugin = cls;
164 uint32_t type32 = (uint32_t) block->type;
165 uint32_t ro32 = (uint32_t) block->type;
166 struct GNUNET_PQ_QueryParam params[] = {
167 GNUNET_PQ_query_param_uint32 (&type32),
168 GNUNET_PQ_query_param_uint32 (&ro32),
169 GNUNET_PQ_query_param_uint32 (&prox),
170 GNUNET_PQ_query_param_absolute_time (&block->expiration_time),
171 GNUNET_PQ_query_param_auto_from_type (&block->key),
172 GNUNET_PQ_query_param_fixed_size (block->data,
173 block->data_size),
174 GNUNET_PQ_query_param_auto_from_type (&block->trunc_peer),
175 GNUNET_PQ_query_param_fixed_size (block->put_path,
176 block->put_path_length
177 * sizeof(struct GNUNET_DHT_PathElement)),
178 GNUNET_PQ_query_param_end
179 };
180 enum GNUNET_DB_QueryStatus ret;
181
182 ret = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
183 "put",
184 params);
185 if (0 > ret)
186 return -1;
187 plugin->num_items++;
188 return block->data_size + OVERHEAD;
189}
190
191
192/**
193 * Closure for #handle_results.
194 */
195struct HandleResultContext
196{
197 /**
198 * Function to call on each result, may be NULL.
199 */
200 GNUNET_DATACACHE_Iterator iter;
201
202 /**
203 * Closure for @e iter.
204 */
205 void *iter_cls;
206
207 /**
208 * Key used.
209 */
210 const struct GNUNET_HashCode *key;
211};
212
213
214/**
215 * Function to be called with the results of a SELECT statement
216 * that has returned @a num_results results. Parse the result
217 * and call the callback given in @a cls
218 *
219 * @param cls closure of type `struct HandleResultContext`
220 * @param result the postgres result
221 * @param num_result the number of results in @a result
222 */
223static void
224handle_results (void *cls,
225 PGresult *result,
226 unsigned int num_results)
227{
228 struct HandleResultContext *hrc = cls;
229
230 for (unsigned int i = 0; i < num_results; i++)
231 {
232 uint32_t type32;
233 uint32_t bro32;
234 void *data;
235 struct GNUNET_DATACACHE_Block block;
236 void *path;
237 size_t path_size;
238 struct GNUNET_PQ_ResultSpec rs[] = {
239 GNUNET_PQ_result_spec_absolute_time ("expiration_time",
240 &block.expiration_time),
241 GNUNET_PQ_result_spec_uint32 ("type",
242 &type32),
243 GNUNET_PQ_result_spec_uint32 ("ro",
244 &bro32),
245 GNUNET_PQ_result_spec_variable_size ("value",
246 &data,
247 &block.data_size),
248 GNUNET_PQ_result_spec_auto_from_type ("trunc",
249 &block.trunc_peer),
250 GNUNET_PQ_result_spec_variable_size ("path",
251 &path,
252 &path_size),
253 GNUNET_PQ_result_spec_end
254 };
255
256 if (GNUNET_YES !=
257 GNUNET_PQ_extract_result (result,
258 rs,
259 i))
260 {
261 GNUNET_break (0);
262 return;
263 }
264 if (0 != (path_size % sizeof(struct GNUNET_DHT_PathElement)))
265 {
266 GNUNET_break (0);
267 path_size = 0;
268 path = NULL;
269 }
270 block.data = data;
271 block.put_path = path;
272 block.put_path_length
273 = path_size / sizeof (struct GNUNET_DHT_PathElement);
274 block.type = (enum GNUNET_BLOCK_Type) type32;
275 block.ro = (enum GNUNET_DHT_RouteOption) bro32;
276 block.key = *hrc->key;
277 LOG (GNUNET_ERROR_TYPE_DEBUG,
278 "Found result of size %u bytes and type %u in database\n",
279 (unsigned int) block.data_size,
280 (unsigned int) block.type);
281 if ( (NULL != hrc->iter) &&
282 (GNUNET_SYSERR ==
283 hrc->iter (hrc->iter_cls,
284 &block)) )
285 {
286 LOG (GNUNET_ERROR_TYPE_DEBUG,
287 "Ending iteration (client error)\n");
288 GNUNET_PQ_cleanup_result (rs);
289 return;
290 }
291 GNUNET_PQ_cleanup_result (rs);
292 }
293}
294
295
296/**
297 * Iterate over the results for a particular key
298 * in the datastore.
299 *
300 * @param cls closure (our `struct Plugin`)
301 * @param key key to look for
302 * @param type entries of which type are relevant?
303 * @param iter maybe NULL (to just count)
304 * @param iter_cls closure for @a iter
305 * @return the number of results found
306 */
307static unsigned int
308postgres_plugin_get (void *cls,
309 const struct GNUNET_HashCode *key,
310 enum GNUNET_BLOCK_Type type,
311 GNUNET_DATACACHE_Iterator iter,
312 void *iter_cls)
313{
314 struct Plugin *plugin = cls;
315 uint32_t type32 = (uint32_t) type;
316 struct GNUNET_TIME_Absolute now = { 0 };
317 struct GNUNET_PQ_QueryParam paramk[] = {
318 GNUNET_PQ_query_param_auto_from_type (key),
319 GNUNET_PQ_query_param_absolute_time (&now),
320 GNUNET_PQ_query_param_end
321 };
322 struct GNUNET_PQ_QueryParam paramkt[] = {
323 GNUNET_PQ_query_param_auto_from_type (key),
324 GNUNET_PQ_query_param_uint32 (&type32),
325 GNUNET_PQ_query_param_absolute_time (&now),
326 GNUNET_PQ_query_param_end
327 };
328 enum GNUNET_DB_QueryStatus res;
329 struct HandleResultContext hr_ctx;
330
331 now = GNUNET_TIME_absolute_get ();
332 hr_ctx.iter = iter;
333 hr_ctx.iter_cls = iter_cls;
334 hr_ctx.key = key;
335 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
336 (0 == type) ? "getk" : "getkt",
337 (0 == type) ? paramk : paramkt,
338 &handle_results,
339 &hr_ctx);
340 if (res < 0)
341 return 0;
342 return res;
343}
344
345
346/**
347 * Delete the entry with the lowest expiration value
348 * from the datacache right now.
349 *
350 * @param cls closure (our `struct Plugin`)
351 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
352 */
353static enum GNUNET_GenericReturnValue
354postgres_plugin_del (void *cls)
355{
356 struct Plugin *plugin = cls;
357 struct GNUNET_PQ_QueryParam pempty[] = {
358 GNUNET_PQ_query_param_end
359 };
360 uint32_t size;
361 uint32_t oid;
362 struct GNUNET_HashCode key;
363 struct GNUNET_PQ_ResultSpec rs[] = {
364 GNUNET_PQ_result_spec_uint32 ("len",
365 &size),
366 GNUNET_PQ_result_spec_uint32 ("oid",
367 &oid),
368 GNUNET_PQ_result_spec_auto_from_type ("key",
369 &key),
370 GNUNET_PQ_result_spec_end
371 };
372 enum GNUNET_DB_QueryStatus res;
373 struct GNUNET_PQ_QueryParam dparam[] = {
374 GNUNET_PQ_query_param_uint32 (&oid),
375 GNUNET_PQ_query_param_end
376 };
377 struct GNUNET_TIME_Absolute now;
378 struct GNUNET_PQ_QueryParam xparam[] = {
379 GNUNET_PQ_query_param_absolute_time (&now),
380 GNUNET_PQ_query_param_end
381 };
382
383 now = GNUNET_TIME_absolute_get ();
384 res = GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh,
385 "getex",
386 xparam,
387 rs);
388 if (0 >= res)
389 res = GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh,
390 "getm",
391 pempty,
392 rs);
393 if (0 > res)
394 return GNUNET_SYSERR;
395 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res)
396 {
397 /* no result */
398 LOG (GNUNET_ERROR_TYPE_DEBUG,
399 "Ending iteration (no more results)\n");
400 return 0;
401 }
402 res = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
403 "delrow",
404 dparam);
405 if (0 > res)
406 {
407 GNUNET_PQ_cleanup_result (rs);
408 return GNUNET_SYSERR;
409 }
410 plugin->num_items--;
411 plugin->env->delete_notify (plugin->env->cls,
412 &key,
413 size + OVERHEAD);
414 GNUNET_PQ_cleanup_result (rs);
415 return GNUNET_OK;
416}
417
418
419/**
420 * Closure for #extract_result_cb.
421 */
422struct ExtractResultContext
423{
424 /**
425 * Function to call for each result found.
426 */
427 GNUNET_DATACACHE_Iterator iter;
428
429 /**
430 * Closure for @e iter.
431 */
432 void *iter_cls;
433};
434
435
436/**
437 * Function to be called with the results of a SELECT statement
438 * that has returned @a num_results results. Calls the `iter`
439 * from @a cls for each result.
440 *
441 * @param cls closure with the `struct ExtractResultContext`
442 * @param result the postgres result
443 * @param num_result the number of results in @a result
444 */
445static void
446extract_result_cb (void *cls,
447 PGresult *result,
448 unsigned int num_results)
449{
450 struct ExtractResultContext *erc = cls;
451
452 if (NULL == erc->iter)
453 return;
454 for (unsigned int i = 0; i < num_results; i++)
455 {
456 uint32_t type32;
457 uint32_t bro32;
458 struct GNUNET_DATACACHE_Block block;
459 void *data;
460 void *path;
461 size_t path_size;
462 struct GNUNET_PQ_ResultSpec rs[] = {
463 GNUNET_PQ_result_spec_absolute_time ("expiration_time",
464 &block.expiration_time),
465 GNUNET_PQ_result_spec_uint32 ("type",
466 &type32),
467 GNUNET_PQ_result_spec_uint32 ("ro",
468 &bro32),
469 GNUNET_PQ_result_spec_variable_size ("value",
470 &data,
471 &block.data_size),
472 GNUNET_PQ_result_spec_auto_from_type ("trunc",
473 &block.trunc_peer),
474 GNUNET_PQ_result_spec_variable_size ("path",
475 &path,
476 &path_size),
477 GNUNET_PQ_result_spec_auto_from_type ("key",
478 &block.key),
479 GNUNET_PQ_result_spec_end
480 };
481
482 if (GNUNET_YES !=
483 GNUNET_PQ_extract_result (result,
484 rs,
485 i))
486 {
487 GNUNET_break (0);
488 return;
489 }
490 if (0 != (path_size % sizeof(struct GNUNET_DHT_PathElement)))
491 {
492 GNUNET_break (0);
493 path_size = 0;
494 path = NULL;
495 }
496 block.type = (enum GNUNET_BLOCK_Type) type32;
497 block.ro = (enum GNUNET_DHT_RouteOption) bro32;
498 block.data = data;
499 block.put_path = path;
500 block.put_path_length = path_size / sizeof (struct GNUNET_DHT_PathElement);
501 LOG (GNUNET_ERROR_TYPE_DEBUG,
502 "Found result of size %u bytes and type %u in database\n",
503 (unsigned int) block.data_size,
504 (unsigned int) block.type);
505 if ( (NULL != erc->iter) &&
506 (GNUNET_SYSERR ==
507 erc->iter (erc->iter_cls,
508 &block)) )
509 {
510 LOG (GNUNET_ERROR_TYPE_DEBUG,
511 "Ending iteration (client error)\n");
512 GNUNET_PQ_cleanup_result (rs);
513 break;
514 }
515 GNUNET_PQ_cleanup_result (rs);
516 }
517}
518
519
520/**
521 * Iterate over the results that are "close" to a particular key in
522 * the datacache. "close" is defined as numerically larger than @a
523 * key (when interpreted as a circular address space), with small
524 * distance.
525 *
526 * @param cls closure (internal context for the plugin)
527 * @param key area of the keyspace to look into
528 * @param type desired block type for the replies
529 * @param num_results number of results that should be returned to @a iter
530 * @param iter maybe NULL (to just count)
531 * @param iter_cls closure for @a iter
532 * @return the number of results found
533 */
534static unsigned int
535postgres_plugin_get_closest (void *cls,
536 const struct GNUNET_HashCode *key,
537 enum GNUNET_BLOCK_Type type,
538 unsigned int num_results,
539 GNUNET_DATACACHE_Iterator iter,
540 void *iter_cls)
541{
542 struct Plugin *plugin = cls;
543 uint32_t num_results32 = (uint32_t) num_results;
544 uint32_t type32 = (uint32_t) type;
545 struct GNUNET_TIME_Absolute now;
546 struct GNUNET_PQ_QueryParam params[] = {
547 GNUNET_PQ_query_param_auto_from_type (key),
548 GNUNET_PQ_query_param_absolute_time (&now),
549 GNUNET_PQ_query_param_uint32 (&type32),
550 GNUNET_PQ_query_param_uint32 (&num_results32),
551 GNUNET_PQ_query_param_end
552 };
553 enum GNUNET_DB_QueryStatus res;
554 struct ExtractResultContext erc;
555
556 erc.iter = iter;
557 erc.iter_cls = iter_cls;
558 now = GNUNET_TIME_absolute_get ();
559 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
560 "get_closest",
561 params,
562 &extract_result_cb,
563 &erc);
564 if (0 > res)
565 {
566 LOG (GNUNET_ERROR_TYPE_DEBUG,
567 "Ending iteration (postgres error)\n");
568 return 0;
569 }
570 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res)
571 {
572 /* no result */
573 LOG (GNUNET_ERROR_TYPE_DEBUG,
574 "Ending iteration (no more results)\n");
575 return 0;
576 }
577 return res;
578}
579
580
581/**
582 * Entry point for the plugin.
583 *
584 * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironmnet`)
585 * @return the plugin's closure (our `struct Plugin`)
586 */
587void *
588libgnunet_plugin_datacache_postgres_init (void *cls)
589{
590 struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
591 struct GNUNET_DATACACHE_PluginFunctions *api;
592 struct Plugin *plugin;
593
594 plugin = GNUNET_new (struct Plugin);
595 plugin->env = env;
596
597 if (GNUNET_OK != init_connection (plugin))
598 {
599 GNUNET_free (plugin);
600 return NULL;
601 }
602
603 api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
604 api->cls = plugin;
605 api->get = &postgres_plugin_get;
606 api->put = &postgres_plugin_put;
607 api->del = &postgres_plugin_del;
608 api->get_closest = &postgres_plugin_get_closest;
609 LOG (GNUNET_ERROR_TYPE_INFO,
610 "Postgres datacache running\n");
611 return api;
612}
613
614
615/**
616 * Exit point from the plugin.
617 *
618 * @param cls closure (our `struct Plugin`)
619 * @return NULL
620 */
621void *
622libgnunet_plugin_datacache_postgres_done (void *cls)
623{
624 struct GNUNET_DATACACHE_PluginFunctions *api = cls;
625 struct Plugin *plugin = api->cls;
626
627 GNUNET_PQ_disconnect (plugin->dbh);
628 GNUNET_free (plugin);
629 GNUNET_free (api);
630 return NULL;
631}
632
633
634/* end of plugin_datacache_postgres.c */
diff --git a/src/datacache/plugin_datacache_sqlite.c b/src/datacache/plugin_datacache_sqlite.c
deleted file mode 100644
index 0753d87ce..000000000
--- a/src/datacache/plugin_datacache_sqlite.c
+++ /dev/null
@@ -1,1063 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2006, 2009, 2015, 2022 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file datacache/plugin_datacache_sqlite.c
23 * @brief sqlite for an implementation of a database backend for the datacache
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_datacache_plugin.h"
29#include "gnunet_sq_lib.h"
30#include <sqlite3.h>
31
32#define LOG(kind, ...) GNUNET_log_from (kind, "datacache-sqlite", __VA_ARGS__)
33
34#define LOG_STRERROR_FILE(kind, op, fn) \
35 GNUNET_log_from_strerror_file (kind, "datacache-sqlite", op, fn)
36
37
38/**
39 * How much overhead do we assume per entry in the
40 * datacache?
41 */
42#define OVERHEAD (sizeof(struct GNUNET_HashCode) + 36)
43
44/**
45 * Context for all functions in this plugin.
46 */
47struct Plugin
48{
49 /**
50 * Our execution environment.
51 */
52 struct GNUNET_DATACACHE_PluginEnvironment *env;
53
54 /**
55 * Handle to the sqlite database.
56 */
57 sqlite3 *dbh;
58
59 /**
60 * Filename used for the DB.
61 */
62 char *fn;
63
64 /**
65 * Prepared statement for #sqlite_plugin_put.
66 */
67 sqlite3_stmt *insert_stmt;
68
69 /**
70 * Prepared statement for #sqlite_plugin_get.
71 */
72 sqlite3_stmt *get_count_stmt;
73
74 /**
75 * Prepared statement for #sqlite_plugin_get.
76 */
77 sqlite3_stmt *get_count_any_stmt;
78
79 /**
80 * Prepared statement for #sqlite_plugin_get.
81 */
82 sqlite3_stmt *get_stmt;
83
84 /**
85 * Prepared statement for #sqlite_plugin_get.
86 */
87 sqlite3_stmt *get_any_stmt;
88
89 /**
90 * Prepared statement for #sqlite_plugin_del.
91 */
92 sqlite3_stmt *del_select_stmt;
93
94 /**
95 * Prepared statement for #sqlite_plugin_del.
96 */
97 sqlite3_stmt *del_expired_stmt;
98
99 /**
100 * Prepared statement for #sqlite_plugin_del.
101 */
102 sqlite3_stmt *del_stmt;
103
104 /**
105 * Prepared statement for #sqlite_plugin_get_closest.
106 */
107 sqlite3_stmt *get_closest_stmt;
108
109 /**
110 * Number of key-value pairs in the database.
111 */
112 unsigned int num_items;
113};
114
115
116/**
117 * Log an error message at log-level @a level that indicates
118 * a failure of the command @a cmd with the error from the database @a db
119 *
120 * @param db database handle
121 * @param level log level
122 * @param cmd failed command
123 */
124#define LOG_SQLITE(db, level, cmd) \
125 do \
126 { \
127 LOG (level, \
128 _ ("`%s' failed at %s:%d with error: %s\n"), \
129 cmd, \
130 __FILE__, \
131 __LINE__, \
132 sqlite3_errmsg (db)); \
133 } while (0)
134
135
136/**
137 * Execute SQL statement.
138 *
139 * @param db database handle
140 * @param cmd SQL command to execute
141 */
142#define SQLITE3_EXEC(db, cmd) \
143 do \
144 { \
145 emsg = NULL; \
146 if (SQLITE_OK != \
147 sqlite3_exec (db, cmd, NULL, NULL, &emsg)) \
148 { \
149 LOG (GNUNET_ERROR_TYPE_ERROR, \
150 _ ("`%s' failed at %s:%d with error: %s\n"), \
151 "sqlite3_exec", \
152 __FILE__, \
153 __LINE__, \
154 emsg); \
155 sqlite3_free (emsg); \
156 } \
157 } while (0)
158
159
160/**
161 * @brief Prepare a SQL statement
162 *
163 * @param dbh database handle
164 * @param zsql SQL statement text
165 * @param[out] ppStmt set to the prepared statement
166 * @return 0 on success
167 */
168static int
169sq_prepare (sqlite3 *dbh,
170 const char *zSql, /* SQL statement, UTF-8 encoded */
171 sqlite3_stmt **ppStmt)
172{ /* OUT: Statement handle */
173 char *dummy;
174
175 return sqlite3_prepare (dbh,
176 zSql,
177 strlen (zSql),
178 ppStmt,
179 (const char **) &dummy);
180}
181
182
183/**
184 * Store an item in the datastore.
185 *
186 * @param cls closure (our `struct Plugin`)
187 * @param xor_distance how close is @a key to our PID?
188 * @param block data to store
189 * @return 0 if duplicate, -1 on error, number of bytes used otherwise
190 */
191static ssize_t
192sqlite_plugin_put (void *cls,
193 uint32_t xor_distance,
194 const struct GNUNET_DATACACHE_Block *block)
195{
196 struct Plugin *plugin = cls;
197 uint32_t type32 = (uint32_t) block->type;
198 uint32_t ro32 = (uint32_t) block->ro;
199 struct GNUNET_SQ_QueryParam params[] = {
200 GNUNET_SQ_query_param_uint32 (&type32),
201 GNUNET_SQ_query_param_uint32 (&ro32),
202 GNUNET_SQ_query_param_absolute_time (&block->expiration_time),
203 GNUNET_SQ_query_param_auto_from_type (&block->key),
204 GNUNET_SQ_query_param_uint32 (&xor_distance),
205 GNUNET_SQ_query_param_fixed_size (block->data,
206 block->data_size),
207 GNUNET_SQ_query_param_fixed_size (block->put_path,
208 block->put_path_length
209 * sizeof(struct GNUNET_DHT_PathElement)),
210 GNUNET_SQ_query_param_auto_from_type (&block->trunc_peer),
211 GNUNET_SQ_query_param_end
212 };
213
214 LOG (GNUNET_ERROR_TYPE_DEBUG,
215 "Processing PUT of %u bytes with key `%s' and expiration %s\n",
216 (unsigned int) block->data_size,
217 GNUNET_h2s (&block->key),
218 GNUNET_STRINGS_relative_time_to_string (
219 GNUNET_TIME_absolute_get_remaining (
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,
227 GNUNET_ERROR_TYPE_ERROR,
228 "sqlite3_bind_xxx");
229 GNUNET_SQ_reset (plugin->dbh,
230 plugin->insert_stmt);
231 return -1;
232 }
233 if (SQLITE_DONE !=
234 sqlite3_step (plugin->insert_stmt))
235 {
236 LOG_SQLITE (plugin->dbh,
237 GNUNET_ERROR_TYPE_ERROR,
238 "sqlite3_step");
239 GNUNET_SQ_reset (plugin->dbh,
240 plugin->insert_stmt);
241 return -1;
242 }
243 plugin->num_items++;
244 GNUNET_SQ_reset (plugin->dbh,
245 plugin->insert_stmt);
246 return block->data_size + OVERHEAD;
247}
248
249
250/**
251 * Iterate over the results for a particular key
252 * in the datastore.
253 *
254 * @param cls closure (our `struct Plugin`)
255 * @param key
256 * @param iter maybe NULL (to just count)
257 * @param iter_cls closure for @a iter
258 * @return the number of results found
259 */
260static unsigned int
261get_any (void *cls,
262 const struct GNUNET_HashCode *key,
263 GNUNET_DATACACHE_Iterator iter,
264 void *iter_cls)
265{
266 struct Plugin *plugin = cls;
267 struct GNUNET_TIME_Absolute now;
268 unsigned int cnt;
269 uint32_t off;
270 uint32_t btype32;
271 uint32_t bro32;
272 unsigned int total;
273 struct GNUNET_DATACACHE_Block block;
274 void *path;
275 void *data;
276 size_t path_size;
277 struct GNUNET_SQ_QueryParam params_count[] = {
278 GNUNET_SQ_query_param_auto_from_type (key),
279 GNUNET_SQ_query_param_absolute_time (&now),
280 GNUNET_SQ_query_param_end
281 };
282 struct GNUNET_SQ_QueryParam params_select[] = {
283 GNUNET_SQ_query_param_auto_from_type (key),
284 GNUNET_SQ_query_param_absolute_time (&now),
285 GNUNET_SQ_query_param_uint32 (&off),
286 GNUNET_SQ_query_param_end
287 };
288 struct GNUNET_SQ_ResultSpec rs[] = {
289 GNUNET_SQ_result_spec_variable_size (&data,
290 &block.data_size),
291 GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
292 GNUNET_SQ_result_spec_variable_size (&path,
293 &path_size),
294 GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
295 GNUNET_SQ_result_spec_uint32 (&btype32),
296 GNUNET_SQ_result_spec_uint32 (&bro32),
297 GNUNET_SQ_result_spec_end
298 };
299
300 now = GNUNET_TIME_absolute_get ();
301 LOG (GNUNET_ERROR_TYPE_DEBUG,
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,
310 GNUNET_ERROR_TYPE_ERROR,
311 "sqlite3_bind_xxx");
312 GNUNET_SQ_reset (plugin->dbh,
313 plugin->get_count_any_stmt);
314 return 0;
315 }
316 if (SQLITE_ROW !=
317 sqlite3_step (plugin->get_count_any_stmt))
318 {
319 LOG_SQLITE (plugin->dbh,
320 GNUNET_ERROR_TYPE_ERROR,
321 "sqlite_step");
322 GNUNET_SQ_reset (plugin->dbh,
323 plugin->get_count_any_stmt);
324 LOG (GNUNET_ERROR_TYPE_DEBUG,
325 "No content found when processing GET for key `%s'\n",
326 GNUNET_h2s (key));
327 return 0;
328 }
329 total = sqlite3_column_int (plugin->get_count_any_stmt,
330 0);
331 GNUNET_SQ_reset (plugin->dbh,
332 plugin->get_count_any_stmt);
333 if ( (0 == total) ||
334 (NULL == iter) )
335 {
336 if (0 == total)
337 LOG (GNUNET_ERROR_TYPE_DEBUG,
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;
345 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
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,
355 GNUNET_ERROR_TYPE_ERROR,
356 "sqlite3_bind_xxx");
357 GNUNET_SQ_reset (plugin->dbh,
358 plugin->get_any_stmt);
359 return cnt;
360 }
361 if (SQLITE_ROW !=
362 sqlite3_step (plugin->get_any_stmt))
363 break;
364 if (GNUNET_OK !=
365 GNUNET_SQ_extract_result (plugin->get_any_stmt,
366 rs))
367 {
368 GNUNET_break (0);
369 GNUNET_SQ_reset (plugin->dbh,
370 plugin->get_any_stmt);
371 break;
372 }
373 if (0 != path_size % sizeof(struct GNUNET_DHT_PathElement))
374 {
375 GNUNET_break (0);
376 path_size = 0;
377 path = NULL;
378 }
379 block.data = data;
380 block.put_path = path;
381 block.put_path_length = path_size / sizeof(struct GNUNET_DHT_PathElement);
382 block.type = (enum GNUNET_BLOCK_Type) btype32;
383 block.ro = (enum GNUNET_DHT_RouteOption) bro32;
384 cnt++;
385 LOG (GNUNET_ERROR_TYPE_DEBUG,
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 {
393 GNUNET_SQ_cleanup_result (rs);
394 GNUNET_SQ_reset (plugin->dbh,
395 plugin->get_any_stmt);
396 break;
397 }
398 GNUNET_SQ_cleanup_result (rs);
399 GNUNET_SQ_reset (plugin->dbh,
400 plugin->get_any_stmt);
401 }
402 GNUNET_SQ_reset (plugin->dbh,
403 plugin->get_any_stmt);
404 return cnt;
405}
406
407
408/**
409 * Iterate over the results for a particular key
410 * in the datastore.
411 *
412 * @param cls closure (our `struct Plugin`)
413 * @param key
414 * @param type entries of which type are relevant?
415 * @param iter maybe NULL (to just count)
416 * @param iter_cls closure for @a iter
417 * @return the number of results found
418 */
419static unsigned int
420get_typed (void *cls,
421 const struct GNUNET_HashCode *key,
422 enum GNUNET_BLOCK_Type type,
423 GNUNET_DATACACHE_Iterator iter,
424 void *iter_cls)
425{
426 struct Plugin *plugin = cls;
427 uint32_t type32 = type;
428 struct GNUNET_TIME_Absolute now;
429 unsigned int cnt;
430 uint32_t off;
431 uint32_t bro32;
432 unsigned int total;
433 struct GNUNET_DATACACHE_Block block;
434 void *path;
435 void *data;
436 size_t path_size;
437 struct GNUNET_SQ_QueryParam params_count[] = {
438 GNUNET_SQ_query_param_auto_from_type (key),
439 GNUNET_SQ_query_param_uint32 (&type32),
440 GNUNET_SQ_query_param_absolute_time (&now),
441 GNUNET_SQ_query_param_end
442 };
443 struct GNUNET_SQ_QueryParam params_select[] = {
444 GNUNET_SQ_query_param_auto_from_type (key),
445 GNUNET_SQ_query_param_uint32 (&type32),
446 GNUNET_SQ_query_param_absolute_time (&now),
447 GNUNET_SQ_query_param_uint32 (&off),
448 GNUNET_SQ_query_param_end
449 };
450 struct GNUNET_SQ_ResultSpec rs[] = {
451 GNUNET_SQ_result_spec_variable_size (&data,
452 &block.data_size),
453 GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
454 GNUNET_SQ_result_spec_variable_size (&path,
455 &path_size),
456 GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
457 GNUNET_SQ_result_spec_uint32 (&bro32),
458 GNUNET_SQ_result_spec_end
459 };
460
461 now = GNUNET_TIME_absolute_get ();
462 LOG (GNUNET_ERROR_TYPE_DEBUG,
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,
471 GNUNET_ERROR_TYPE_ERROR,
472 "sqlite3_bind_xxx");
473 GNUNET_SQ_reset (plugin->dbh,
474 plugin->get_count_stmt);
475 return 0;
476 }
477 if (SQLITE_ROW !=
478 sqlite3_step (plugin->get_count_stmt))
479 {
480 LOG_SQLITE (plugin->dbh,
481 GNUNET_ERROR_TYPE_ERROR,
482 "sqlite_step");
483 GNUNET_SQ_reset (plugin->dbh,
484 plugin->get_count_stmt);
485 LOG (GNUNET_ERROR_TYPE_DEBUG,
486 "No content found when processing GET for key `%s'\n",
487 GNUNET_h2s (key));
488 return 0;
489 }
490 total = sqlite3_column_int (plugin->get_count_stmt,
491 0);
492 GNUNET_SQ_reset (plugin->dbh,
493 plugin->get_count_stmt);
494 if ( (0 == total) ||
495 (NULL == iter) )
496 {
497 if (0 == total)
498 LOG (GNUNET_ERROR_TYPE_DEBUG,
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;
506 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
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,
516 GNUNET_ERROR_TYPE_ERROR,
517 "sqlite3_bind_xxx");
518 GNUNET_SQ_reset (plugin->dbh,
519 plugin->get_stmt);
520 return cnt;
521 }
522 if (SQLITE_ROW !=
523 sqlite3_step (plugin->get_stmt))
524 break;
525 if (GNUNET_OK !=
526 GNUNET_SQ_extract_result (plugin->get_stmt,
527 rs))
528 {
529 GNUNET_break (0);
530 GNUNET_SQ_reset (plugin->dbh,
531 plugin->get_stmt);
532 break;
533 }
534 if (0 != path_size % sizeof(struct GNUNET_DHT_PathElement))
535 {
536 GNUNET_break (0);
537 path_size = 0;
538 path = NULL;
539 }
540 block.data = data;
541 block.put_path = path;
542 block.put_path_length = path_size / sizeof(struct GNUNET_DHT_PathElement);
543 block.type = type;
544 block.ro = (enum GNUNET_DHT_RouteOption) bro32;
545 cnt++;
546 LOG (GNUNET_ERROR_TYPE_DEBUG,
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 {
555 GNUNET_SQ_cleanup_result (rs);
556 GNUNET_SQ_reset (plugin->dbh,
557 plugin->get_stmt);
558 break;
559 }
560 GNUNET_SQ_cleanup_result (rs);
561 GNUNET_SQ_reset (plugin->dbh,
562 plugin->get_stmt);
563 }
564 GNUNET_SQ_reset (plugin->dbh,
565 plugin->get_stmt);
566 return cnt;
567}
568
569
570/**
571 * Iterate over the results for a particular key
572 * in the datastore.
573 *
574 * @param cls closure (our `struct Plugin`)
575 * @param key
576 * @param type entries of which type are relevant?
577 * @param iter maybe NULL (to just count)
578 * @param iter_cls closure for @a iter
579 * @return the number of results found
580 */
581static unsigned int
582sqlite_plugin_get (void *cls,
583 const struct GNUNET_HashCode *key,
584 enum GNUNET_BLOCK_Type type,
585 GNUNET_DATACACHE_Iterator iter,
586 void *iter_cls)
587{
588 if (GNUNET_BLOCK_TYPE_ANY == type)
589 return get_any (cls,
590 key,
591 iter,
592 iter_cls);
593 return get_typed (cls,
594 key,
595 type,
596 iter,
597 iter_cls);
598}
599
600
601/**
602 * Delete the entry with the lowest expiration value
603 * from the datacache right now.
604 *
605 * @param cls closure (our `struct Plugin`)
606 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
607 */
608static enum GNUNET_GenericReturnValue
609sqlite_plugin_del (void *cls)
610{
611 struct Plugin *plugin = cls;
612 uint64_t rowid;
613 void *data;
614 size_t data_size;
615 struct GNUNET_HashCode hc;
616 struct GNUNET_TIME_Absolute now;
617 struct GNUNET_SQ_ResultSpec rs[] = {
618 GNUNET_SQ_result_spec_uint64 (&rowid),
619 GNUNET_SQ_result_spec_auto_from_type (&hc),
620 GNUNET_SQ_result_spec_variable_size (&data,
621 &data_size),
622 GNUNET_SQ_result_spec_end
623 };
624 struct GNUNET_SQ_QueryParam params[] = {
625 GNUNET_SQ_query_param_uint64 (&rowid),
626 GNUNET_SQ_query_param_end
627 };
628 struct GNUNET_SQ_QueryParam time_params[] = {
629 GNUNET_SQ_query_param_absolute_time (&now),
630 GNUNET_SQ_query_param_end
631 };
632
633 LOG (GNUNET_ERROR_TYPE_DEBUG,
634 "Processing DEL\n");
635 now = GNUNET_TIME_absolute_get ();
636 if (GNUNET_OK !=
637 GNUNET_SQ_bind (plugin->del_expired_stmt,
638 time_params))
639 {
640 LOG_SQLITE (plugin->dbh,
641 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
642 "sqlite3_bind");
643 GNUNET_SQ_reset (plugin->dbh,
644 plugin->del_expired_stmt);
645 return GNUNET_SYSERR;
646 }
647 if ( (SQLITE_ROW !=
648 sqlite3_step (plugin->del_expired_stmt)) ||
649 (GNUNET_OK !=
650 GNUNET_SQ_extract_result (plugin->del_expired_stmt,
651 rs)))
652 {
653 GNUNET_SQ_reset (plugin->dbh,
654 plugin->del_expired_stmt);
655 if (SQLITE_ROW !=
656 sqlite3_step (plugin->del_select_stmt))
657 {
658 LOG_SQLITE (plugin->dbh,
659 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
660 "sqlite3_step");
661 GNUNET_SQ_reset (plugin->dbh,
662 plugin->del_select_stmt);
663 return GNUNET_SYSERR;
664 }
665 if (GNUNET_OK !=
666 GNUNET_SQ_extract_result (plugin->del_select_stmt,
667 rs))
668 {
669 GNUNET_SQ_reset (plugin->dbh,
670 plugin->del_select_stmt);
671 GNUNET_break (0);
672 return GNUNET_SYSERR;
673 }
674 }
675 GNUNET_SQ_cleanup_result (rs);
676 GNUNET_SQ_reset (plugin->dbh,
677 plugin->del_select_stmt);
678 if (GNUNET_OK !=
679 GNUNET_SQ_bind (plugin->del_stmt,
680 params))
681 {
682 LOG_SQLITE (plugin->dbh,
683 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
684 "sqlite3_bind");
685 GNUNET_SQ_reset (plugin->dbh,
686 plugin->del_stmt);
687 return GNUNET_SYSERR;
688 }
689 if (SQLITE_DONE !=
690 sqlite3_step (plugin->del_stmt))
691 {
692 LOG_SQLITE (plugin->dbh,
693 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
694 "sqlite3_step");
695 GNUNET_SQ_reset (plugin->dbh,
696 plugin->del_stmt);
697 return GNUNET_SYSERR;
698 }
699 plugin->num_items--;
700 plugin->env->delete_notify (plugin->env->cls,
701 &hc,
702 data_size + OVERHEAD);
703 GNUNET_SQ_reset (plugin->dbh,
704 plugin->del_stmt);
705 return GNUNET_OK;
706}
707
708
709/**
710 * Iterate over the results that are "close" to a particular key in
711 * the datacache. "close" is defined as numerically larger than @a
712 * key (when interpreted as a circular address space), with small
713 * distance.
714 *
715 * @param cls closure (internal context for the plugin)
716 * @param key area of the keyspace to look into
717 * @param type desired block type for the replies
718 * @param num_results number of results that should be returned to @a iter
719 * @param iter maybe NULL (to just count)
720 * @param iter_cls closure for @a iter
721 * @return the number of results found
722 */
723static unsigned int
724sqlite_plugin_get_closest (void *cls,
725 const struct GNUNET_HashCode *key,
726 enum GNUNET_BLOCK_Type type,
727 unsigned int num_results,
728 GNUNET_DATACACHE_Iterator iter,
729 void *iter_cls)
730{
731 struct Plugin *plugin = cls;
732 uint32_t type32 = type;
733 uint32_t num_results32 = num_results;
734 struct GNUNET_TIME_Absolute now;
735 void *data;
736 void *path;
737 size_t path_size;
738 unsigned int cnt;
739 uint32_t bro32;
740 struct GNUNET_DATACACHE_Block block;
741 uint32_t rtype32;
742 struct GNUNET_SQ_QueryParam params[] = {
743 GNUNET_SQ_query_param_auto_from_type (key),
744 GNUNET_SQ_query_param_absolute_time (&now),
745 GNUNET_SQ_query_param_uint32 (&type32),
746 GNUNET_SQ_query_param_uint32 (&num_results32),
747 GNUNET_SQ_query_param_end
748 };
749 struct GNUNET_SQ_ResultSpec rs[] = {
750 GNUNET_SQ_result_spec_variable_size (&data,
751 &block.data_size),
752 GNUNET_SQ_result_spec_absolute_time (&block.expiration_time),
753 GNUNET_SQ_result_spec_variable_size (&path,
754 &path_size),
755 GNUNET_SQ_result_spec_auto_from_type (&block.trunc_peer),
756 GNUNET_SQ_result_spec_uint32 (&rtype32),
757 GNUNET_SQ_result_spec_uint32 (&bro32),
758 GNUNET_SQ_result_spec_auto_from_type (&block.key),
759 GNUNET_SQ_result_spec_end
760 };
761
762 now = GNUNET_TIME_absolute_get ();
763 LOG (GNUNET_ERROR_TYPE_DEBUG,
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,
771 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
772 "sqlite3_bind_xxx");
773 GNUNET_SQ_reset (plugin->dbh,
774 plugin->get_closest_stmt);
775 return 0;
776 }
777 cnt = 0;
778 while (SQLITE_ROW ==
779 sqlite3_step (plugin->get_closest_stmt))
780 {
781 if (GNUNET_OK !=
782 GNUNET_SQ_extract_result (plugin->get_closest_stmt,
783 rs))
784 {
785 GNUNET_break (0);
786 break;
787 }
788 if (0 != path_size % sizeof(struct GNUNET_DHT_PathElement))
789 {
790 GNUNET_break (0);
791 path_size = 0;
792 path = NULL;
793 }
794 block.put_path_length
795 = path_size / sizeof(struct GNUNET_DHT_PathElement);
796 block.put_path = path;
797 block.data = data;
798 block.type = (enum GNUNET_BLOCK_Type) rtype32;
799 block.ro = (enum GNUNET_DHT_RouteOption) bro32;
800 cnt++;
801 LOG (GNUNET_ERROR_TYPE_DEBUG,
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 {
810 GNUNET_SQ_cleanup_result (rs);
811 break;
812 }
813 GNUNET_SQ_cleanup_result (rs);
814 }
815 GNUNET_SQ_reset (plugin->dbh,
816 plugin->get_closest_stmt);
817 return cnt;
818}
819
820
821/**
822 * Entry point for the plugin.
823 *
824 * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironment`)
825 * @return the plugin's closure (our `struct Plugin`)
826 */
827void *
828libgnunet_plugin_datacache_sqlite_init (void *cls)
829{
830 struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
831 struct GNUNET_DATACACHE_PluginFunctions *api;
832 struct Plugin *plugin;
833 char *fn;
834 char *fn_utf8;
835 sqlite3 *dbh;
836 char *emsg;
837
838 if (GNUNET_YES ==
839 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
840 "datacache-sqlite",
841 "IN_MEMORY"))
842 {
843 if (SQLITE_OK !=
844 sqlite3_open (":memory:",
845 &dbh))
846 return NULL;
847 fn_utf8 = NULL;
848 }
849 else
850 {
851 fn = GNUNET_DISK_mktemp ("gnunet-datacache");
852 if (NULL == fn)
853 {
854 GNUNET_break (0);
855 return NULL;
856 }
857 /* fn should be UTF-8-encoded. If it isn't, it's a bug. */
858 fn_utf8 = GNUNET_strdup (fn);
859 if (SQLITE_OK !=
860 sqlite3_open (fn_utf8,
861 &dbh))
862 {
863 GNUNET_free (fn);
864 GNUNET_free (fn_utf8);
865 return NULL;
866 }
867 GNUNET_free (fn);
868 }
869
870 SQLITE3_EXEC (dbh, "PRAGMA temp_store=MEMORY");
871 SQLITE3_EXEC (dbh, "PRAGMA locking_mode=EXCLUSIVE");
872 SQLITE3_EXEC (dbh, "PRAGMA journal_mode=OFF");
873 SQLITE3_EXEC (dbh, "PRAGMA synchronous=OFF");
874 SQLITE3_EXEC (dbh, "PRAGMA page_size=4092");
875 if (GNUNET_YES ==
876 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
877 "datacache-sqlite",
878 "IN_MEMORY"))
879 SQLITE3_EXEC (dbh, "PRAGMA sqlite_temp_store=3");
880
881 SQLITE3_EXEC (dbh,
882 "CREATE TABLE ds180 ("
883 " type INTEGER NOT NULL DEFAULT 0,"
884 " ro INTEGER NOT NULL DEFAULT 0,"
885 " expire INTEGER NOT NULL,"
886 " key BLOB NOT NULL DEFAULT '',"
887 " prox INTEGER NOT NULL,"
888 " value BLOB NOT NULL,"
889 " trunc BLOB NOT NULL,"
890 " path BLOB DEFAULT '')");
891 SQLITE3_EXEC (dbh,
892 "CREATE INDEX idx_hashidx"
893 " ON ds180 (key,type,expire)");
894 SQLITE3_EXEC (dbh,
895 "CREATE INDEX idx_prox_expire"
896 " ON ds180 (prox,expire)");
897 SQLITE3_EXEC (dbh,
898 "CREATE INDEX idx_expire_only"
899 " ON ds180 (expire)");
900 plugin = GNUNET_new (struct Plugin);
901 plugin->env = env;
902 plugin->dbh = dbh;
903 plugin->fn = fn_utf8;
904
905 if ((SQLITE_OK !=
906 sq_prepare (plugin->dbh,
907 "INSERT INTO ds180"
908 " (type, ro, expire, key, prox, value, path, trunc)"
909 " VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
910 &plugin->insert_stmt)) ||
911 (SQLITE_OK !=
912 sq_prepare (plugin->dbh,
913 "SELECT COUNT(*) FROM ds180 "
914 "WHERE key=?"
915 " AND type=?"
916 " AND expire >= ?",
917 &plugin->get_count_stmt)) ||
918 (SQLITE_OK !=
919 sq_prepare (plugin->dbh,
920 "SELECT COUNT(*) FROM ds180 "
921 "WHERE key=? AND expire >= ?",
922 &plugin->get_count_any_stmt)) ||
923 (SQLITE_OK !=
924 sq_prepare (plugin->dbh,
925 "SELECT value,expire,path,trunc,ro"
926 " FROM ds180"
927 " WHERE key=?"
928 " AND type=?"
929 " AND expire >= ?"
930 " LIMIT 1 OFFSET ?",
931 &plugin->get_stmt)) ||
932 (SQLITE_OK !=
933 sq_prepare (plugin->dbh,
934 "SELECT value,expire,path,trunc,type,ro"
935 " FROM ds180"
936 " WHERE key=?"
937 " AND expire >= ?"
938 " LIMIT 1 OFFSET ?",
939 &plugin->get_any_stmt)) ||
940 (SQLITE_OK !=
941 sq_prepare (plugin->dbh,
942 "SELECT _ROWID_,key,value FROM ds180"
943 " WHERE expire < ?1"
944 " ORDER BY expire ASC LIMIT 1",
945 &plugin->del_expired_stmt)) ||
946 (SQLITE_OK !=
947 sq_prepare (plugin->dbh,
948 "SELECT _ROWID_,key,value FROM ds180"
949 " ORDER BY prox ASC, expire ASC LIMIT 1",
950 &plugin->del_select_stmt)) ||
951 (SQLITE_OK !=
952 sq_prepare (plugin->dbh,
953 "DELETE FROM ds180 WHERE _ROWID_=?",
954 &plugin->del_stmt)) ||
955 (SQLITE_OK !=
956 sq_prepare (plugin->dbh,
957 "SELECT * FROM ("
958 " SELECT value,expire,path,trunc,type,ro,key"
959 " FROM ds180 "
960 " WHERE key>=?1 "
961 " AND expire >= ?2"
962 " AND ( (type=?3) or (0 == ?3) )"
963 " ORDER BY KEY ASC LIMIT ?4)"
964 "UNION "
965 "SELECT * FROM ("
966 " SELECT value,expire,path,trunc,type,ro,key"
967 " FROM ds180 "
968 " WHERE key<=?1 "
969 " AND expire >= ?2"
970 " AND ( (type=?3) or (0 == ?3) )"
971 " ORDER BY KEY DESC LIMIT ?4)",
972 &plugin->get_closest_stmt)))
973 {
974 LOG_SQLITE (plugin->dbh,
975 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
976 "sq_prepare");
977 GNUNET_break (SQLITE_OK ==
978 sqlite3_close (plugin->dbh));
979 GNUNET_free (plugin);
980 return NULL;
981 }
982
983 api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
984 api->cls = plugin;
985 api->get = &sqlite_plugin_get;
986 api->put = &sqlite_plugin_put;
987 api->del = &sqlite_plugin_del;
988 api->get_closest = &sqlite_plugin_get_closest;
989 LOG (GNUNET_ERROR_TYPE_INFO,
990 "Sqlite datacache running\n");
991 return api;
992}
993
994
995/**
996 * Exit point from the plugin.
997 *
998 * @param cls closure (our `struct Plugin`)
999 * @return NULL
1000 */
1001void *
1002libgnunet_plugin_datacache_sqlite_done (void *cls)
1003{
1004 struct GNUNET_DATACACHE_PluginFunctions *api = cls;
1005 struct Plugin *plugin = api->cls;
1006 int result;
1007
1008#if SQLITE_VERSION_NUMBER >= 3007000
1009 sqlite3_stmt *stmt;
1010#endif
1011
1012#if ! WINDOWS || defined(__CYGWIN__)
1013 if ( (NULL != plugin->fn) &&
1014 (0 != unlink (plugin->fn)) )
1015 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
1016 "unlink",
1017 plugin->fn);
1018 GNUNET_free (plugin->fn);
1019#endif
1020 sqlite3_finalize (plugin->insert_stmt);
1021 sqlite3_finalize (plugin->get_count_stmt);
1022 sqlite3_finalize (plugin->get_count_any_stmt);
1023 sqlite3_finalize (plugin->get_stmt);
1024 sqlite3_finalize (plugin->get_any_stmt);
1025 sqlite3_finalize (plugin->del_select_stmt);
1026 sqlite3_finalize (plugin->del_expired_stmt);
1027 sqlite3_finalize (plugin->del_stmt);
1028 sqlite3_finalize (plugin->get_closest_stmt);
1029 result = sqlite3_close (plugin->dbh);
1030#if SQLITE_VERSION_NUMBER >= 3007000
1031 if (SQLITE_BUSY == result)
1032 {
1033 LOG (GNUNET_ERROR_TYPE_WARNING,
1034 _ (
1035 "Tried to close sqlite without finalizing all prepared statements.\n"));
1036 stmt = sqlite3_next_stmt (plugin->dbh,
1037 NULL);
1038 while (NULL != stmt)
1039 {
1040 result = sqlite3_finalize (stmt);
1041 if (result != SQLITE_OK)
1042 LOG (GNUNET_ERROR_TYPE_WARNING,
1043 "Failed to close statement %p: %d\n",
1044 stmt,
1045 result);
1046 stmt = sqlite3_next_stmt (plugin->dbh,
1047 NULL);
1048 }
1049 result = sqlite3_close (plugin->dbh);
1050 }
1051#endif
1052 if (SQLITE_OK != result)
1053 LOG_SQLITE (plugin->dbh,
1054 GNUNET_ERROR_TYPE_ERROR,
1055 "sqlite3_close");
1056
1057 GNUNET_free (plugin);
1058 GNUNET_free (api);
1059 return NULL;
1060}
1061
1062
1063/* end of plugin_datacache_sqlite.c */
diff --git a/src/datacache/plugin_datacache_template.c b/src/datacache/plugin_datacache_template.c
deleted file mode 100644
index 1bd712d39..000000000
--- a/src/datacache/plugin_datacache_template.c
+++ /dev/null
@@ -1,172 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2006, 2009, 2015, 2022 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file datacache/plugin_datacache_template.c
23 * @brief template for an implementation of a database backend for the datacache
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_datacache_plugin.h"
29
30
31/**
32 * Context for all functions in this plugin.
33 */
34struct Plugin
35{
36 /**
37 * Our execution environment.
38 */
39 struct GNUNET_DATACACHE_PluginEnvironment *env;
40};
41
42
43/**
44 * Store an item in the datastore.
45 *
46 * @param cls closure (our `struct Plugin`)
47 * @param xor_distance distance of @a key to our PID
48 * @param block data to store
49 * @return 0 if duplicate, -1 on error, number of bytes used otherwise
50 */
51static ssize_t
52template_plugin_put (void *cls,
53 uint32_t xor_distance,
54 const struct GNUNET_DATACACHE_Block *block)
55{
56 GNUNET_break (0);
57 return -1;
58}
59
60
61/**
62 * Iterate over the results for a particular key
63 * in the datastore.
64 *
65 * @param cls closure (our `struct Plugin`)
66 * @param key
67 * @param type entries of which type are relevant?
68 * @param iter maybe NULL (to just count)
69 * @param iter_cls closure for @a iter
70 * @return the number of results found
71 */
72static unsigned int
73template_plugin_get (void *cls,
74 const struct GNUNET_HashCode *key,
75 enum GNUNET_BLOCK_Type type,
76 GNUNET_DATACACHE_Iterator iter,
77 void *iter_cls)
78{
79 GNUNET_break (0);
80 return 0;
81}
82
83
84/**
85 * Delete the entry with the lowest expiration value
86 * from the datacache right now.
87 *
88 * @param cls closure (our `struct Plugin`)
89 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
90 */
91static enum GNUNET_GenericReturnValue
92template_plugin_del (void *cls)
93{
94 GNUNET_break (0);
95 return GNUNET_SYSERR;
96}
97
98
99/**
100 * Iterate over the results that are "close" to a particular key in
101 * the datacache. "close" is defined as numerically larger than @a
102 * key (when interpreted as a circular address space), with small
103 * distance.
104 *
105 * @param cls closure (internal context for the plugin)
106 * @param key area of the keyspace to look into
107 * @param type desired block type for the replies
108 * @param num_results number of results that should be returned to @a iter
109 * @param iter maybe NULL (to just count)
110 * @param iter_cls closure for @a iter
111 * @return the number of results found
112 */
113static unsigned int
114template_plugin_get_closest (void *cls,
115 const struct GNUNET_HashCode *key,
116 enum GNUNET_BLOCK_Type type,
117 unsigned int num_results,
118 GNUNET_DATACACHE_Iterator iter,
119 void *iter_cls)
120{
121 GNUNET_break (0);
122 return 0;
123}
124
125
126/**
127 * Entry point for the plugin.
128 *
129 * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironmnet`)
130 * @return the plugin's closure (our `struct Plugin`)
131 */
132void *
133libgnunet_plugin_datacache_template_init (void *cls)
134{
135 struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
136 struct GNUNET_DATACACHE_PluginFunctions *api;
137 struct Plugin *plugin;
138
139 plugin = GNUNET_new (struct Plugin);
140 plugin->env = env;
141 api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
142 api->cls = plugin;
143 api->get = &template_plugin_get;
144 api->put = &template_plugin_put;
145 api->del = &template_plugin_del;
146 api->get_closest = &template_plugin_get_closest;
147 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
148 "template",
149 "Template datacache running\n");
150 return api;
151}
152
153
154/**
155 * Exit point from the plugin.
156 *
157 * @param cls closure (our `struct Plugin`)
158 * @return NULL
159 */
160void *
161libgnunet_plugin_datacache_template_done (void *cls)
162{
163 struct GNUNET_DATACACHE_PluginFunctions *api = cls;
164 struct Plugin *plugin = api->cls;
165
166 GNUNET_free (plugin);
167 GNUNET_free (api);
168 return NULL;
169}
170
171
172/* end of plugin_datacache_template.c */
diff --git a/src/datacache/test_datacache.c b/src/datacache/test_datacache.c
deleted file mode 100644
index fd5a5f54c..000000000
--- a/src/datacache/test_datacache.c
+++ /dev/null
@@ -1,205 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2009, 2010, 2022 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/*
21 * @file datacache/test_datacache.c
22 * @brief Test for the datacache implementations.
23 * @author Nils Durner
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_datacache_lib.h"
28#include "gnunet_testing_lib.h"
29
30#define ASSERT(x) do { if (! (x)) { printf ("Error at %s:%d\n", __FILE__, \
31 __LINE__); goto FAILURE; \
32 } } while (0)
33
34static int ok;
35
36/**
37 * Name of plugin under test.
38 */
39static const char *plugin_name;
40
41
42static enum GNUNET_GenericReturnValue
43checkIt (void *cls,
44 const struct GNUNET_DATACACHE_Block *block)
45{
46 if (block->data_size != sizeof(struct GNUNET_HashCode))
47 {
48 GNUNET_break (0);
49 ok = 2;
50 }
51 if (0 != memcmp (block->data,
52 cls,
53 block->data_size))
54 {
55 GNUNET_break (0);
56 ok = 3;
57 }
58 return GNUNET_OK;
59}
60
61
62static void
63run (void *cls,
64 char *const *args,
65 const char *cfgfile,
66 const struct GNUNET_CONFIGURATION_Handle *cfg)
67{
68 struct GNUNET_DATACACHE_Handle *h;
69 struct GNUNET_DATACACHE_Block block;
70 struct GNUNET_HashCode k;
71 struct GNUNET_HashCode n;
72
73 (void) cls;
74 (void) args;
75 (void) cfgfile;
76 ok = 0;
77 h = GNUNET_DATACACHE_create (cfg,
78 "testcache");
79 if (NULL == h)
80 {
81 fprintf (stderr,
82 "%s",
83 "Failed to initialize datacache. Database likely not setup, skipping test.\n");
84 ok = 77; /* mark test as skipped */
85 return;
86 }
87 block.expiration_time = GNUNET_TIME_absolute_get ();
88 block.expiration_time.abs_value_us += 5 * 60 * 1000 * 1000LL;
89 memset (&k,
90 0,
91 sizeof(struct GNUNET_HashCode));
92 for (unsigned int i = 0; i < 100; i++)
93 {
94 GNUNET_CRYPTO_hash (&k,
95 sizeof(struct GNUNET_HashCode),
96 &n);
97 block.key = k;
98 block.data = &n;
99 block.data_size = sizeof (n);
100 memset (&block.trunc_peer,
101 43,
102 sizeof (block.trunc_peer));
103 block.ro = 42;
104 block.type = (enum GNUNET_BLOCK_Type) (1 + i % 16);
105 block.put_path = NULL;
106 block.put_path_length = 0;
107 block.ro = GNUNET_DHT_RO_RECORD_ROUTE;
108 ASSERT (GNUNET_OK ==
109 GNUNET_DATACACHE_put (h,
110 42,
111 &block));
112 k = n;
113 }
114 memset (&k,
115 0,
116 sizeof(struct GNUNET_HashCode));
117 for (unsigned int i = 0; i < 100; i++)
118 {
119 GNUNET_CRYPTO_hash (&k,
120 sizeof(struct GNUNET_HashCode),
121 &n);
122 ASSERT (1 == GNUNET_DATACACHE_get (h,
123 &k,
124 (enum GNUNET_BLOCK_Type) (1 + i % 16),
125 &checkIt,
126 &n));
127 k = n;
128 }
129
130 memset (&k,
131 42,
132 sizeof(struct GNUNET_HashCode));
133 GNUNET_CRYPTO_hash (&k,
134 sizeof(struct GNUNET_HashCode),
135 &n);
136 block.key = k;
137 block.data = &n;
138 block.data_size = sizeof (n);
139 block.ro = 42;
140 memset (&block.trunc_peer,
141 44,
142 sizeof (block.trunc_peer));
143 block.type = (enum GNUNET_BLOCK_Type) 792;
144 block.put_path = NULL;
145 block.put_path_length = 0;
146 block.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS;
147 block.ro = GNUNET_DHT_RO_RECORD_ROUTE;
148 ASSERT (GNUNET_OK ==
149 GNUNET_DATACACHE_put (h,
150 42,
151 &block));
152 ASSERT (0 != GNUNET_DATACACHE_get (h,
153 &k,
154 792,
155 &checkIt,
156 &n));
157 GNUNET_DATACACHE_destroy (h);
158 ASSERT (ok == 0);
159 return;
160FAILURE:
161 if (h != NULL)
162 GNUNET_DATACACHE_destroy (h);
163 ok = GNUNET_SYSERR;
164}
165
166
167int
168main (int argc, char *argv[])
169{
170 char cfg_name[PATH_MAX];
171 char *const xargv[] = {
172 "test-datacache",
173 "-c",
174 cfg_name,
175 NULL
176 };
177 struct GNUNET_GETOPT_CommandLineOption options[] = {
178 GNUNET_GETOPT_OPTION_END
179 };
180
181 (void) argc;
182 GNUNET_log_setup ("test-datacache",
183 "WARNING",
184 NULL);
185 plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
186 GNUNET_snprintf (cfg_name,
187 sizeof(cfg_name),
188 "test_datacache_data_%s.conf",
189 plugin_name);
190 GNUNET_PROGRAM_run ((sizeof(xargv) / sizeof(char *)) - 1,
191 xargv,
192 "test-datacache",
193 "nohelp",
194 options,
195 &run,
196 NULL);
197 if ((0 != ok) && (77 != ok))
198 fprintf (stderr,
199 "Missed some testcases: %d\n",
200 ok);
201 return ok;
202}
203
204
205/* end of test_datacache.c */
diff --git a/src/datacache/test_datacache_data_heap.conf b/src/datacache/test_datacache_data_heap.conf
deleted file mode 100644
index 082cf48f4..000000000
--- a/src/datacache/test_datacache_data_heap.conf
+++ /dev/null
@@ -1,4 +0,0 @@
1[testcache]
2QUOTA = 1 MB
3DATABASE = heap
4
diff --git a/src/datacache/test_datacache_data_postgres.conf b/src/datacache/test_datacache_data_postgres.conf
deleted file mode 100644
index 92313157c..000000000
--- a/src/datacache/test_datacache_data_postgres.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1
2[testcache]
3QUOTA = 1 MB
4DATABASE = postgres
5
6[datacache-postgres]
7CONFIG = postgres:///gnunetcheck
diff --git a/src/datacache/test_datacache_data_sqlite.conf b/src/datacache/test_datacache_data_sqlite.conf
deleted file mode 100644
index bf6ce1b2b..000000000
--- a/src/datacache/test_datacache_data_sqlite.conf
+++ /dev/null
@@ -1,5 +0,0 @@
1[testcache]
2QUOTA = 1 MB
3DATABASE = sqlite
4
5
diff --git a/src/datacache/test_datacache_quota.c b/src/datacache/test_datacache_quota.c
deleted file mode 100644
index 994147a64..000000000
--- a/src/datacache/test_datacache_quota.c
+++ /dev/null
@@ -1,193 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2009, 2010, 2022 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/*
21 * @file datacache/test_datacache_quota.c
22 * @brief Test for the quota code of the datacache implementations.
23 * @author Nils Durner
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_datacache_lib.h"
28#include "gnunet_testing_lib.h"
29
30#define ASSERT(x) do { if (! (x)) { printf ("Error at %s:%d\n", __FILE__, \
31 __LINE__); goto FAILURE; \
32 } } while (0)
33
34static int ok;
35
36/**
37 * Name of plugin under test.
38 */
39static const char *plugin_name;
40
41/**
42 * Quota is 1 MB. Each iteration of the test puts in about 1 MB of
43 * data. We do 10 iterations. Afterwards we check that the data from
44 * the first 5 iterations has all been discarded and that at least
45 * some of the data from the last iteration is still there.
46 */
47static void
48run (void *cls,
49 char *const *args,
50 const char *cfgfile,
51 const struct GNUNET_CONFIGURATION_Handle *cfg)
52{
53 struct GNUNET_DATACACHE_Handle *h;
54 struct GNUNET_HashCode k;
55 struct GNUNET_HashCode n;
56 struct GNUNET_DATACACHE_Block block;
57 char buf[3200];
58
59 (void) cls;
60 (void) args;
61 (void) cfgfile;
62 ok = 0;
63 h = GNUNET_DATACACHE_create (cfg,
64 "testcache");
65
66 if (h == NULL)
67 {
68 fprintf (stderr,
69 "%s",
70 "Failed to initialize datacache. Database likely not setup, skipping test.\n");
71 return;
72 }
73 block.expiration_time = GNUNET_TIME_relative_to_absolute (
74 GNUNET_TIME_UNIT_HOURS);
75 memset (buf,
76 1,
77 sizeof(buf));
78 memset (&k,
79 0,
80 sizeof(struct GNUNET_HashCode));
81 for (unsigned int i = 0; i < 10; i++)
82 {
83 fprintf (stderr,
84 "%s",
85 ".");
86 GNUNET_CRYPTO_hash (&k,
87 sizeof(struct GNUNET_HashCode),
88 &n);
89 for (unsigned int j = i; j < sizeof(buf); j += 10)
90 {
91 buf[j] = i;
92 block.key = k;
93 block.data = buf;
94 block.data_size = j;
95 memset (&block.trunc_peer,
96 43,
97 sizeof (block.trunc_peer));
98 block.ro = 42;
99 block.type = (enum GNUNET_BLOCK_Type) (1 + i);
100 block.put_path = NULL;
101 block.put_path_length = 0;
102 block.ro = GNUNET_DHT_RO_RECORD_ROUTE;
103 block.expiration_time.abs_value_us++;
104 ASSERT (GNUNET_OK ==
105 GNUNET_DATACACHE_put (h,
106 42,
107 &block));
108 ASSERT (0 < GNUNET_DATACACHE_get (h,
109 &k,
110 1 + i,
111 NULL,
112 NULL));
113 }
114 k = n;
115 }
116 fprintf (stderr, "%s", "\n");
117 memset (&k,
118 0,
119 sizeof(struct GNUNET_HashCode));
120 for (unsigned int i = 0; i < 10; i++)
121 {
122 fprintf (stderr, "%s", ".");
123 GNUNET_CRYPTO_hash (&k,
124 sizeof(struct GNUNET_HashCode),
125 &n);
126 if (i < 2)
127 ASSERT (0 ==
128 GNUNET_DATACACHE_get (h,
129 &k,
130 1 + i,
131 NULL,
132 NULL));
133 if (i == 9)
134 ASSERT (0 < GNUNET_DATACACHE_get (h,
135 &k,
136 1 + i,
137 NULL,
138 NULL));
139 k = n;
140 }
141 fprintf (stderr,
142 "%s",
143 "\n");
144 GNUNET_DATACACHE_destroy (h);
145 return;
146FAILURE:
147 if (h != NULL)
148 GNUNET_DATACACHE_destroy (h);
149 ok = GNUNET_SYSERR;
150}
151
152
153int
154main (int argc,
155 char *argv[])
156{
157 char cfg_name[PATH_MAX];
158 char *const xargv[] = {
159 "test-datacache-quota",
160 "-c",
161 cfg_name,
162 NULL
163 };
164 struct GNUNET_GETOPT_CommandLineOption options[] = {
165 GNUNET_GETOPT_OPTION_END
166 };
167
168 (void) argc;
169 GNUNET_log_setup ("test-datacache-quota",
170 "WARNING",
171 NULL);
172
173 plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
174 GNUNET_snprintf (cfg_name,
175 sizeof(cfg_name),
176 "test_datacache_data_%s.conf",
177 plugin_name);
178 GNUNET_PROGRAM_run ((sizeof(xargv) / sizeof(char *)) - 1,
179 xargv,
180 "test-datacache-quota",
181 "nohelp",
182 options,
183 &run,
184 NULL);
185 if (0 != ok)
186 fprintf (stderr,
187 "Missed some testcases: %d\n",
188 ok);
189 return ok;
190}
191
192
193/* end of test_datacache_quota.c */