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.c371
-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.c593
-rw-r--r--src/datacache/plugin_datacache_postgres.c631
-rw-r--r--src/datacache/plugin_datacache_sqlite.c747
-rw-r--r--src/datacache/plugin_datacache_template.c184
-rw-r--r--src/datacache/test_datacache.c195
-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.c164
17 files changed, 0 insertions, 3298 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 761ab801f..000000000
--- a/src/datacache/datacache.c
+++ /dev/null
@@ -1,371 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2015 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 const struct GNUNET_HashCode *key,
263 uint32_t xor_distance,
264 size_t data_size,
265 const char *data,
266 enum GNUNET_BLOCK_Type type,
267 struct GNUNET_TIME_Absolute discard_time,
268 unsigned int path_info_len,
269 const struct GNUNET_DHT_PathElement *path_info)
270{
271 ssize_t used;
272
273 used = h->api->put (h->api->cls,
274 key,
275 xor_distance,
276 data_size,
277 data,
278 type,
279 discard_time,
280 path_info_len,
281 path_info);
282 if (-1 == used)
283 {
284 GNUNET_break (0);
285 return GNUNET_SYSERR;
286 }
287 if (0 == used)
288 {
289 /* duplicate */
290 return GNUNET_NO;
291 }
292 LOG (GNUNET_ERROR_TYPE_DEBUG,
293 "Stored data under key `%s' in cache\n",
294 GNUNET_h2s (key));
295 if (NULL != h->filter)
296 GNUNET_CONTAINER_bloomfilter_add (h->filter,
297 key);
298 GNUNET_STATISTICS_update (h->stats,
299 "# bytes stored",
300 used,
301 GNUNET_NO);
302 GNUNET_STATISTICS_update (h->stats,
303 "# items stored",
304 1,
305 GNUNET_NO);
306 while (h->utilization + used > h->env.quota)
307 GNUNET_assert (GNUNET_OK ==
308 h->api->del (h->api->cls));
309 h->utilization += used;
310 return GNUNET_OK;
311}
312
313
314unsigned int
315GNUNET_DATACACHE_get (struct GNUNET_DATACACHE_Handle *h,
316 const struct GNUNET_HashCode *key,
317 enum GNUNET_BLOCK_Type type,
318 GNUNET_DATACACHE_Iterator iter,
319 void *iter_cls)
320{
321 GNUNET_STATISTICS_update (h->stats,
322 "# requests received",
323 1,
324 GNUNET_NO);
325 LOG (GNUNET_ERROR_TYPE_DEBUG,
326 "Processing request for key `%s'\n",
327 GNUNET_h2s (key));
328 if ((NULL != h->filter) &&
329 (GNUNET_OK !=
330 GNUNET_CONTAINER_bloomfilter_test (h->filter, key)))
331 {
332 GNUNET_STATISTICS_update (h->stats,
333 "# requests filtered by bloom filter",
334 1,
335 GNUNET_NO);
336 LOG (GNUNET_ERROR_TYPE_DEBUG,
337 "Bloomfilter filters request for key `%s'\n",
338 GNUNET_h2s (key));
339 return 0; /* can not be present */
340 }
341 return h->api->get (h->api->cls,
342 key,
343 type,
344 iter, iter_cls);
345}
346
347
348unsigned int
349GNUNET_DATACACHE_get_closest (struct GNUNET_DATACACHE_Handle *h,
350 const struct GNUNET_HashCode *key,
351 enum GNUNET_BLOCK_Type type,
352 unsigned int num_results,
353 GNUNET_DATACACHE_Iterator iter,
354 void *iter_cls)
355{
356 GNUNET_STATISTICS_update (h->stats,
357 "# proximity search requests received",
358 1,
359 GNUNET_NO);
360 LOG (GNUNET_ERROR_TYPE_DEBUG,
361 "Processing proximity search at `%s'\n",
362 GNUNET_h2s (key));
363 return h->api->get_closest (h->api->cls,
364 key,
365 type,
366 num_results,
367 iter, iter_cls);
368}
369
370
371/* 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 5b50468a5..000000000
--- a/src/datacache/plugin_datacache_heap.c
+++ /dev/null
@@ -1,593 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2012, 2015 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 * Key for the entry.
67 */
68 struct GNUNET_HashCode key;
69
70 /**
71 * Expiration time.
72 */
73 struct GNUNET_TIME_Absolute discard_time;
74
75 /**
76 * Corresponding node in the heap.
77 */
78 struct GNUNET_CONTAINER_HeapNode *hn;
79
80 /**
81 * Path information.
82 */
83 struct GNUNET_DHT_PathElement *path_info;
84
85 /**
86 * Payload (actual payload follows this struct)
87 */
88 size_t size;
89
90 /**
91 * Number of entries in @e path_info.
92 */
93 unsigned int path_info_len;
94
95 /**
96 * How close is the hash to us? Determines which heap we are in!
97 */
98 uint32_t distance;
99
100 /**
101 * Type of the block.
102 */
103 enum GNUNET_BLOCK_Type type;
104};
105
106
107#define OVERHEAD (sizeof(struct Value) + 64)
108
109
110/**
111 * Closure for #put_cb().
112 */
113struct PutContext
114{
115 /**
116 * Expiration time for the new value.
117 */
118 struct GNUNET_TIME_Absolute discard_time;
119
120 /**
121 * Data for the new value.
122 */
123 const char *data;
124
125 /**
126 * Path information.
127 */
128 const struct GNUNET_DHT_PathElement *path_info;
129
130 /**
131 * Number of bytes in @e data.
132 */
133 size_t size;
134
135 /**
136 * Type of the node.
137 */
138 enum GNUNET_BLOCK_Type type;
139
140 /**
141 * Number of entries in @e path_info.
142 */
143 unsigned int path_info_len;
144
145 /**
146 * Value to set to #GNUNET_YES if an equivalent block was found.
147 */
148 int found;
149};
150
151
152/**
153 * Function called during PUT to detect if an equivalent block
154 * already exists.
155 *
156 * @param cls the `struct PutContext`
157 * @param key the key for the value(s)
158 * @param value an existing value
159 * @return #GNUNET_YES if not found (to continue to iterate)
160 */
161static enum GNUNET_GenericReturnValue
162put_cb (void *cls,
163 const struct GNUNET_HashCode *key,
164 void *value)
165{
166 struct PutContext *put_ctx = cls;
167 struct Value *val = value;
168
169 if ((val->size == put_ctx->size) &&
170 (val->type == put_ctx->type) &&
171 (0 == memcmp (&val[1],
172 put_ctx->data,
173 put_ctx->size)))
174 {
175 put_ctx->found = GNUNET_YES;
176 val->discard_time = GNUNET_TIME_absolute_max (val->discard_time,
177 put_ctx->discard_time);
178 /* replace old path with new path */
179 GNUNET_array_grow (val->path_info,
180 val->path_info_len,
181 put_ctx->path_info_len);
182 GNUNET_memcpy (val->path_info,
183 put_ctx->path_info,
184 put_ctx->path_info_len * sizeof(struct
185 GNUNET_DHT_PathElement));
186 GNUNET_CONTAINER_heap_update_cost (val->hn,
187 val->discard_time.abs_value_us);
188 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
189 "Got same value for key %s and type %d (size %u vs %u)\n",
190 GNUNET_h2s (key),
191 val->type,
192 (unsigned int) val->size,
193 (unsigned int) put_ctx->size);
194 return GNUNET_NO;
195 }
196 return GNUNET_YES;
197}
198
199
200/**
201 * Store an item in the datastore.
202 *
203 * @param cls closure (our `struct Plugin`)
204 * @param key key to store data under
205 * @param xor_distance how close is @a key to our PID?
206 * @param size number of bytes in @a data
207 * @param data data to store
208 * @param type type of the value
209 * @param discard_time when to discard the value in any case
210 * @param path_info_len number of entries in @a path_info
211 * @param path_info a path through the network
212 * @return 0 if duplicate, -1 on error, number of bytes used otherwise
213 */
214static ssize_t
215heap_plugin_put (void *cls,
216 const struct GNUNET_HashCode *key,
217 uint32_t xor_distance,
218 size_t size,
219 const char *data,
220 enum GNUNET_BLOCK_Type type,
221 struct GNUNET_TIME_Absolute discard_time,
222 unsigned int path_info_len,
223 const struct GNUNET_DHT_PathElement *path_info)
224{
225 struct Plugin *plugin = cls;
226 struct Value *val;
227 struct PutContext put_ctx = {
228 .data = data,
229 .size = size,
230 .path_info = path_info,
231 .path_info_len = path_info_len,
232 .discard_time = discard_time,
233 .type = type
234 };
235
236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
237 "Storing %u bytes under key %s with path length %u\n",
238 (unsigned int) size,
239 GNUNET_h2s (key),
240 path_info_len);
241 GNUNET_CONTAINER_multihashmap_get_multiple (plugin->map,
242 key,
243 &put_cb,
244 &put_ctx);
245 if (GNUNET_YES == put_ctx.found)
246 return 0;
247 val = GNUNET_malloc (sizeof(struct Value) + size);
248 GNUNET_memcpy (&val[1],
249 data,
250 size);
251 val->key = *key;
252 val->type = type;
253 val->discard_time = discard_time;
254 val->size = size;
255 if (xor_distance >= NUM_HEAPS)
256 val->distance = NUM_HEAPS - 1;
257 else
258 val->distance = xor_distance;
259 GNUNET_array_grow (val->path_info,
260 val->path_info_len,
261 path_info_len);
262 GNUNET_memcpy (val->path_info,
263 path_info,
264 path_info_len * sizeof(struct GNUNET_DHT_PathElement));
265 (void) GNUNET_CONTAINER_multihashmap_put (plugin->map,
266 &val->key,
267 val,
268 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
269 val->hn = GNUNET_CONTAINER_heap_insert (plugin->heaps[val->distance],
270 val,
271 val->discard_time.abs_value_us);
272 return size + OVERHEAD;
273}
274
275
276/**
277 * Closure for #get_cb().
278 */
279struct GetContext
280{
281 /**
282 * Function to call for each result.
283 */
284 GNUNET_DATACACHE_Iterator iter;
285
286 /**
287 * Closure for @e iter.
288 */
289 void *iter_cls;
290
291 /**
292 * Number of results found.
293 */
294 unsigned int cnt;
295
296 /**
297 * Block type requested.
298 */
299 enum GNUNET_BLOCK_Type type;
300};
301
302
303/**
304 * Function called during GET to find matching blocks.
305 * Only matches by type.
306 *
307 * @param cls the `struct GetContext`
308 * @param key the key for the value(s)
309 * @param value an existing value
310 * @return #GNUNET_YES to continue to iterate
311 */
312static int
313get_cb (void *cls,
314 const struct GNUNET_HashCode *key,
315 void *value)
316{
317 struct GetContext *get_ctx = cls;
318 struct Value *val = value;
319 int ret;
320
321 if ( (get_ctx->type != val->type) &&
322 (GNUNET_BLOCK_TYPE_ANY != get_ctx->type) )
323 {
324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
325 "Result for key %s does not match block type %d\n",
326 GNUNET_h2s (key),
327 get_ctx->type);
328 return GNUNET_OK;
329 }
330 if (GNUNET_TIME_absolute_is_past (val->discard_time))
331 {
332 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
333 "Result for key %s is expired\n",
334 GNUNET_h2s (key));
335 return GNUNET_OK;
336 }
337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
338 "Found result for key %s\n",
339 GNUNET_h2s (key));
340 if (NULL != get_ctx->iter)
341 ret = get_ctx->iter (get_ctx->iter_cls,
342 key,
343 val->size,
344 (const char *) &val[1],
345 val->type,
346 val->discard_time,
347 val->path_info_len,
348 val->path_info);
349 else
350 ret = GNUNET_YES;
351 get_ctx->cnt++;
352 return ret;
353}
354
355
356/**
357 * Iterate over the results for a particular key
358 * in the datastore.
359 *
360 * @param cls closure (our `struct Plugin`)
361 * @param key
362 * @param type entries of which type are relevant?
363 * @param iter maybe NULL (to just count)
364 * @param iter_cls closure for @a iter
365 * @return the number of results found
366 */
367static unsigned int
368heap_plugin_get (void *cls,
369 const struct GNUNET_HashCode *key,
370 enum GNUNET_BLOCK_Type type,
371 GNUNET_DATACACHE_Iterator iter,
372 void *iter_cls)
373{
374 struct Plugin *plugin = cls;
375 struct GetContext get_ctx;
376
377 get_ctx.type = type;
378 get_ctx.iter = iter;
379 get_ctx.iter_cls = iter_cls;
380 get_ctx.cnt = 0;
381 GNUNET_CONTAINER_multihashmap_get_multiple (plugin->map,
382 key,
383 &get_cb,
384 &get_ctx);
385 return get_ctx.cnt;
386}
387
388
389/**
390 * Delete the entry with the lowest expiration value
391 * from the datacache right now.
392 *
393 * @param cls closure (our `struct Plugin`)
394 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
395 */
396static int
397heap_plugin_del (void *cls)
398{
399 struct Plugin *plugin = cls;
400 struct Value *val;
401
402 for (unsigned int i = 0; i < NUM_HEAPS; i++)
403 {
404 val = GNUNET_CONTAINER_heap_remove_root (plugin->heaps[i]);
405 if (NULL != val)
406 break;
407 }
408 if (NULL == val)
409 return GNUNET_SYSERR;
410 GNUNET_assert (GNUNET_YES ==
411 GNUNET_CONTAINER_multihashmap_remove (plugin->map,
412 &val->key,
413 val));
414 plugin->env->delete_notify (plugin->env->cls,
415 &val->key,
416 val->size + OVERHEAD);
417 GNUNET_free (val->path_info);
418 GNUNET_free (val);
419 return GNUNET_OK;
420}
421
422
423/**
424 * Closure for #find_closest().
425 */
426struct GetClosestContext
427{
428 struct Value **values;
429
430 const struct GNUNET_HashCode *key;
431
432 enum GNUNET_BLOCK_Type type;
433
434 unsigned int num_results;
435
436};
437
438
439static enum GNUNET_GenericReturnValue
440find_closest (void *cls,
441 const struct GNUNET_HashCode *key,
442 void *value)
443{
444 struct GetClosestContext *gcc = cls;
445 struct Value *val = value;
446 unsigned int j;
447
448 if (1 != GNUNET_CRYPTO_hash_cmp (key,
449 gcc->key))
450 return GNUNET_OK; /* useless */
451 if ( (val->type != gcc->type) &&
452 (GNUNET_BLOCK_TYPE_ANY != gcc->type) )
453 return GNUNET_OK; /* useless */
454 j = gcc->num_results;
455 for (unsigned int i = 0; i < gcc->num_results; i++)
456 {
457 if (NULL == gcc->values[i])
458 {
459 j = i;
460 break;
461 }
462 if (1 ==
463 GNUNET_CRYPTO_hash_cmp (&gcc->values[i]->key,
464 key))
465 {
466 j = i;
467 break;
468 }
469 }
470 if (j == gcc->num_results)
471 return GNUNET_OK;
472 gcc->values[j] = val;
473 return GNUNET_OK;
474}
475
476
477/**
478 * Iterate over the results that are "close" to a particular key in
479 * the datacache. "close" is defined as numerically larger than @a
480 * key (when interpreted as a circular address space), with small
481 * distance.
482 *
483 * @param cls closure (internal context for the plugin)
484 * @param key area of the keyspace to look into
485 * @param type desired block type for the replies
486 * @param num_results number of results that should be returned to @a iter
487 * @param iter maybe NULL (to just count)
488 * @param iter_cls closure for @a iter
489 * @return the number of results found
490 */
491static unsigned int
492heap_plugin_get_closest (void *cls,
493 const struct GNUNET_HashCode *key,
494 enum GNUNET_BLOCK_Type type,
495 unsigned int num_results,
496 GNUNET_DATACACHE_Iterator iter,
497 void *iter_cls)
498{
499 struct Plugin *plugin = cls;
500 struct Value *values[num_results];
501 struct GetClosestContext gcc = {
502 .values = values,
503 .type = type,
504 .num_results = num_results * 2,
505 .key = key
506 };
507
508 GNUNET_CONTAINER_multihashmap_iterate (plugin->map,
509 &find_closest,
510 &gcc);
511 for (unsigned int i = 0; i < num_results * 2; i++)
512 {
513 if (NULL == values[i])
514 return i;
515 iter (iter_cls,
516 &values[i]->key,
517 values[i]->size,
518 (void *) &values[i][1],
519 values[i]->type,
520 values[i]->discard_time,
521 values[i]->path_info_len,
522 values[i]->path_info);
523 }
524 return num_results * 2;
525}
526
527
528/**
529 * Entry point for the plugin.
530 *
531 * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironmnet`)
532 * @return the plugin's closure (our `struct Plugin`)
533 */
534void *
535libgnunet_plugin_datacache_heap_init (void *cls)
536{
537 struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
538 struct GNUNET_DATACACHE_PluginFunctions *api;
539 struct Plugin *plugin;
540
541 plugin = GNUNET_new (struct Plugin);
542 plugin->map = GNUNET_CONTAINER_multihashmap_create (1024, /* FIXME: base on quota! */
543 GNUNET_YES);
544 for (unsigned int i = 0; i < NUM_HEAPS; i++)
545 plugin->heaps[i] = GNUNET_CONTAINER_heap_create (
546 GNUNET_CONTAINER_HEAP_ORDER_MIN);
547 plugin->env = env;
548 api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
549 api->cls = plugin;
550 api->get = &heap_plugin_get;
551 api->put = &heap_plugin_put;
552 api->del = &heap_plugin_del;
553 api->get_closest = &heap_plugin_get_closest;
554 LOG (GNUNET_ERROR_TYPE_INFO,
555 _ ("Heap datacache running\n"));
556 return api;
557}
558
559
560/**
561 * Exit point from the plugin.
562 *
563 * @param cls closure (our "struct Plugin")
564 * @return NULL
565 */
566void *
567libgnunet_plugin_datacache_heap_done (void *cls)
568{
569 struct GNUNET_DATACACHE_PluginFunctions *api = cls;
570 struct Plugin *plugin = api->cls;
571 struct Value *val;
572
573 for (unsigned int i = 0; i < NUM_HEAPS; i++)
574 {
575 while (NULL != (val = GNUNET_CONTAINER_heap_remove_root (plugin->heaps[i])))
576 {
577 GNUNET_assert (GNUNET_YES ==
578 GNUNET_CONTAINER_multihashmap_remove (plugin->map,
579 &val->key,
580 val));
581 GNUNET_free (val->path_info);
582 GNUNET_free (val);
583 }
584 GNUNET_CONTAINER_heap_destroy (plugin->heaps[i]);
585 }
586 GNUNET_CONTAINER_multihashmap_destroy (plugin->map);
587 GNUNET_free (plugin);
588 GNUNET_free (api);
589 return NULL;
590}
591
592
593/* 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 1a83cda86..000000000
--- a/src/datacache/plugin_datacache_postgres.c
+++ /dev/null
@@ -1,631 +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 int
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 gn011dc_oid_seq"),
72 GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS gn011dc ("
73 " oid OID NOT NULL DEFAULT nextval('gn011dc_oid_seq'),"
74 " type INTEGER NOT NULL,"
75 " prox INTEGER NOT NULL,"
76 " discard_time BIGINT NOT NULL,"
77 " key BYTEA NOT NULL,"
78 " value BYTEA NOT NULL,"
79 " path BYTEA DEFAULT NULL)"),
80 GNUNET_PQ_make_try_execute (
81 "ALTER SEQUENCE gnu011dc_oid_seq OWNED BY gn011dc.oid"),
82 GNUNET_PQ_make_try_execute (
83 "CREATE INDEX IF NOT EXISTS idx_oid ON gn011dc (oid)"),
84 GNUNET_PQ_make_try_execute (
85 "CREATE INDEX IF NOT EXISTS idx_key ON gn011dc (key)"),
86 GNUNET_PQ_make_try_execute (
87 "CREATE INDEX IF NOT EXISTS idx_dt ON gn011dc (discard_time)"),
88 GNUNET_PQ_make_execute (
89 "ALTER TABLE gn011dc ALTER value SET STORAGE EXTERNAL"),
90 GNUNET_PQ_make_execute ("ALTER TABLE gn011dc ALTER key SET STORAGE PLAIN"),
91 GNUNET_PQ_EXECUTE_STATEMENT_END
92 };
93 struct GNUNET_PQ_PreparedStatement ps[] = {
94 GNUNET_PQ_make_prepare ("getkt",
95 "SELECT discard_time,type,value,path FROM gn011dc "
96 "WHERE key=$1 AND type=$2 AND discard_time >= $3",
97 3),
98 GNUNET_PQ_make_prepare ("getk",
99 "SELECT discard_time,type,value,path FROM gn011dc "
100 "WHERE key=$1 AND discard_time >= $2",
101 2),
102 GNUNET_PQ_make_prepare ("getex",
103 "SELECT length(value) AS len,oid,key FROM gn011dc"
104 " WHERE discard_time < $1"
105 " ORDER BY discard_time ASC LIMIT 1",
106 1),
107 GNUNET_PQ_make_prepare ("getm",
108 "SELECT length(value) AS len,oid,key FROM gn011dc"
109 " ORDER BY prox ASC, discard_time ASC LIMIT 1",
110 0),
111 GNUNET_PQ_make_prepare ("get_closest",
112 "(SELECT discard_time,type,value,path,key FROM gn011dc"
113 " WHERE key >= $1"
114 " AND discard_time >= $2"
115 " AND ( (type = $3) OR ( 0 = $3) )"
116 " ORDER BY key ASC"
117 " LIMIT $4)"
118 " UNION "
119 "(SELECT discard_time,type,value,path,key FROM gn011dc"
120 " WHERE key <= $1"
121 " AND discard_time >= $2"
122 " AND ( (type = $3) OR ( 0 = $3) )"
123 " ORDER BY key DESC"
124 " LIMIT $4)",
125 4),
126 GNUNET_PQ_make_prepare ("delrow",
127 "DELETE FROM gn011dc WHERE oid=$1",
128 1),
129 GNUNET_PQ_make_prepare ("put",
130 "INSERT INTO gn011dc (type, prox, discard_time, key, value, path) "
131 "VALUES ($1, $2, $3, $4, $5, $6)",
132 6),
133 GNUNET_PQ_PREPARED_STATEMENT_END
134 };
135
136 plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->env->cfg,
137 "datacache-postgres",
138 NULL,
139 es,
140 ps);
141 if (NULL == plugin->dbh)
142 return GNUNET_SYSERR;
143 return GNUNET_OK;
144}
145
146
147/**
148 * Store an item in the datastore.
149 *
150 * @param cls closure (our `struct Plugin`)
151 * @param key key to store @a data under
152 * @param prox proximity of @a key to my PID
153 * @param data_size number of bytes in @a data
154 * @param data data to store
155 * @param type type of the value
156 * @param discard_time when to discard the value in any case
157 * @param path_info_len number of entries in @a path_info
158 * @param path_info a path through the network
159 * @return 0 if duplicate, -1 on error, number of bytes used otherwise
160 */
161static ssize_t
162postgres_plugin_put (void *cls,
163 const struct GNUNET_HashCode *key,
164 uint32_t prox,
165 size_t data_size,
166 const char *data,
167 enum GNUNET_BLOCK_Type type,
168 struct GNUNET_TIME_Absolute discard_time,
169 unsigned int path_info_len,
170 const struct GNUNET_DHT_PathElement *path_info)
171{
172 struct Plugin *plugin = cls;
173 uint32_t type32 = (uint32_t) type;
174 struct GNUNET_PQ_QueryParam params[] = {
175 GNUNET_PQ_query_param_uint32 (&type32),
176 GNUNET_PQ_query_param_uint32 (&prox),
177 GNUNET_PQ_query_param_absolute_time (&discard_time),
178 GNUNET_PQ_query_param_auto_from_type (key),
179 GNUNET_PQ_query_param_fixed_size (data, data_size),
180 GNUNET_PQ_query_param_fixed_size (path_info,
181 path_info_len * sizeof(struct
182 GNUNET_DHT_PathElement)),
183 GNUNET_PQ_query_param_end
184 };
185 enum GNUNET_DB_QueryStatus ret;
186
187 ret = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
188 "put",
189 params);
190 if (0 > ret)
191 return -1;
192 plugin->num_items++;
193 return data_size + OVERHEAD;
194}
195
196
197/**
198 * Closure for #handle_results.
199 */
200struct HandleResultContext
201{
202 /**
203 * Function to call on each result, may be NULL.
204 */
205 GNUNET_DATACACHE_Iterator iter;
206
207 /**
208 * Closure for @e iter.
209 */
210 void *iter_cls;
211
212 /**
213 * Key used.
214 */
215 const struct GNUNET_HashCode *key;
216};
217
218
219/**
220 * Function to be called with the results of a SELECT statement
221 * that has returned @a num_results results. Parse the result
222 * and call the callback given in @a cls
223 *
224 * @param cls closure of type `struct HandleResultContext`
225 * @param result the postgres result
226 * @param num_result the number of results in @a result
227 */
228static void
229handle_results (void *cls,
230 PGresult *result,
231 unsigned int num_results)
232{
233 struct HandleResultContext *hrc = cls;
234
235 for (unsigned int i = 0; i < num_results; i++)
236 {
237 struct GNUNET_TIME_Absolute expiration_time;
238 uint32_t type;
239 void *data;
240 size_t data_size;
241 struct GNUNET_DHT_PathElement *path;
242 size_t path_len;
243 struct GNUNET_PQ_ResultSpec rs[] = {
244 GNUNET_PQ_result_spec_absolute_time ("discard_time",
245 &expiration_time),
246 GNUNET_PQ_result_spec_uint32 ("type",
247 &type),
248 GNUNET_PQ_result_spec_variable_size ("value",
249 &data,
250 &data_size),
251 GNUNET_PQ_result_spec_variable_size ("path",
252 (void **) &path,
253 &path_len),
254 GNUNET_PQ_result_spec_end
255 };
256
257 if (GNUNET_YES !=
258 GNUNET_PQ_extract_result (result,
259 rs,
260 i))
261 {
262 GNUNET_break (0);
263 return;
264 }
265 if (0 != (path_len % sizeof(struct GNUNET_DHT_PathElement)))
266 {
267 GNUNET_break (0);
268 path_len = 0;
269 }
270 path_len %= sizeof(struct GNUNET_DHT_PathElement);
271 LOG (GNUNET_ERROR_TYPE_DEBUG,
272 "Found result of size %u bytes and type %u in database\n",
273 (unsigned int) data_size,
274 (unsigned int) type);
275 if ((NULL != hrc->iter) &&
276 (GNUNET_SYSERR ==
277 hrc->iter (hrc->iter_cls,
278 hrc->key,
279 data_size,
280 data,
281 (enum GNUNET_BLOCK_Type) type,
282 expiration_time,
283 path_len,
284 path)))
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 int
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 struct GNUNET_TIME_Absolute expiration_time;
457 uint32_t type;
458 void *data;
459 size_t data_size;
460 struct GNUNET_DHT_PathElement *path;
461 size_t path_len;
462 struct GNUNET_HashCode key;
463 struct GNUNET_PQ_ResultSpec rs[] = {
464 GNUNET_PQ_result_spec_absolute_time ("",
465 &expiration_time),
466 GNUNET_PQ_result_spec_uint32 ("type",
467 &type),
468 GNUNET_PQ_result_spec_variable_size ("value",
469 &data,
470 &data_size),
471 GNUNET_PQ_result_spec_variable_size ("path",
472 (void **) &path,
473 &path_len),
474 GNUNET_PQ_result_spec_auto_from_type ("key",
475 &key),
476 GNUNET_PQ_result_spec_end
477 };
478
479 if (GNUNET_YES !=
480 GNUNET_PQ_extract_result (result,
481 rs,
482 i))
483 {
484 GNUNET_break (0);
485 return;
486 }
487 if (0 != (path_len % sizeof(struct GNUNET_DHT_PathElement)))
488 {
489 GNUNET_break (0);
490 path_len = 0;
491 }
492 path_len %= sizeof(struct GNUNET_DHT_PathElement);
493 LOG (GNUNET_ERROR_TYPE_DEBUG,
494 "Found result of size %u bytes and type %u in database\n",
495 (unsigned int) data_size,
496 (unsigned int) type);
497 if (GNUNET_SYSERR ==
498 erc->iter (erc->iter_cls,
499 &key,
500 data_size,
501 data,
502 (enum GNUNET_BLOCK_Type) type,
503 expiration_time,
504 path_len,
505 path))
506 {
507 LOG (GNUNET_ERROR_TYPE_DEBUG,
508 "Ending iteration (client error)\n");
509 GNUNET_PQ_cleanup_result (rs);
510 break;
511 }
512 GNUNET_PQ_cleanup_result (rs);
513 }
514}
515
516
517/**
518 * Iterate over the results that are "close" to a particular key in
519 * the datacache. "close" is defined as numerically larger than @a
520 * key (when interpreted as a circular address space), with small
521 * distance.
522 *
523 * @param cls closure (internal context for the plugin)
524 * @param key area of the keyspace to look into
525 * @param type desired block type for the replies
526 * @param num_results number of results that should be returned to @a iter
527 * @param iter maybe NULL (to just count)
528 * @param iter_cls closure for @a iter
529 * @return the number of results found
530 */
531static unsigned int
532postgres_plugin_get_closest (void *cls,
533 const struct GNUNET_HashCode *key,
534 enum GNUNET_BLOCK_Type type,
535 unsigned int num_results,
536 GNUNET_DATACACHE_Iterator iter,
537 void *iter_cls)
538{
539 struct Plugin *plugin = cls;
540 uint32_t num_results32 = (uint32_t) num_results;
541 uint32_t type32 = (uint32_t) type;
542 struct GNUNET_TIME_Absolute now;
543 struct GNUNET_PQ_QueryParam params[] = {
544 GNUNET_PQ_query_param_auto_from_type (key),
545 GNUNET_PQ_query_param_absolute_time (&now),
546 GNUNET_PQ_query_param_uint32 (&type32),
547 GNUNET_PQ_query_param_uint32 (&num_results32),
548 GNUNET_PQ_query_param_end
549 };
550 enum GNUNET_DB_QueryStatus res;
551 struct ExtractResultContext erc;
552
553 erc.iter = iter;
554 erc.iter_cls = iter_cls;
555 now = GNUNET_TIME_absolute_get ();
556 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
557 "get_closest",
558 params,
559 &extract_result_cb,
560 &erc);
561 if (0 > res)
562 {
563 LOG (GNUNET_ERROR_TYPE_DEBUG,
564 "Ending iteration (postgres error)\n");
565 return 0;
566 }
567 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res)
568 {
569 /* no result */
570 LOG (GNUNET_ERROR_TYPE_DEBUG,
571 "Ending iteration (no more results)\n");
572 return 0;
573 }
574 return res;
575}
576
577
578/**
579 * Entry point for the plugin.
580 *
581 * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironmnet`)
582 * @return the plugin's closure (our `struct Plugin`)
583 */
584void *
585libgnunet_plugin_datacache_postgres_init (void *cls)
586{
587 struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
588 struct GNUNET_DATACACHE_PluginFunctions *api;
589 struct Plugin *plugin;
590
591 plugin = GNUNET_new (struct Plugin);
592 plugin->env = env;
593
594 if (GNUNET_OK != init_connection (plugin))
595 {
596 GNUNET_free (plugin);
597 return NULL;
598 }
599
600 api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
601 api->cls = plugin;
602 api->get = &postgres_plugin_get;
603 api->put = &postgres_plugin_put;
604 api->del = &postgres_plugin_del;
605 api->get_closest = &postgres_plugin_get_closest;
606 LOG (GNUNET_ERROR_TYPE_INFO,
607 "Postgres datacache running\n");
608 return api;
609}
610
611
612/**
613 * Exit point from the plugin.
614 *
615 * @param cls closure (our `struct Plugin`)
616 * @return NULL
617 */
618void *
619libgnunet_plugin_datacache_postgres_done (void *cls)
620{
621 struct GNUNET_DATACACHE_PluginFunctions *api = cls;
622 struct Plugin *plugin = api->cls;
623
624 GNUNET_PQ_disconnect (plugin->dbh);
625 GNUNET_free (plugin);
626 GNUNET_free (api);
627 return NULL;
628}
629
630
631/* 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 6f2165433..000000000
--- a/src/datacache/plugin_datacache_sqlite.c
+++ /dev/null
@@ -1,747 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2006, 2009, 2015 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_stmt;
78
79 /**
80 * Prepared statement for #sqlite_plugin_del.
81 */
82 sqlite3_stmt *del_select_stmt;
83
84 /**
85 * Prepared statement for #sqlite_plugin_del.
86 */
87 sqlite3_stmt *del_expired_stmt;
88
89 /**
90 * Prepared statement for #sqlite_plugin_del.
91 */
92 sqlite3_stmt *del_stmt;
93
94 /**
95 * Prepared statement for #sqlite_plugin_get_closest.
96 */
97 sqlite3_stmt *get_closest_stmt;
98
99 /**
100 * Number of key-value pairs in the database.
101 */
102 unsigned int num_items;
103};
104
105
106/**
107 * Log an error message at log-level @a level that indicates
108 * a failure of the command @a cmd with the error from the database @a db
109 *
110 * @param db database handle
111 * @param level log level
112 * @param cmd failed command
113 */
114#define LOG_SQLITE(db, level, cmd) \
115 do \
116 { \
117 LOG (level, \
118 _ ("`%s' failed at %s:%d with error: %s\n"), \
119 cmd, \
120 __FILE__, \
121 __LINE__, \
122 sqlite3_errmsg (db)); \
123 } while (0)
124
125
126/**
127 * Execute SQL statement.
128 *
129 * @param db database handle
130 * @param cmd SQL command to execute
131 */
132#define SQLITE3_EXEC(db, cmd) \
133 do \
134 { \
135 emsg = NULL; \
136 if (SQLITE_OK != sqlite3_exec (db, cmd, NULL, NULL, &emsg)) \
137 { \
138 LOG (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, \
139 _ ("`%s' failed at %s:%d with error: %s\n"), \
140 "sqlite3_exec", \
141 __FILE__, \
142 __LINE__, \
143 emsg); \
144 sqlite3_free (emsg); \
145 } \
146 } while (0)
147
148
149/**
150 * @brief Prepare a SQL statement
151 *
152 * @param dbh database handle
153 * @param zsql SQL statement text
154 * @param[out] ppStmt set to the prepared statement
155 * @return 0 on success
156 */
157static int
158sq_prepare (sqlite3 *dbh,
159 const char *zSql, /* SQL statement, UTF-8 encoded */
160 sqlite3_stmt **ppStmt)
161{ /* OUT: Statement handle */
162 char *dummy;
163
164 return sqlite3_prepare (dbh,
165 zSql,
166 strlen (zSql),
167 ppStmt,
168 (const char **) &dummy);
169}
170
171
172/**
173 * Store an item in the datastore.
174 *
175 * @param cls closure (our `struct Plugin`)
176 * @param key key to store @a data under
177 * @param xor_distance how close is @a key to our PID?
178 * @param size number of bytes in @a data
179 * @param data data to store
180 * @param type type of the value
181 * @param discard_time when to discard the value in any case
182 * @param path_info_len number of entries in @a path_info
183 * @param path_info array of peers that have processed the request
184 * @return 0 if duplicate, -1 on error, number of bytes used otherwise
185 */
186static ssize_t
187sqlite_plugin_put (void *cls,
188 const struct GNUNET_HashCode *key,
189 uint32_t xor_distance,
190 size_t size,
191 const char *data,
192 enum GNUNET_BLOCK_Type type,
193 struct GNUNET_TIME_Absolute discard_time,
194 unsigned int path_info_len,
195 const struct GNUNET_DHT_PathElement *path_info)
196{
197 struct Plugin *plugin = cls;
198 uint32_t type32 = type;
199 struct GNUNET_SQ_QueryParam params[] =
200 { GNUNET_SQ_query_param_uint32 (&type32),
201 GNUNET_SQ_query_param_absolute_time (&discard_time),
202 GNUNET_SQ_query_param_auto_from_type (key),
203 GNUNET_SQ_query_param_uint32 (&xor_distance),
204 GNUNET_SQ_query_param_fixed_size (data, size),
205 GNUNET_SQ_query_param_fixed_size (path_info,
206 path_info_len
207 * sizeof(struct GNUNET_DHT_PathElement)),
208 GNUNET_SQ_query_param_end };
209
210 LOG (GNUNET_ERROR_TYPE_DEBUG,
211 "Processing PUT of %u bytes with key `%s' and expiration %s\n",
212 (unsigned int) size,
213 GNUNET_h2s (key),
214 GNUNET_STRINGS_relative_time_to_string (
215 GNUNET_TIME_absolute_get_remaining (
216 discard_time),
217 GNUNET_YES));
218 if (GNUNET_OK != GNUNET_SQ_bind (plugin->insert_stmt, params))
219 {
220 LOG_SQLITE (plugin->dbh,
221 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
222 "sqlite3_bind_xxx");
223 GNUNET_SQ_reset (plugin->dbh, plugin->insert_stmt);
224 return -1;
225 }
226 if (SQLITE_DONE != sqlite3_step (plugin->insert_stmt))
227 {
228 LOG_SQLITE (plugin->dbh,
229 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
230 "sqlite3_step");
231 GNUNET_SQ_reset (plugin->dbh, plugin->insert_stmt);
232 return -1;
233 }
234 plugin->num_items++;
235 GNUNET_SQ_reset (plugin->dbh, plugin->insert_stmt);
236 return size + OVERHEAD;
237}
238
239
240/**
241 * Iterate over the results for a particular key
242 * in the datastore.
243 *
244 * @param cls closure (our `struct Plugin`)
245 * @param key
246 * @param type entries of which type are relevant?
247 * @param iter maybe NULL (to just count)
248 * @param iter_cls closure for @a iter
249 * @return the number of results found
250 */
251static unsigned int
252sqlite_plugin_get (void *cls,
253 const struct GNUNET_HashCode *key,
254 enum GNUNET_BLOCK_Type type,
255 GNUNET_DATACACHE_Iterator iter,
256 void *iter_cls)
257{
258 struct Plugin *plugin = cls;
259 uint32_t type32 = type;
260 struct GNUNET_TIME_Absolute now;
261 struct GNUNET_TIME_Absolute exp;
262 size_t size;
263 void *dat;
264 unsigned int cnt;
265 uint32_t off;
266 unsigned int total;
267 size_t psize;
268 struct GNUNET_DHT_PathElement *path;
269 struct GNUNET_SQ_QueryParam params_count[] =
270 { GNUNET_SQ_query_param_auto_from_type (key),
271 GNUNET_SQ_query_param_uint32 (&type32),
272 GNUNET_SQ_query_param_absolute_time (&now),
273 GNUNET_SQ_query_param_end };
274 struct GNUNET_SQ_QueryParam params_select[] =
275 { GNUNET_SQ_query_param_auto_from_type (key),
276 GNUNET_SQ_query_param_uint32 (&type32),
277 GNUNET_SQ_query_param_absolute_time (&now),
278 GNUNET_SQ_query_param_uint32 (&off),
279 GNUNET_SQ_query_param_end };
280 struct GNUNET_SQ_ResultSpec rs[] =
281 { GNUNET_SQ_result_spec_variable_size (&dat, &size),
282 GNUNET_SQ_result_spec_absolute_time (&exp),
283 GNUNET_SQ_result_spec_variable_size ((void **) &path, &psize),
284 GNUNET_SQ_result_spec_end };
285
286 now = GNUNET_TIME_absolute_get ();
287 LOG (GNUNET_ERROR_TYPE_DEBUG,
288 "Processing GET for key `%s'\n",
289 GNUNET_h2s (key));
290
291 if (GNUNET_OK != GNUNET_SQ_bind (plugin->get_count_stmt, params_count))
292 {
293 LOG_SQLITE (plugin->dbh,
294 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
295 "sqlite3_bind_xxx");
296 GNUNET_SQ_reset (plugin->dbh, plugin->get_count_stmt);
297 return 0;
298 }
299 if (SQLITE_ROW != sqlite3_step (plugin->get_count_stmt))
300 {
301 LOG_SQLITE (plugin->dbh,
302 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
303 "sqlite_step");
304 GNUNET_SQ_reset (plugin->dbh, plugin->get_count_stmt);
305 LOG (GNUNET_ERROR_TYPE_DEBUG,
306 "No content found when processing GET for key `%s'\n",
307 GNUNET_h2s (key));
308 return 0;
309 }
310 total = sqlite3_column_int (plugin->get_count_stmt, 0);
311 GNUNET_SQ_reset (plugin->dbh, plugin->get_count_stmt);
312 if ((0 == total) || (NULL == iter))
313 {
314 if (0 == total)
315 LOG (GNUNET_ERROR_TYPE_DEBUG,
316 "No content found when processing GET for key `%s'\n",
317 GNUNET_h2s (key));
318 return total;
319 }
320
321 cnt = 0;
322 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total);
323 while (cnt < total)
324 {
325 off = (off + 1) % total;
326 if (GNUNET_OK != GNUNET_SQ_bind (plugin->get_stmt, params_select))
327 {
328 LOG_SQLITE (plugin->dbh,
329 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
330 "sqlite3_bind_xxx");
331 GNUNET_SQ_reset (plugin->dbh, plugin->get_stmt);
332 return cnt;
333 }
334 if (SQLITE_ROW != sqlite3_step (plugin->get_stmt))
335 break;
336 if (GNUNET_OK != GNUNET_SQ_extract_result (plugin->get_stmt, rs))
337 {
338 GNUNET_break (0);
339 GNUNET_SQ_reset (plugin->dbh, plugin->get_stmt);
340 break;
341 }
342 if (0 != psize % sizeof(struct GNUNET_DHT_PathElement))
343 {
344 GNUNET_break (0);
345 psize = 0;
346 path = NULL;
347 }
348 psize /= sizeof(struct GNUNET_DHT_PathElement);
349 cnt++;
350 LOG (GNUNET_ERROR_TYPE_DEBUG,
351 "Found %u-byte result when processing GET for key `%s'\n",
352 (unsigned int) size,
353 GNUNET_h2s (key));
354 if (GNUNET_OK != iter (iter_cls, key, size, dat, type, exp, psize, path))
355 {
356 GNUNET_SQ_cleanup_result (rs);
357 GNUNET_SQ_reset (plugin->dbh, plugin->get_stmt);
358 break;
359 }
360 GNUNET_SQ_cleanup_result (rs);
361 GNUNET_SQ_reset (plugin->dbh, plugin->get_stmt);
362 }
363 GNUNET_SQ_reset (plugin->dbh, plugin->get_stmt);
364 return cnt;
365}
366
367
368/**
369 * Delete the entry with the lowest expiration value
370 * from the datacache right now.
371 *
372 * @param cls closure (our `struct Plugin`)
373 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
374 */
375static int
376sqlite_plugin_del (void *cls)
377{
378 struct Plugin *plugin = cls;
379 uint64_t rowid;
380 void *data;
381 size_t dsize;
382 struct GNUNET_HashCode hc;
383 struct GNUNET_TIME_Absolute now;
384 struct GNUNET_SQ_ResultSpec rs[] =
385 { GNUNET_SQ_result_spec_uint64 (&rowid),
386 GNUNET_SQ_result_spec_auto_from_type (&hc),
387 GNUNET_SQ_result_spec_variable_size ((void **) &data, &dsize),
388 GNUNET_SQ_result_spec_end };
389 struct GNUNET_SQ_QueryParam params[] = { GNUNET_SQ_query_param_uint64 (
390 &rowid),
391 GNUNET_SQ_query_param_end };
392 struct GNUNET_SQ_QueryParam time_params[] =
393 { GNUNET_SQ_query_param_absolute_time (&now), GNUNET_SQ_query_param_end };
394
395 LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing DEL\n");
396 now = GNUNET_TIME_absolute_get ();
397 if (GNUNET_OK != GNUNET_SQ_bind (plugin->del_expired_stmt, time_params))
398 {
399 LOG_SQLITE (plugin->dbh,
400 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
401 "sqlite3_bind");
402 GNUNET_SQ_reset (plugin->dbh, plugin->del_expired_stmt);
403 return GNUNET_SYSERR;
404 }
405 if ((SQLITE_ROW != sqlite3_step (plugin->del_expired_stmt)) ||
406 (GNUNET_OK != GNUNET_SQ_extract_result (plugin->del_expired_stmt, rs)))
407 {
408 GNUNET_SQ_reset (plugin->dbh, plugin->del_expired_stmt);
409 if (SQLITE_ROW != sqlite3_step (plugin->del_select_stmt))
410 {
411 LOG_SQLITE (plugin->dbh,
412 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
413 "sqlite3_step");
414 GNUNET_SQ_reset (plugin->dbh, plugin->del_select_stmt);
415 return GNUNET_SYSERR;
416 }
417 if (GNUNET_OK != GNUNET_SQ_extract_result (plugin->del_select_stmt, rs))
418 {
419 GNUNET_SQ_reset (plugin->dbh, plugin->del_select_stmt);
420 GNUNET_break (0);
421 return GNUNET_SYSERR;
422 }
423 }
424 GNUNET_SQ_cleanup_result (rs);
425 GNUNET_SQ_reset (plugin->dbh, plugin->del_select_stmt);
426 if (GNUNET_OK != GNUNET_SQ_bind (plugin->del_stmt, params))
427 {
428 LOG_SQLITE (plugin->dbh,
429 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
430 "sqlite3_bind");
431 GNUNET_SQ_reset (plugin->dbh, plugin->del_stmt);
432 return GNUNET_SYSERR;
433 }
434 if (SQLITE_DONE != sqlite3_step (plugin->del_stmt))
435 {
436 LOG_SQLITE (plugin->dbh,
437 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
438 "sqlite3_step");
439 GNUNET_SQ_reset (plugin->dbh, plugin->del_stmt);
440 return GNUNET_SYSERR;
441 }
442 plugin->num_items--;
443 plugin->env->delete_notify (plugin->env->cls, &hc, dsize + OVERHEAD);
444 GNUNET_SQ_reset (plugin->dbh, plugin->del_stmt);
445 return GNUNET_OK;
446}
447
448
449/**
450 * Iterate over the results that are "close" to a particular key in
451 * the datacache. "close" is defined as numerically larger than @a
452 * key (when interpreted as a circular address space), with small
453 * distance.
454 *
455 * @param cls closure (internal context for the plugin)
456 * @param key area of the keyspace to look into
457 * @param type desired block type for the replies
458 * @param num_results number of results that should be returned to @a iter
459 * @param iter maybe NULL (to just count)
460 * @param iter_cls closure for @a iter
461 * @return the number of results found
462 */
463static unsigned int
464sqlite_plugin_get_closest (void *cls,
465 const struct GNUNET_HashCode *key,
466 enum GNUNET_BLOCK_Type type,
467 unsigned int num_results,
468 GNUNET_DATACACHE_Iterator iter,
469 void *iter_cls)
470{
471 struct Plugin *plugin = cls;
472 uint32_t type32 = type;
473 uint32_t num_results32 = num_results;
474 struct GNUNET_TIME_Absolute now;
475 struct GNUNET_TIME_Absolute exp;
476 size_t size;
477 void *dat;
478 unsigned int cnt;
479 size_t psize;
480 uint32_t rtype;
481 struct GNUNET_HashCode hc;
482 struct GNUNET_DHT_PathElement *path;
483 struct GNUNET_SQ_QueryParam params[] = {
484 GNUNET_SQ_query_param_auto_from_type (key),
485 GNUNET_SQ_query_param_absolute_time (&now),
486 GNUNET_SQ_query_param_uint32 (&type32),
487 GNUNET_SQ_query_param_uint32 (&num_results32),
488 GNUNET_SQ_query_param_end
489 };
490 struct GNUNET_SQ_ResultSpec rs[] = {
491 GNUNET_SQ_result_spec_variable_size (&dat, &size),
492 GNUNET_SQ_result_spec_absolute_time (&exp),
493 GNUNET_SQ_result_spec_variable_size ((void **) &path, &psize),
494 GNUNET_SQ_result_spec_uint32 (&rtype),
495 GNUNET_SQ_result_spec_auto_from_type (&hc),
496 GNUNET_SQ_result_spec_end
497 };
498
499 now = GNUNET_TIME_absolute_get ();
500 LOG (GNUNET_ERROR_TYPE_DEBUG,
501 "Processing GET_CLOSEST for key `%s'\n",
502 GNUNET_h2s (key));
503 if (GNUNET_OK !=
504 GNUNET_SQ_bind (plugin->get_closest_stmt,
505 params))
506 {
507 LOG_SQLITE (plugin->dbh,
508 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
509 "sqlite3_bind_xxx");
510 GNUNET_SQ_reset (plugin->dbh,
511 plugin->get_closest_stmt);
512 return 0;
513 }
514 cnt = 0;
515 while (SQLITE_ROW == sqlite3_step (plugin->get_closest_stmt))
516 {
517 if (GNUNET_OK !=
518 GNUNET_SQ_extract_result (plugin->get_closest_stmt,
519 rs))
520 {
521 GNUNET_break (0);
522 break;
523 }
524 if (0 != psize % sizeof(struct GNUNET_DHT_PathElement))
525 {
526 GNUNET_break (0);
527 psize = 0;
528 path = NULL;
529 }
530 psize /= sizeof(struct GNUNET_DHT_PathElement);
531 cnt++;
532 LOG (GNUNET_ERROR_TYPE_DEBUG,
533 "Found %u-byte result at %s when processing GET_CLOSE\n",
534 (unsigned int) size,
535 GNUNET_h2s (&hc));
536 if (GNUNET_OK != iter (iter_cls,
537 &hc,
538 size,
539 dat,
540 rtype,
541 exp,
542 psize,
543 path))
544 {
545 GNUNET_SQ_cleanup_result (rs);
546 break;
547 }
548 GNUNET_SQ_cleanup_result (rs);
549 }
550 GNUNET_SQ_reset (plugin->dbh,
551 plugin->get_closest_stmt);
552 return cnt;
553}
554
555
556/**
557 * Entry point for the plugin.
558 *
559 * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironment`)
560 * @return the plugin's closure (our `struct Plugin`)
561 */
562void *
563libgnunet_plugin_datacache_sqlite_init (void *cls)
564{
565 struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
566 struct GNUNET_DATACACHE_PluginFunctions *api;
567 struct Plugin *plugin;
568 char *fn;
569 char *fn_utf8;
570 sqlite3 *dbh;
571 char *emsg;
572
573 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
574 "datacache-sqlite",
575 "IN_MEMORY"))
576 {
577 if (SQLITE_OK != sqlite3_open (":memory:", &dbh))
578 return NULL;
579 fn_utf8 = NULL;
580 }
581 else
582 {
583 fn = GNUNET_DISK_mktemp ("gnunet-datacache");
584 if (fn == NULL)
585 {
586 GNUNET_break (0);
587 return NULL;
588 }
589 /* fn should be UTF-8-encoded. If it isn't, it's a bug. */
590 fn_utf8 = GNUNET_strdup (fn);
591 if (SQLITE_OK != sqlite3_open (fn_utf8, &dbh))
592 {
593 GNUNET_free (fn);
594 GNUNET_free (fn_utf8);
595 return NULL;
596 }
597 GNUNET_free (fn);
598 }
599
600 SQLITE3_EXEC (dbh, "PRAGMA temp_store=MEMORY");
601 SQLITE3_EXEC (dbh, "PRAGMA locking_mode=EXCLUSIVE");
602 SQLITE3_EXEC (dbh, "PRAGMA journal_mode=OFF");
603 SQLITE3_EXEC (dbh, "PRAGMA synchronous=OFF");
604 SQLITE3_EXEC (dbh, "PRAGMA page_size=4092");
605 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
606 "datacache-sqlite",
607 "IN_MEMORY"))
608 SQLITE3_EXEC (dbh, "PRAGMA sqlite_temp_store=3");
609
610 SQLITE3_EXEC (dbh,
611 "CREATE TABLE ds091 ("
612 " type INTEGER NOT NULL DEFAULT 0,"
613 " expire INTEGER NOT NULL,"
614 " key BLOB NOT NULL DEFAULT '',"
615 " prox INTEGER NOT NULL,"
616 " value BLOB NOT NULL,"
617 " path BLOB DEFAULT '')");
618 SQLITE3_EXEC (dbh, "CREATE INDEX idx_hashidx ON ds091 (key,type,expire)");
619 SQLITE3_EXEC (dbh, "CREATE INDEX idx_prox_expire ON ds091 (prox,expire)");
620 SQLITE3_EXEC (dbh, "CREATE INDEX idx_expire_only ON ds091 (expire)");
621 plugin = GNUNET_new (struct Plugin);
622 plugin->env = env;
623 plugin->dbh = dbh;
624 plugin->fn = fn_utf8;
625
626 if ((SQLITE_OK !=
627 sq_prepare (plugin->dbh,
628 "INSERT INTO ds091 (type, expire, key, prox, value, path) "
629 "VALUES (?, ?, ?, ?, ?, ?)",
630 &plugin->insert_stmt)) ||
631 (SQLITE_OK != sq_prepare (plugin->dbh,
632 "SELECT count(*) FROM ds091 "
633 "WHERE key=? AND type=? AND expire >= ?",
634 &plugin->get_count_stmt)) ||
635 (SQLITE_OK !=
636 sq_prepare (plugin->dbh,
637 "SELECT value,expire,path FROM ds091"
638 " WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET ?",
639 &plugin->get_stmt)) ||
640 (SQLITE_OK != sq_prepare (plugin->dbh,
641 "SELECT _ROWID_,key,value FROM ds091"
642 " WHERE expire < ?1"
643 " ORDER BY expire ASC LIMIT 1",
644 &plugin->del_expired_stmt)) ||
645 (SQLITE_OK != sq_prepare (plugin->dbh,
646 "SELECT _ROWID_,key,value FROM ds091"
647 " ORDER BY prox ASC, expire ASC LIMIT 1",
648 &plugin->del_select_stmt)) ||
649 (SQLITE_OK != sq_prepare (plugin->dbh,
650 "DELETE FROM ds091 WHERE _ROWID_=?",
651 &plugin->del_stmt)) ||
652 (SQLITE_OK !=
653 sq_prepare (plugin->dbh,
654 "SELECT * FROM ("
655 " SELECT value,expire,path,type,key FROM ds091 "
656 " WHERE key>=?1 "
657 " AND expire >= ?2"
658 " AND ( (type=?3) or (0 == ?3) )"
659 " ORDER BY KEY ASC LIMIT ?4)"
660 "UNION "
661 "SELECT * FROM ("
662 " SELECT value,expire,path,type,key FROM ds091 "
663 " WHERE key<=?1 "
664 " AND expire >= ?2"
665 " AND ( (type=?3) or (0 == ?3) )"
666 " ORDER BY KEY DESC LIMIT ?4)",
667 &plugin->get_closest_stmt)))
668 {
669 LOG_SQLITE (plugin->dbh,
670 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
671 "sq_prepare");
672 GNUNET_break (SQLITE_OK == sqlite3_close (plugin->dbh));
673 GNUNET_free (plugin);
674 return NULL;
675 }
676
677 api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
678 api->cls = plugin;
679 api->get = &sqlite_plugin_get;
680 api->put = &sqlite_plugin_put;
681 api->del = &sqlite_plugin_del;
682 api->get_closest = &sqlite_plugin_get_closest;
683 LOG (GNUNET_ERROR_TYPE_INFO, "Sqlite datacache running\n");
684 return api;
685}
686
687
688/**
689 * Exit point from the plugin.
690 *
691 * @param cls closure (our `struct Plugin`)
692 * @return NULL
693 */
694void *
695libgnunet_plugin_datacache_sqlite_done (void *cls)
696{
697 struct GNUNET_DATACACHE_PluginFunctions *api = cls;
698 struct Plugin *plugin = api->cls;
699 int result;
700
701#if SQLITE_VERSION_NUMBER >= 3007000
702 sqlite3_stmt *stmt;
703#endif
704
705#if ! WINDOWS || defined(__CYGWIN__)
706 if ((NULL != plugin->fn) && (0 != unlink (plugin->fn)))
707 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", plugin->fn);
708 GNUNET_free (plugin->fn);
709#endif
710 sqlite3_finalize (plugin->insert_stmt);
711 sqlite3_finalize (plugin->get_count_stmt);
712 sqlite3_finalize (plugin->get_stmt);
713 sqlite3_finalize (plugin->del_select_stmt);
714 sqlite3_finalize (plugin->del_expired_stmt);
715 sqlite3_finalize (plugin->del_stmt);
716 sqlite3_finalize (plugin->get_closest_stmt);
717 result = sqlite3_close (plugin->dbh);
718#if SQLITE_VERSION_NUMBER >= 3007000
719 if (SQLITE_BUSY == result)
720 {
721 LOG (GNUNET_ERROR_TYPE_WARNING,
722 _ (
723 "Tried to close sqlite without finalizing all prepared statements.\n"));
724 stmt = sqlite3_next_stmt (plugin->dbh, NULL);
725 while (NULL != stmt)
726 {
727 result = sqlite3_finalize (stmt);
728 if (result != SQLITE_OK)
729 LOG (GNUNET_ERROR_TYPE_WARNING,
730 "Failed to close statement %p: %d\n",
731 stmt,
732 result);
733 stmt = sqlite3_next_stmt (plugin->dbh, NULL);
734 }
735 result = sqlite3_close (plugin->dbh);
736 }
737#endif
738 if (SQLITE_OK != result)
739 LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close");
740
741 GNUNET_free (plugin);
742 GNUNET_free (api);
743 return NULL;
744}
745
746
747/* 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 2f7b41dbe..000000000
--- a/src/datacache/plugin_datacache_template.c
+++ /dev/null
@@ -1,184 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2006, 2009, 2015 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 key key to store @a data under
48 * @param xor_distance distance of @a key to our PID
49 * @param size number of bytes in @a data
50 * @param data data to store
51 * @param type type of the value
52 * @param discard_time when to discard the value in any case
53 * @param path_info_len number of entries in @a path_info
54 * @param path_info a path through the network
55 * @return 0 if duplicate, -1 on error, number of bytes used otherwise
56 */
57static ssize_t
58template_plugin_put (void *cls,
59 const struct GNUNET_HashCode *key,
60 uint32_t xor_distance,
61 size_t size,
62 const char *data,
63 enum GNUNET_BLOCK_Type type,
64 struct GNUNET_TIME_Absolute discard_time,
65 unsigned int path_info_len,
66 const struct GNUNET_DHT_PathElement *path_info)
67{
68 GNUNET_break (0);
69 return -1;
70}
71
72
73/**
74 * Iterate over the results for a particular key
75 * in the datastore.
76 *
77 * @param cls closure (our `struct Plugin`)
78 * @param key
79 * @param type entries of which type are relevant?
80 * @param iter maybe NULL (to just count)
81 * @param iter_cls closure for @a iter
82 * @return the number of results found
83 */
84static unsigned int
85template_plugin_get (void *cls,
86 const struct GNUNET_HashCode *key,
87 enum GNUNET_BLOCK_Type type,
88 GNUNET_DATACACHE_Iterator iter,
89 void *iter_cls)
90{
91 GNUNET_break (0);
92 return 0;
93}
94
95
96/**
97 * Delete the entry with the lowest expiration value
98 * from the datacache right now.
99 *
100 * @param cls closure (our `struct Plugin`)
101 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
102 */
103static int
104template_plugin_del (void *cls)
105{
106 GNUNET_break (0);
107 return GNUNET_SYSERR;
108}
109
110
111/**
112 * Iterate over the results that are "close" to a particular key in
113 * the datacache. "close" is defined as numerically larger than @a
114 * key (when interpreted as a circular address space), with small
115 * distance.
116 *
117 * @param cls closure (internal context for the plugin)
118 * @param key area of the keyspace to look into
119 * @param type desired block type for the replies
120 * @param num_results number of results that should be returned to @a iter
121 * @param iter maybe NULL (to just count)
122 * @param iter_cls closure for @a iter
123 * @return the number of results found
124 */
125static unsigned int
126template_plugin_get_closest (void *cls,
127 const struct GNUNET_HashCode *key,
128 enum GNUNET_BLOCK_Type type,
129 unsigned int num_results,
130 GNUNET_DATACACHE_Iterator iter,
131 void *iter_cls)
132{
133 GNUNET_break (0);
134 return 0;
135}
136
137
138/**
139 * Entry point for the plugin.
140 *
141 * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironmnet`)
142 * @return the plugin's closure (our `struct Plugin`)
143 */
144void *
145libgnunet_plugin_datacache_template_init (void *cls)
146{
147 struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
148 struct GNUNET_DATACACHE_PluginFunctions *api;
149 struct Plugin *plugin;
150
151 plugin = GNUNET_new (struct Plugin);
152 plugin->env = env;
153 api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
154 api->cls = plugin;
155 api->get = &template_plugin_get;
156 api->put = &template_plugin_put;
157 api->del = &template_plugin_del;
158 api->get_closest = &template_plugin_get_closest;
159 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
160 "template",
161 "Template datacache running\n");
162 return api;
163}
164
165
166/**
167 * Exit point from the plugin.
168 *
169 * @param cls closure (our `struct Plugin`)
170 * @return NULL
171 */
172void *
173libgnunet_plugin_datacache_template_done (void *cls)
174{
175 struct GNUNET_DATACACHE_PluginFunctions *api = cls;
176 struct Plugin *plugin = api->cls;
177
178 GNUNET_free (plugin);
179 GNUNET_free (api);
180 return NULL;
181}
182
183
184/* 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 5740d2b7d..000000000
--- a/src/datacache/test_datacache.c
+++ /dev/null
@@ -1,195 +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/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 int
43checkIt (void *cls,
44 const struct GNUNET_HashCode *key,
45 size_t size, const char *data,
46 enum GNUNET_BLOCK_Type type,
47 struct GNUNET_TIME_Absolute exp,
48 unsigned int path_len,
49 const struct GNUNET_DHT_PathElement *path)
50{
51 (void) key;
52 (void) type;
53 (void) exp;
54 (void) path_len;
55 (void) path;
56 if (size != sizeof(struct GNUNET_HashCode))
57 {
58 GNUNET_break (0);
59 ok = 2;
60 }
61 if (0 != memcmp (data, cls, size))
62 {
63 GNUNET_break (0);
64 ok = 3;
65 }
66 return GNUNET_OK;
67}
68
69
70static void
71run (void *cls,
72 char *const *args,
73 const char *cfgfile,
74 const struct GNUNET_CONFIGURATION_Handle *cfg)
75{
76 struct GNUNET_DATACACHE_Handle *h;
77 struct GNUNET_HashCode k;
78 struct GNUNET_HashCode n;
79 struct GNUNET_TIME_Absolute exp;
80
81 (void) cls;
82 (void) args;
83 (void) cfgfile;
84 ok = 0;
85 h = GNUNET_DATACACHE_create (cfg,
86 "testcache");
87 if (h == NULL)
88 {
89 fprintf (stderr,
90 "%s",
91 "Failed to initialize datacache. Database likely not setup, skipping test.\n");
92 ok = 77; /* mark test as skipped */
93 return;
94 }
95 exp = GNUNET_TIME_absolute_get ();
96 exp.abs_value_us += 5 * 60 * 1000 * 1000LL;
97 memset (&k, 0, sizeof(struct GNUNET_HashCode));
98 for (unsigned int i = 0; i < 100; i++)
99 {
100 GNUNET_CRYPTO_hash (&k, sizeof(struct GNUNET_HashCode), &n);
101 ASSERT (GNUNET_OK ==
102 GNUNET_DATACACHE_put (h,
103 &k,
104 GNUNET_YES,
105 sizeof(struct GNUNET_HashCode),
106 (const char *) &n, 1 + i % 16, exp,
107 0, NULL));
108 k = n;
109 }
110 memset (&k,
111 0,
112 sizeof(struct GNUNET_HashCode));
113 for (unsigned int i = 0; i < 100; i++)
114 {
115 GNUNET_CRYPTO_hash (&k,
116 sizeof(struct GNUNET_HashCode),
117 &n);
118 ASSERT (1 == GNUNET_DATACACHE_get (h,
119 &k,
120 1 + i % 16,
121 &checkIt,
122 &n));
123 k = n;
124 }
125
126 memset (&k,
127 42,
128 sizeof(struct GNUNET_HashCode));
129 GNUNET_CRYPTO_hash (&k,
130 sizeof(struct GNUNET_HashCode),
131 &n);
132 ASSERT (GNUNET_OK ==
133 GNUNET_DATACACHE_put (h,
134 &k,
135 GNUNET_YES,
136 sizeof(struct GNUNET_HashCode),
137 (const char *) &n,
138 792,
139 GNUNET_TIME_UNIT_FOREVER_ABS,
140 0,
141 NULL));
142 ASSERT (0 != GNUNET_DATACACHE_get (h,
143 &k,
144 792,
145 &checkIt,
146 &n));
147 GNUNET_DATACACHE_destroy (h);
148 ASSERT (ok == 0);
149 return;
150FAILURE:
151 if (h != NULL)
152 GNUNET_DATACACHE_destroy (h);
153 ok = GNUNET_SYSERR;
154}
155
156
157int
158main (int argc, char *argv[])
159{
160 char cfg_name[PATH_MAX];
161 char *const xargv[] = {
162 "test-datacache",
163 "-c",
164 cfg_name,
165 NULL
166 };
167 struct GNUNET_GETOPT_CommandLineOption options[] = {
168 GNUNET_GETOPT_OPTION_END
169 };
170
171 (void) argc;
172 GNUNET_log_setup ("test-datacache",
173 "WARNING",
174 NULL);
175 plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
176 GNUNET_snprintf (cfg_name,
177 sizeof(cfg_name),
178 "test_datacache_data_%s.conf",
179 plugin_name);
180 GNUNET_PROGRAM_run ((sizeof(xargv) / sizeof(char *)) - 1,
181 xargv,
182 "test-datacache",
183 "nohelp",
184 options,
185 &run,
186 NULL);
187 if ((0 != ok) && (77 != ok))
188 fprintf (stderr,
189 "Missed some testcases: %d\n",
190 ok);
191 return ok;
192}
193
194
195/* 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 92807fbe2..000000000
--- a/src/datacache/test_datacache_quota.c
+++ /dev/null
@@ -1,164 +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/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 char buf[3200];
57 struct GNUNET_TIME_Absolute exp;
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 exp = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS);
74 memset (buf, 1, sizeof(buf));
75 memset (&k, 0, sizeof(struct GNUNET_HashCode));
76 for (unsigned int i = 0; i < 10; i++)
77 {
78 fprintf (stderr,
79 "%s",
80 ".");
81 GNUNET_CRYPTO_hash (&k,
82 sizeof(struct GNUNET_HashCode),
83 &n);
84 for (unsigned int j = i; j < sizeof(buf); j += 10)
85 {
86 exp.abs_value_us++;
87 buf[j] = i;
88 ASSERT (GNUNET_OK ==
89 GNUNET_DATACACHE_put (h,
90 &k,
91 GNUNET_YES,
92 j,
93 buf,
94 1 + i,
95 exp,
96 0,
97 NULL));
98 ASSERT (0 < GNUNET_DATACACHE_get (h, &k, 1 + i, NULL, NULL));
99 }
100 k = n;
101 }
102 fprintf (stderr, "%s", "\n");
103 memset (&k, 0, sizeof(struct GNUNET_HashCode));
104 for (unsigned int i = 0; i < 10; i++)
105 {
106 fprintf (stderr, "%s", ".");
107 GNUNET_CRYPTO_hash (&k, sizeof(struct GNUNET_HashCode), &n);
108 if (i < 2)
109 ASSERT (0 == GNUNET_DATACACHE_get (h, &k, 1 + i, NULL, NULL));
110 if (i == 9)
111 ASSERT (0 < GNUNET_DATACACHE_get (h, &k, 1 + i, NULL, NULL));
112 k = n;
113 }
114 fprintf (stderr, "%s", "\n");
115 GNUNET_DATACACHE_destroy (h);
116 return;
117FAILURE:
118 if (h != NULL)
119 GNUNET_DATACACHE_destroy (h);
120 ok = GNUNET_SYSERR;
121}
122
123
124int
125main (int argc,
126 char *argv[])
127{
128 char cfg_name[PATH_MAX];
129 char *const xargv[] = {
130 "test-datacache-quota",
131 "-c",
132 cfg_name,
133 NULL
134 };
135 struct GNUNET_GETOPT_CommandLineOption options[] = {
136 GNUNET_GETOPT_OPTION_END
137 };
138
139 (void) argc;
140 GNUNET_log_setup ("test-datacache-quota",
141 "WARNING",
142 NULL);
143
144 plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
145 GNUNET_snprintf (cfg_name,
146 sizeof(cfg_name),
147 "test_datacache_data_%s.conf",
148 plugin_name);
149 GNUNET_PROGRAM_run ((sizeof(xargv) / sizeof(char *)) - 1,
150 xargv,
151 "test-datacache-quota",
152 "nohelp",
153 options,
154 &run,
155 NULL);
156 if (0 != ok)
157 fprintf (stderr,
158 "Missed some testcases: %d\n",
159 ok);
160 return ok;
161}
162
163
164/* end of test_datacache_quota.c */