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