aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO2
-rw-r--r--configure.ac1
-rw-r--r--src/Makefile.am3
-rw-r--r--src/datacache/Makefile.am76
-rw-r--r--src/datacache/datacache_api.c261
-rw-r--r--src/datacache/plugin_datacache.h159
-rw-r--r--src/datacache/plugin_datacache_sqlite.c676
-rw-r--r--src/datacache/plugin_datacache_template.c151
-rw-r--r--src/datacache/test_datacache_api.c120
-rw-r--r--src/datastore/Makefile.am2
-rw-r--r--src/datastore/plugin_datastore_template.c15
-rw-r--r--src/include/gnunet_datacache_lib.h16
12 files changed, 1472 insertions, 10 deletions
diff --git a/TODO b/TODO
index 07d082161..6c3bdeef2 100644
--- a/TODO
+++ b/TODO
@@ -58,7 +58,7 @@ that would cause them to be executed and check that they are working:
58 58
59 59
60Module features to implement: 60Module features to implement:
61* Dstore (needed for DHT) 61* datacache (needed for DHT)
62 - design plugin API 62 - design plugin API
63 - implement sqlite-based dstore plugin 63 - implement sqlite-based dstore plugin
64 - implement dstore API 64 - implement dstore API
diff --git a/configure.ac b/configure.ac
index 30aeb32f6..9932e9092 100644
--- a/configure.ac
+++ b/configure.ac
@@ -745,6 +745,7 @@ po/Makefile.in
745src/Makefile 745src/Makefile
746src/arm/Makefile 746src/arm/Makefile
747src/core/Makefile 747src/core/Makefile
748src/datacache/Makefile
748src/datastore/Makefile 749src/datastore/Makefile
749src/fragmentation/Makefile 750src/fragmentation/Makefile
750src/hello/Makefile 751src/hello/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index e4335db9d..42a668c75 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,6 +11,8 @@ SUBDIRS = \
11 include $(INTLEMU_SUBDIRS) \ 11 include $(INTLEMU_SUBDIRS) \
12 util \ 12 util \
13 arm \ 13 arm \
14 datacache \
15 datastore \
14 fragmentation \ 16 fragmentation \
15 hello \ 17 hello \
16 peerinfo \ 18 peerinfo \
@@ -19,7 +21,6 @@ SUBDIRS = \
19 template \ 21 template \
20 transport \ 22 transport \
21 core \ 23 core \
22 datastore \
23 $(HOSTLIST_DIR) \ 24 $(HOSTLIST_DIR) \
24 topology 25 topology
25 26
diff --git a/src/datacache/Makefile.am b/src/datacache/Makefile.am
new file mode 100644
index 000000000..80b56bba1
--- /dev/null
+++ b/src/datacache/Makefile.am
@@ -0,0 +1,76 @@
1INCLUDES = -I$(top_srcdir)/src/include
2
3plugindir = $(libdir)/gnunet
4
5if MINGW
6 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
7endif
8
9if USE_COVERAGE
10 AM_CFLAGS = --coverage -O0
11 XLIBS = -lgcov
12endif
13
14
15lib_LTLIBRARIES = \
16 libgnunetdatacache.la
17
18libgnunetdatacache_la_SOURCES = \
19 datacache_api.c plugin_datacache.h
20libgnunetdatacache_la_LIBADD = \
21 $(top_builddir)/src/util/libgnunetutil.la \
22 $(GN_LIBINTL)
23libgnunetdatacache_la_LDFLAGS = \
24 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
25 -version-info 0:0:0
26
27
28plugin_LTLIBRARIES = \
29 libgnunet_plugin_datacache_sqlite.la \
30 libgnunet_plugin_datacache_template.la
31
32
33libgnunet_plugin_datacache_sqlite_la_SOURCES = \
34 plugin_datacache_sqlite.c
35libgnunet_plugin_datacache_sqlite_la_LIBADD = \
36 $(top_builddir)/src/statistics/libgnunetstatistics.la \
37 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3
38libgnunet_plugin_datacache_sqlite_la_LDFLAGS = \
39 $(GN_PLUGIN_LDFLAGS)
40
41libgnunet_plugin_datacache_template_la_SOURCES = \
42 plugin_datacache_template.c
43libgnunet_plugin_datacache_template_la_LIBADD = \
44 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS)
45libgnunet_plugin_datacache_template_la_LDFLAGS = \
46 $(GN_PLUGIN_LDFLAGS)
47
48
49#check_PROGRAMS = \
50# test_datacache_api \
51# perf_datacache_api \
52# perf_plugin_datacache
53#
54#TESTS = $(check_PROGRAMS)
55#
56#test_datacache_api_SOURCES = \
57# test_datacache_api.c
58#test_datacache_api_LDADD = \
59# $(top_builddir)/src/datacache/libgnunetdatacache.la \
60# $(top_builddir)/src/util/libgnunetutil.la
61#
62#perf_datacache_api_SOURCES = \
63# perf_datacache_api.c
64#perf_datacache_api_LDADD = \
65# $(top_builddir)/src/datacache/libgnunetdatacache.la \
66# $(top_builddir)/src/util/libgnunetutil.la
67#
68#perf_plugin_datacache_SOURCES = \
69# perf_plugin_datacache.c
70#perf_plugin_datacache_LDADD = \
71# $(top_builddir)/src/util/libgnunetutil.la
72#
73#
74#EXTRA_DIST = \
75# test_datacache_api_data.conf \
76# perf_plugin_datacache_data.conf
diff --git a/src/datacache/datacache_api.c b/src/datacache/datacache_api.c
new file mode 100644
index 000000000..1fe428b08
--- /dev/null
+++ b/src/datacache/datacache_api.c
@@ -0,0 +1,261 @@
1/*
2 This file is part of GNUnet
3 (C) 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file datacache/datacache_api.c
23 * @brief datacache API implementation
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_datacache_lib.h"
29#include "plugin_datacache.h"
30
31/**
32 * Internal state of the datacache library.
33 */
34struct GNUNET_DATACACHE_Handle
35{
36
37 /**
38 * Our datastore plugin (NULL if not available).
39 */
40 struct DatastorePlugin *plugin;
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 struct GNUNET_CONFIGURATION_Handle *cfg;
51
52 /**
53 * Configuration section to use.
54 */
55 char *section;
56
57 /**
58 * API of the transport as returned by the plugin's
59 * initialization function.
60 */
61 struct GNUNET_DATACACHE_PluginFunctions *api;
62
63 /**
64 * Short name for the plugin (i.e. "sqlite").
65 */
66 char *short_name;
67
68 /**
69 * Name of the library (i.e. "gnunet_plugin_datacache_sqlite").
70 */
71 char *lib_name;
72
73 /**
74 * Environment provided to our plugin.
75 */
76 struct GNUNET_DATASTORE_PluginEnvironment env;
77
78 /**
79 * How much space is in use right now?
80 */
81 unsigned long long utilization;
82
83};
84
85
86/**
87 * Function called by plugins to notify the datacache
88 * about content deletions.
89 *
90 * @param cls closure
91 * @param key key of the content that was deleted
92 * @param size number of bytes that were made available
93 */
94static void
95env_delete_notify (void *cls,
96 const GNUNET_HashCode *key,
97 uint32_t size)
98{
99 struct GNUNET_DATACACHE_Handle * h = cls;
100 GNUNET_assert (h->utilization >= size);
101 h->utilization -= size;
102 GNUNET_CONTAINER_bloomfilter_remove (h->filter, key);
103}
104
105
106/**
107 * Create a data cache.
108 *
109 * @param sched scheduler to use
110 * @param cfg configuration to use
111 * @param section section in the configuration that contains our options
112 * @return handle to use to access the service
113 */
114struct GNUNET_DATACACHE_Handle *
115GNUNET_DATACACHE_create (struct GNUNET_SCHEDULER_Handle *sched,
116 struct GNUNET_CONFIGURATION_Handle *cfg,
117 const char *section)
118{
119 unsigned int bf_size;
120 struct GNUNET_DATACACHE_Handle *ret;
121 struct DatacachePlugin *ret;
122 char *libname;
123 char *name;
124
125 if (GNUNET_OK !=
126 GNUNET_CONFIGURATION_get_value_number (c,
127 section, "QUOTA", &quota))
128 {
129 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
130 _("No `%s' specified for `%s' in configuration!\n"),
131 "QUOTA",
132 section);
133 return;
134 }
135 if (GNUNET_OK !=
136 GNUNET_CONFIGURATION_get_value_string (cfg,
137 section,
138 "DATABASE", &name))
139 {
140 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
141 _("No `%s' specified for `%s' in configuration!\n"),
142 "DATABASE",
143 section);
144 return NULL;
145 }
146 bf_size = quota / 32; /* 8 bit per entry, 1 bit per 32 kb in DB */
147
148 ret = GNUNET_malloc (sizeof(struct GNUNET_DATACACHE_Handle));
149 /* FIXME: create a temporary file for the bloomfilter to better
150 support deletions! */
151 ret->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, bf_size, 5); /* approx. 3% false positives at max use */
152 ret->section = GNUNET_strdup (section);
153 ret->env.sched = s;
154 ret->env.cfg = cfg;
155 ret->env.delete_notify = &env_delete_notify;
156 ret->env.section = ret->section;
157 ret->env.cls = ret;
158 ret->env.delete_notify = &delete_notify;
159 ret->env.quota = quota;
160 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
161 _("Loading `%s' datacache plugin\n"), name);
162 GNUNET_asprintf (&libname, "libgnunet_plugin_datacache_%s", name);
163 ret->short_name = name;
164 ret->lib_name = libname;
165 ret->api = GNUNET_PLUGIN_load (libname, &ret->env);
166 if (ret->api == NULL)
167 {
168 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
169 _("Failed to load datacache plugin for `%s'\n"), name);
170 GNUNET_DATACACHE_destroy (ret);
171 return NULL;
172 }
173 return ret;
174}
175
176
177/**
178 * Destroy a data cache (and free associated resources).
179 *
180 * @param h handle to the datastore
181 */
182void GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h)
183{
184 GNUNET_CONTAINER_bloomfilter_free (h->filter);
185 if (h->api != NULL)
186 GNUNET_break (NULL == GNUNET_PLUGIN_unload (h->lib_name, h->api));
187 GNUNET_free (h->lib_name);
188 GNUNET_free (h->short_name);
189 GNUNET_free (h->section);
190 GNUNET_free (h);
191}
192
193
194/**
195 * Store an item in the datastore.
196 *
197 * @param h handle to the datacache
198 * @param key key to store data under
199 * @param size number of bytes in data
200 * @param data data to store
201 * @param type type of the value
202 * @param discard_time when to discard the value in any case
203 * @return GNUNET_OK on success, GNUNET_SYSERR on error (full, etc.)
204 */
205int
206GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h,
207 const GNUNET_HashCode * key,
208 uint32_t size,
209 const char *data,
210 unsigned int type,
211 struct GNUNET_TIME_Absolute discard_time)
212{
213 uint32_t used;
214
215 used = h->api->put (h->api->cls,
216 key,
217 size,
218 data,
219 type,
220 discard_time);
221 if (used == 0)
222 return GNUNET_SYSERR;
223 GNUNET_CONTAINER_bloomfilter_add (h->filter, key);
224 while (h->utilization + used > h->api.quota)
225 GNUNET_assert (GNUNET_OK == h->api->del (h->api->cls));
226 h->utilization += used;
227 return GNUNET_OK;
228}
229
230
231/**
232 * Iterate over the results for a particular key
233 * in the datacache.
234 *
235 * @param h handle to the datacache
236 * @param key what to look up
237 * @param type entries of which type are relevant?
238 * @param iter maybe NULL (to just count)
239 * @param iter_cls closure for iter
240 * @return the number of results found
241 */
242unsigned int
243GNUNET_DATACACHE_get (struct GNUNET_DATACACHE_Handle *h,
244 const GNUNET_HashCode * key,
245 unsigned int type,
246 GNUNET_DATACACHE_Iterator iter,
247 void *iter_cls)
248{
249 if (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_test (h->filter,
250 key))
251 return 0; /* can not be present */
252 return h->api->get (h->api->cls,
253 key,
254 type,
255 iter,
256 iter_cls);
257}
258
259
260
261/* end of datacache_api.c */
diff --git a/src/datacache/plugin_datacache.h b/src/datacache/plugin_datacache.h
new file mode 100644
index 000000000..e099cd31d
--- /dev/null
+++ b/src/datacache/plugin_datacache.h
@@ -0,0 +1,159 @@
1/*
2 This file is part of GNUnet
3 (C) 2006, 2009 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file datacache/plugin_datacache.h
23 * @brief API for database backends for the datacache
24 * @author Christian Grothoff
25 */
26#ifndef PLUGIN_DATACACHE_H
27#define PLUGIN_DATACACHE_H
28
29#include "gnunet_datacache_lib.h"
30
31#ifdef __cplusplus
32extern "C"
33{
34#if 0 /* keep Emacsens' auto-indent happy */
35}
36#endif
37#endif
38
39
40/**
41 * Function called by plugins to notify the datacache
42 * about content deletions.
43 *
44 * @param cls closure
45 * @param key key of the content that was deleted
46 * @param size number of bytes that were made available
47 */
48typedef void (*GNUNET_DATACACHE_DeleteNotifyCallback)(void *cls,
49 const GNUNET_HashCode *key,
50 uint32_t size);
51
52
53/**
54 * The datastore service will pass a pointer to a struct
55 * of this type as the first and only argument to the
56 * entry point of each datastore plugin.
57 */
58struct GNUNET_DATACACHE_PluginEnvironment
59{
60
61 /**
62 * Scheduler to use.
63 */
64 struct GNUNET_SCHEDULER_Handle *sched;
65
66 /**
67 * Configuration to use.
68 */
69 struct GNUNET_CONFIGURATION_Handle *cfg;
70
71 /**
72 * Configuration section to use.
73 */
74 const char *section;
75
76 /**
77 * Closure to use for callbacks.
78 */
79 void *cls;
80
81 /**
82 * Function to call whenever the plugin needs to
83 * discard content that it was asked to store.
84 */
85 GNUNET_DATACACHE_DeleteNotifyCallback delete_notify;
86
87 /**
88 * How much space are we allowed to use?
89 */
90 unsigned long long quota;
91
92};
93
94
95/**
96 * @brief struct returned by the initialization function of the plugin
97 */
98struct GNUNET_DATACACHE_PluginFunctions {
99
100 /**
101 * Closure to pass to all plugin functions.
102 */
103 void *cls;
104
105 /**
106 * Store an item in the datastore.
107 *
108 * @param key key to store data under
109 * @param size number of bytes in data
110 * @param data data to store
111 * @param type type of the value
112 * @param discard_time when to discard the value in any case
113 * @return 0 on error, number of bytes used otherwise
114 */
115 uint32_t (*put) (void *cls,
116 const GNUNET_HashCode * key,
117 uint32_t size,
118 const char *data,
119 uint32_t type,
120 struct GNUNET_TIME_Absolute discard_time);
121
122
123 /**
124 * Iterate over the results for a particular key
125 * in the datastore.
126 *
127 * @param key
128 * @param type entries of which type are relevant?
129 * @param iter maybe NULL (to just count)
130 * @return the number of results found
131 */
132 unsigned int (*get) (void *cls,
133 const GNUNET_HashCode * key,
134 uint32_t type,
135 GNUNET_DATACACHE_Iterator iter,
136 void *iter_cls);
137
138
139 /**
140 * Delete the entry with the lowest expiration value
141 * from the datacache right now.
142 *
143 * @return GNUNET_OK on success, GNUNET_SYSERR on error
144 */
145 int (*del) (void *cls);
146
147
148};
149
150
151#if 0 /* keep Emacsens' auto-indent happy */
152{
153#endif
154#ifdef __cplusplus
155}
156#endif
157
158/* end of plugin_datacache.h */
159#endif
diff --git a/src/datacache/plugin_datacache_sqlite.c b/src/datacache/plugin_datacache_sqlite.c
new file mode 100644
index 000000000..e386b55de
--- /dev/null
+++ b/src/datacache/plugin_datacache_sqlite.c
@@ -0,0 +1,676 @@
1/*
2 This file is part of GNUnet.
3 (C) 2006, 2007, 2008 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file applications/dstore_sqlite/dstore.c
23 * @brief SQLite based implementation of the dstore service
24 * @author Christian Grothoff
25 * @todo Indexes, statistics
26 *
27 * Database: SQLite
28 */
29
30#include "platform.h"
31#include "gnunet_util.h"
32#include "gnunet_dstore_service.h"
33#include "gnunet_stats_service.h"
34#include <sqlite3.h>
35
36#define DEBUG_DSTORE GNUNET_NO
37
38/**
39 * Maximum size for an individual item.
40 */
41#define MAX_CONTENT_SIZE 65536
42
43/**
44 * Bytes used
45 */
46static unsigned long long payload;
47
48/**
49 * Maximum bytes available
50 */
51static unsigned long long quota;
52
53/**
54 * Filename of this database
55 */
56static char *fn;
57static char *fn_utf8;
58
59static GNUNET_CoreAPIForPlugins *coreAPI;
60
61static struct GNUNET_Mutex *lock;
62
63/**
64 * Statistics service.
65 */
66static GNUNET_Stats_ServiceAPI *stats;
67
68static unsigned int stat_dstore_size;
69
70static unsigned int stat_dstore_quota;
71
72/**
73 * Estimate of the per-entry overhead (including indices).
74 */
75#define OVERHEAD ((4*2+4*2+8*2+8*2+sizeof(GNUNET_HashCode)*5+32))
76
77struct GNUNET_BloomFilter *bloom;
78
79static char *bloom_name;
80
81/**
82 * @brief Prepare a SQL statement
83 */
84static int
85sq_prepare (sqlite3 * dbh, const char *zSql, /* SQL statement, UTF-8 encoded */
86 sqlite3_stmt ** ppStmt)
87{ /* OUT: Statement handle */
88 char *dummy;
89 return sqlite3_prepare (dbh,
90 zSql,
91 strlen (zSql), ppStmt, (const char **) &dummy);
92}
93
94#define SQLITE3_EXEC(db, cmd) do { emsg = NULL; if (SQLITE_OK != sqlite3_exec(db, cmd, NULL, NULL, &emsg)) { GNUNET_GE_LOG(coreAPI->ectx, GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK, _("`%s' failed at %s:%d with error: %s\n"), "sqlite3_exec", __FILE__, __LINE__, emsg); sqlite3_free(emsg); } } while(0)
95
96/**
97 * Log an error message at log-level 'level' that indicates
98 * a failure of the command 'cmd' on file 'filename'
99 * with the message given by strerror(errno).
100 */
101#define LOG_SQLITE(db, level, cmd) do { GNUNET_GE_LOG(coreAPI->ectx, level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db)); } while(0)
102
103static void
104db_init (sqlite3 * dbh)
105{
106 char *emsg;
107
108 SQLITE3_EXEC (dbh, "PRAGMA temp_store=MEMORY");
109 SQLITE3_EXEC (dbh, "PRAGMA synchronous=OFF");
110 SQLITE3_EXEC (dbh, "PRAGMA count_changes=OFF");
111 SQLITE3_EXEC (dbh, "PRAGMA page_size=4092");
112 SQLITE3_EXEC (dbh,
113 "CREATE TABLE ds080 ("
114 " size INTEGER NOT NULL DEFAULT 0,"
115 " type INTEGER NOT NULL DEFAULT 0,"
116 " puttime INTEGER NOT NULL DEFAULT 0,"
117 " expire INTEGER NOT NULL DEFAULT 0,"
118 " key BLOB NOT NULL DEFAULT '',"
119 " vhash BLOB NOT NULL DEFAULT '',"
120 " value BLOB NOT NULL DEFAULT '')");
121 SQLITE3_EXEC (dbh, "CREATE INDEX idx_hashidx ON ds080 (key,type,expire)");
122 SQLITE3_EXEC (dbh,
123 "CREATE INDEX idx_allidx ON ds080 (key,vhash,type,size)");
124 SQLITE3_EXEC (dbh, "CREATE INDEX idx_puttime ON ds080 (puttime)");
125}
126
127static int
128db_reset ()
129{
130 int fd;
131 sqlite3 *dbh;
132 char *tmpl;
133 const char *tmpdir;
134
135 if (fn != NULL)
136 {
137 UNLINK (fn);
138 GNUNET_free (fn);
139 GNUNET_free (fn_utf8);
140 }
141 payload = 0;
142
143 tmpdir = getenv ("TMPDIR");
144 tmpdir = tmpdir ? tmpdir : "/tmp";
145
146#define TEMPLATE "/gnunet-dstoreXXXXXX"
147 tmpl = GNUNET_malloc (strlen (tmpdir) + sizeof (TEMPLATE) + 1);
148 strcpy (tmpl, tmpdir);
149 strcat (tmpl, TEMPLATE);
150#undef TEMPLATE
151
152#ifdef MINGW
153 fn = (char *) GNUNET_malloc (MAX_PATH + 1);
154 plibc_conv_to_win_path (tmpl, fn);
155 GNUNET_free (tmpl);
156#else
157 fn = tmpl;
158#endif
159 fd = mkstemp (fn);
160 if (fd == -1)
161 {
162 GNUNET_GE_BREAK (NULL, 0);
163 GNUNET_free (fn);
164 fn = NULL;
165 return GNUNET_SYSERR;
166 }
167 CLOSE (fd);
168 fn_utf8 = GNUNET_convert_string_to_utf8 (coreAPI->ectx, fn, strlen (fn),
169#ifdef ENABLE_NLS
170 nl_langinfo (CODESET)
171#else
172 "UTF-8" /* good luck */
173#endif
174 );
175 if (SQLITE_OK != sqlite3_open (fn_utf8, &dbh))
176 {
177 GNUNET_free (fn);
178 GNUNET_free (fn_utf8);
179 fn = NULL;
180 return GNUNET_SYSERR;
181 }
182 db_init (dbh);
183 sqlite3_close (dbh);
184 return GNUNET_OK;
185}
186
187/**
188 * Check that we are within quota.
189 * @return GNUNET_OK if we are.
190 */
191static int
192checkQuota (sqlite3 * dbh)
193{
194 GNUNET_HashCode dkey;
195 GNUNET_HashCode vhash;
196 unsigned int dsize;
197 unsigned int dtype;
198 sqlite3_stmt *stmt;
199 sqlite3_stmt *dstmt;
200 int err;
201
202 if (payload * 10 <= quota * 9)
203 return GNUNET_OK; /* we seem to be about 10% off */
204#if DEBUG_DSTORE
205 GNUNET_GE_LOG (coreAPI->ectx,
206 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER,
207 "DStore above qutoa (have %llu, allowed %llu), will delete some data.\n",
208 payload, quota);
209#endif
210 stmt = NULL;
211 dstmt = NULL;
212 if ((sq_prepare (dbh,
213 "SELECT size, type, key, vhash FROM ds080 ORDER BY puttime ASC LIMIT 1",
214 &stmt) != SQLITE_OK) ||
215 (sq_prepare (dbh,
216 "DELETE FROM ds080 "
217 "WHERE key=? AND vhash=? AND type=? AND size=?",
218 &dstmt) != SQLITE_OK))
219 {
220 GNUNET_GE_LOG (coreAPI->ectx,
221 GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
222 _("`%s' failed at %s:%d with error: %s\n"),
223 "sq_prepare", __FILE__, __LINE__, sqlite3_errmsg (dbh));
224 GNUNET_GE_BREAK (NULL, 0);
225 if (dstmt != NULL)
226 sqlite3_finalize (dstmt);
227 if (stmt != NULL)
228 sqlite3_finalize (stmt);
229 return GNUNET_SYSERR;
230 }
231 err = SQLITE_DONE;
232 while ((payload * 10 > quota * 9) && /* we seem to be about 10% off */
233 ((err = sqlite3_step (stmt)) == SQLITE_ROW))
234 {
235 dsize = sqlite3_column_int (stmt, 0);
236 dtype = sqlite3_column_int (stmt, 1);
237 GNUNET_GE_BREAK (NULL,
238 sqlite3_column_bytes (stmt,
239 2) == sizeof (GNUNET_HashCode));
240 GNUNET_GE_BREAK (NULL,
241 sqlite3_column_bytes (stmt,
242 3) == sizeof (GNUNET_HashCode));
243 memcpy (&dkey, sqlite3_column_blob (stmt, 2), sizeof (GNUNET_HashCode));
244 memcpy (&vhash, sqlite3_column_blob (stmt, 3),
245 sizeof (GNUNET_HashCode));
246 sqlite3_reset (stmt);
247 sqlite3_bind_blob (dstmt,
248 1, &dkey, sizeof (GNUNET_HashCode),
249 SQLITE_TRANSIENT);
250 sqlite3_bind_blob (dstmt,
251 2, &vhash, sizeof (GNUNET_HashCode),
252 SQLITE_TRANSIENT);
253 sqlite3_bind_int (dstmt, 3, dtype);
254 sqlite3_bind_int (dstmt, 4, dsize);
255 if ((err = sqlite3_step (dstmt)) != SQLITE_DONE)
256 {
257 GNUNET_GE_LOG (coreAPI->ectx,
258 GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
259 _("`%s' failed at %s:%d with error: %s\n"),
260 "sqlite3_step", __FILE__, __LINE__,
261 sqlite3_errmsg (dbh));
262 sqlite3_reset (dstmt);
263 GNUNET_GE_BREAK (NULL, 0); /* should delete but cannot!? */
264 break;
265 }
266 if (sqlite3_total_changes (dbh) > 0)
267 {
268 if (bloom != NULL)
269 GNUNET_bloomfilter_remove (bloom, &dkey);
270 payload -= (dsize + OVERHEAD);
271 }
272#if DEBUG_DSTORE
273 GNUNET_GE_LOG (coreAPI->ectx,
274 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
275 GNUNET_GE_DEVELOPER,
276 "Deleting %u bytes decreases DStore payload to %llu out of %llu\n",
277 dsize, payload, quota);
278#endif
279 sqlite3_reset (dstmt);
280 }
281 if (err != SQLITE_DONE)
282 {
283 GNUNET_GE_LOG (coreAPI->ectx,
284 GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
285 _("`%s' failed at %s:%d with error: %s\n"),
286 "sqlite3_step", __FILE__, __LINE__,
287 sqlite3_errmsg (dbh));
288 }
289 sqlite3_finalize (dstmt);
290 sqlite3_finalize (stmt);
291 if (payload * 10 > quota * 9)
292 {
293 /* we seem to be about 10% off */
294 GNUNET_GE_LOG (coreAPI->ectx,
295 GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_DEVELOPER,
296 "Failed to delete content to drop below quota (bug?).\n",
297 payload, quota);
298 return GNUNET_SYSERR;
299 }
300 return GNUNET_OK;
301}
302
303/**
304 * Store an item in the datastore.
305 *
306 * @return GNUNET_OK on success, GNUNET_SYSERR on error
307 */
308static int
309d_put (const GNUNET_HashCode * key,
310 unsigned int type,
311 GNUNET_CronTime discard_time, unsigned int size, const char *data)
312{
313 GNUNET_HashCode vhash;
314 sqlite3 *dbh;
315 sqlite3_stmt *stmt;
316 int ret;
317 GNUNET_CronTime now;
318
319 if (size > MAX_CONTENT_SIZE)
320 return GNUNET_SYSERR;
321 GNUNET_hash (data, size, &vhash);
322 GNUNET_mutex_lock (lock);
323 if ((fn == NULL) || (SQLITE_OK != sqlite3_open (fn_utf8, &dbh)))
324 {
325 db_reset (dbh);
326 GNUNET_mutex_unlock (lock);
327 return GNUNET_SYSERR;
328 }
329 now = GNUNET_get_time ();
330#if DEBUG_DSTORE
331 GNUNET_GE_LOG (coreAPI->ectx,
332 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER,
333 "dstore processes put `%.*s' with expiration %llu\n",
334 size, data, discard_time);
335#endif
336
337 /* first try UPDATE */
338 if (sq_prepare (dbh,
339 "UPDATE ds080 SET puttime=?, expire=? "
340 "WHERE key=? AND vhash=? AND type=? AND size=?",
341 &stmt) != SQLITE_OK)
342 {
343 GNUNET_GE_LOG (coreAPI->ectx,
344 GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
345 _("`%s' failed at %s:%d with error: %s\n"),
346 "sq_prepare", __FILE__, __LINE__, sqlite3_errmsg (dbh));
347 sqlite3_close (dbh);
348 GNUNET_mutex_unlock (lock);
349 return GNUNET_SYSERR;
350 }
351 if ((SQLITE_OK !=
352 sqlite3_bind_int64 (stmt, 1, now)) ||
353 (SQLITE_OK !=
354 sqlite3_bind_int64 (stmt, 2, discard_time)) ||
355 (SQLITE_OK !=
356 sqlite3_bind_blob (stmt, 3, key, sizeof (GNUNET_HashCode),
357 SQLITE_TRANSIENT)) ||
358 (SQLITE_OK !=
359 sqlite3_bind_blob (stmt, 4, &vhash, sizeof (GNUNET_HashCode),
360 SQLITE_TRANSIENT)) ||
361 (SQLITE_OK != sqlite3_bind_int (stmt, 5, type)) ||
362 (SQLITE_OK != sqlite3_bind_int (stmt, 6, size)))
363 {
364 GNUNET_GE_LOG (coreAPI->ectx,
365 GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
366 _("`%s' failed at %s:%d with error: %s\n"),
367 "sqlite3_bind_xxx", __FILE__, __LINE__,
368 sqlite3_errmsg (dbh));
369 sqlite3_finalize (stmt);
370 sqlite3_close (dbh);
371 GNUNET_mutex_unlock (lock);
372 return GNUNET_SYSERR;
373 }
374 if (SQLITE_DONE != sqlite3_step (stmt))
375 {
376 GNUNET_GE_LOG (coreAPI->ectx,
377 GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
378 _("`%s' failed at %s:%d with error: %s\n"),
379 "sqlite3_step", __FILE__, __LINE__,
380 sqlite3_errmsg (dbh));
381 sqlite3_finalize (stmt);
382 sqlite3_close (dbh);
383 GNUNET_mutex_unlock (lock);
384 return GNUNET_SYSERR;
385 }
386 ret = sqlite3_changes (dbh);
387 sqlite3_finalize (stmt);
388 if (ret > 0)
389 {
390 sqlite3_close (dbh);
391 GNUNET_mutex_unlock (lock);
392 return GNUNET_OK;
393 }
394 if (GNUNET_OK != checkQuota (dbh))
395 {
396 sqlite3_close (dbh);
397 GNUNET_mutex_unlock (lock);
398 return GNUNET_SYSERR;
399 }
400 if (sq_prepare (dbh,
401 "INSERT INTO ds080 "
402 "(size, type, puttime, expire, key, vhash, value) "
403 "VALUES (?, ?, ?, ?, ?, ?, ?)", &stmt) != SQLITE_OK)
404 {
405 GNUNET_GE_LOG (coreAPI->ectx,
406 GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
407 _("`%s' failed at %s:%d with error: %s\n"),
408 "sq_prepare", __FILE__, __LINE__, sqlite3_errmsg (dbh));
409 sqlite3_close (dbh);
410 GNUNET_mutex_unlock (lock);
411 return GNUNET_SYSERR;
412 }
413 if ((SQLITE_OK == sqlite3_bind_int (stmt, 1, size)) &&
414 (SQLITE_OK == sqlite3_bind_int (stmt, 2, type)) &&
415 (SQLITE_OK == sqlite3_bind_int64 (stmt, 3, now)) &&
416 (SQLITE_OK == sqlite3_bind_int64 (stmt, 4, discard_time)) &&
417 (SQLITE_OK ==
418 sqlite3_bind_blob (stmt, 5, key, sizeof (GNUNET_HashCode),
419 SQLITE_TRANSIENT)) &&
420 (SQLITE_OK ==
421 sqlite3_bind_blob (stmt, 6, &vhash, sizeof (GNUNET_HashCode),
422 SQLITE_TRANSIENT))
423 && (SQLITE_OK ==
424 sqlite3_bind_blob (stmt, 7, data, size, SQLITE_TRANSIENT)))
425 {
426 if (SQLITE_DONE != sqlite3_step (stmt))
427 {
428 LOG_SQLITE (dbh,
429 GNUNET_GE_ERROR | GNUNET_GE_DEVELOPER | GNUNET_GE_ADMIN
430 | GNUNET_GE_BULK, "sqlite3_step");
431 }
432 else
433 {
434 payload += size + OVERHEAD;
435 if (bloom != NULL)
436 GNUNET_bloomfilter_add (bloom, key);
437 }
438 if (SQLITE_OK != sqlite3_finalize (stmt))
439 LOG_SQLITE (dbh,
440 GNUNET_GE_ERROR | GNUNET_GE_DEVELOPER | GNUNET_GE_ADMIN |
441 GNUNET_GE_BULK, "sqlite3_finalize");
442 }
443 else
444 {
445 LOG_SQLITE (dbh,
446 GNUNET_GE_ERROR | GNUNET_GE_DEVELOPER | GNUNET_GE_ADMIN |
447 GNUNET_GE_BULK, "sqlite3_bind_xxx");
448 }
449#if DEBUG_DSTORE
450 GNUNET_GE_LOG (coreAPI->ectx,
451 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER,
452 "Storing %u bytes increases DStore payload to %llu out of %llu\n",
453 size, payload, quota);
454#endif
455 checkQuota (dbh);
456 sqlite3_close (dbh);
457 GNUNET_mutex_unlock (lock);
458 if (stats != NULL)
459 stats->set (stat_dstore_size, payload);
460 return GNUNET_OK;
461}
462
463/**
464 * Iterate over the results for a particular key
465 * in the datastore.
466 *
467 * @param key
468 * @param type entries of which type are relevant?
469 * @param iter maybe NULL (to just count)
470 * @return the number of results, GNUNET_SYSERR if the
471 * iter is non-NULL and aborted the iteration
472 */
473static int
474d_get (const GNUNET_HashCode * key,
475 unsigned int type, GNUNET_ResultProcessor handler, void *closure)
476{
477 sqlite3 *dbh;
478 sqlite3_stmt *stmt;
479 GNUNET_CronTime now;
480 unsigned int size;
481 const char *dat;
482 unsigned int cnt;
483 unsigned int off;
484 unsigned int total;
485 char scratch[256];
486
487 GNUNET_mutex_lock (lock);
488 if ((bloom != NULL) && (GNUNET_NO == GNUNET_bloomfilter_test (bloom, key)))
489 {
490 GNUNET_mutex_unlock (lock);
491 return 0;
492 }
493 if ((fn == NULL) || (SQLITE_OK != sqlite3_open (fn_utf8, &dbh)))
494 {
495 db_reset (dbh);
496 GNUNET_mutex_unlock (lock);
497 return GNUNET_SYSERR;
498 }
499 now = GNUNET_get_time ();
500#if DEBUG_DSTORE
501 GNUNET_GE_LOG (coreAPI->ectx,
502 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER,
503 "dstore processes get at `%llu'\n", now);
504#endif
505 if (sq_prepare (dbh,
506 "SELECT count(*) FROM ds080 WHERE key=? AND type=? AND expire >= ?",
507 &stmt) != SQLITE_OK)
508 {
509 GNUNET_GE_LOG (coreAPI->ectx,
510 GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
511 _("`%s' failed at %s:%d with error: %s\n"),
512 "sq_prepare", __FILE__, __LINE__, sqlite3_errmsg (dbh));
513 sqlite3_close (dbh);
514 db_reset (dbh);
515 GNUNET_mutex_unlock (lock);
516 return GNUNET_SYSERR;
517 }
518 sqlite3_bind_blob (stmt, 1, key, sizeof (GNUNET_HashCode),
519 SQLITE_TRANSIENT);
520 sqlite3_bind_int (stmt, 2, type);
521 sqlite3_bind_int64 (stmt, 3, now);
522 if (SQLITE_ROW != sqlite3_step (stmt))
523 {
524 LOG_SQLITE (dbh,
525 GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_USER |
526 GNUNET_GE_BULK, "sqlite_step");
527 sqlite3_reset (stmt);
528 sqlite3_finalize (stmt);
529 db_reset (dbh);
530 GNUNET_mutex_unlock (lock);
531 return GNUNET_SYSERR;
532 }
533 total = sqlite3_column_int (stmt, 0);
534 sqlite3_reset (stmt);
535 sqlite3_finalize (stmt);
536 if ((total == 0) || (handler == NULL))
537 {
538 sqlite3_close (dbh);
539 GNUNET_mutex_unlock (lock);
540 return total;
541 }
542
543 cnt = 0;
544 off = GNUNET_random_u32 (GNUNET_RANDOM_QUALITY_WEAK, total);
545 while (cnt < total)
546 {
547 off = (off + 1) % total;
548 GNUNET_snprintf (scratch, 256,
549 "SELECT size, value FROM ds080 WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET %u",
550 off);
551 if (sq_prepare (dbh, scratch, &stmt) != SQLITE_OK)
552 {
553 GNUNET_GE_LOG (coreAPI->ectx,
554 GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
555 _("`%s' failed at %s:%d with error: %s\n"),
556 "sq_prepare", __FILE__, __LINE__,
557 sqlite3_errmsg (dbh));
558 sqlite3_close (dbh);
559 GNUNET_mutex_unlock (lock);
560 return GNUNET_SYSERR;
561 }
562 sqlite3_bind_blob (stmt, 1, key, sizeof (GNUNET_HashCode),
563 SQLITE_TRANSIENT);
564 sqlite3_bind_int (stmt, 2, type);
565 sqlite3_bind_int64 (stmt, 3, now);
566 if (sqlite3_step (stmt) != SQLITE_ROW)
567 break;
568 size = sqlite3_column_int (stmt, 0);
569 if (size != sqlite3_column_bytes (stmt, 1))
570 {
571 GNUNET_GE_BREAK (NULL, 0);
572 sqlite3_finalize (stmt);
573 continue;
574 }
575 dat = sqlite3_column_blob (stmt, 1);
576 cnt++;
577#if DEBUG_DSTORE
578 GNUNET_GE_LOG (coreAPI->ectx,
579 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
580 GNUNET_GE_DEVELOPER,
581 "dstore found result for get: `%.*s'\n", size, dat);
582#endif
583 if ((handler != NULL) &&
584 (GNUNET_OK != handler (key, type, size, dat, closure)))
585 {
586 sqlite3_finalize (stmt);
587 break;
588 }
589 sqlite3_finalize (stmt);
590 }
591 sqlite3_close (dbh);
592 GNUNET_mutex_unlock (lock);
593 return cnt;
594}
595
596GNUNET_Dstore_ServiceAPI *
597provide_module_dstore_sqlite (GNUNET_CoreAPIForPlugins * capi)
598{
599 static GNUNET_Dstore_ServiceAPI api;
600 int fd;
601
602#if DEBUG_SQLITE
603 GNUNET_GE_LOG (capi->ectx,
604 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
605 "SQLite Dstore: initializing database\n");
606#endif
607 coreAPI = capi;
608 if (GNUNET_OK != db_reset ())
609 {
610 GNUNET_GE_BREAK (capi->ectx, 0);
611 return NULL;
612 }
613 lock = GNUNET_mutex_create (GNUNET_NO);
614
615
616 api.get = &d_get;
617 api.put = &d_put;
618 GNUNET_GC_get_configuration_value_number (coreAPI->cfg,
619 "DSTORE", "QUOTA", 1, 1024, 1,
620 &quota);
621 if (quota == 0) /* error */
622 quota = 1;
623 quota *= 1024 * 1024;
624
625 bloom_name = GNUNET_strdup ("/tmp/dbloomXXXXXX");
626 fd = mkstemp (bloom_name);
627 if (fd != -1)
628 {
629 bloom = GNUNET_bloomfilter_load (coreAPI->ectx, bloom_name, quota / (OVERHEAD + 1024), /* 8 bit per entry in DB, expect 1k entries */
630 5);
631 CLOSE (fd);
632 }
633 stats = capi->service_request ("stats");
634 if (stats != NULL)
635 {
636 stat_dstore_size = stats->create (gettext_noop ("# bytes in dstore"));
637 stat_dstore_quota =
638 stats->create (gettext_noop ("# max bytes allowed in dstore"));
639 stats->set (stat_dstore_quota, quota);
640 }
641 return &api;
642}
643
644/**
645 * Shutdown the module.
646 */
647void
648release_module_dstore_sqlite ()
649{
650 UNLINK (fn);
651 GNUNET_free (fn);
652 GNUNET_free (fn_utf8);
653 fn = NULL;
654 if (bloom != NULL)
655 {
656 GNUNET_bloomfilter_free (bloom);
657 bloom = NULL;
658 }
659 UNLINK (bloom_name);
660 GNUNET_free (bloom_name);
661 bloom_name = NULL;
662 if (stats != NULL)
663 {
664 coreAPI->service_release (stats);
665 stats = NULL;
666 }
667#if DEBUG_SQLITE
668 GNUNET_GE_LOG (coreAPI->ectx,
669 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
670 "SQLite Dstore: database shutdown\n");
671#endif
672 GNUNET_mutex_destroy (lock);
673 coreAPI = NULL;
674}
675
676/* end of dstore.c */
diff --git a/src/datacache/plugin_datacache_template.c b/src/datacache/plugin_datacache_template.c
new file mode 100644
index 000000000..d1f162c17
--- /dev/null
+++ b/src/datacache/plugin_datacache_template.c
@@ -0,0 +1,151 @@
1/*
2 This file is part of GNUnet
3 (C) 2006, 2009 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
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#ifndef PLUGIN_DATACACHE_H
27#define PLUGIN_DATACACHE_H
28
29#include "plugin_datacache.h"
30
31#ifdef __cplusplus
32extern "C"
33{
34#if 0 /* keep Emacsens' auto-indent happy */
35}
36#endif
37#endif
38
39
40
41/**
42 * Context for all functions in this plugin.
43 */
44struct Plugin
45{
46 /**
47 * Our execution environment.
48 */
49 struct GNUNET_DATASTORE_PluginEnvironment *env;
50};
51
52
53/**
54 * Store an item in the datastore.
55 *
56 * @param key key to store data under
57 * @param size number of bytes in data
58 * @param data data to store
59 * @param type type of the value
60 * @param discard_time when to discard the value in any case
61 * @return 0 on error, number of bytes used otherwise
62 */
63static uint32_t
64template_plugin_put (void *cls,
65 const GNUNET_HashCode * key,
66 uint32_t size,
67 const char *data,
68 uint32_t type,
69 struct GNUNET_TIME_Absolute discard_time)
70{
71 GNUNET_break (0);
72 return 0;
73}
74
75
76/**
77 * Iterate over the results for a particular key
78 * in the datastore.
79 *
80 * @param key
81 * @param type entries of which type are relevant?
82 * @param iter maybe NULL (to just count)
83 * @return the number of results found
84 */
85static unsigned int
86template_plugin_get (void *cls,
87 const GNUNET_HashCode * key,
88 uint32_t type,
89 GNUNET_DATACACHE_Iterator iter,
90 void *iter_cls)
91{
92 GNUNET_break (0);
93 return 0;
94}
95
96
97/**
98 * Delete the entry with the lowest expiration value
99 * from the datacache right now.
100 *
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 * Entry point for the plugin.
113 */
114void *
115libgnunet_plugin_datacache_template_init (void *cls)
116{
117 struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
118 struct GNUNET_DATACACHE_PluginFunctions *api;
119 struct Plugin *plugin;
120
121 plugin = GNUNET_malloc (sizeof (struct Plugin));
122 plugin->env = env;
123 api = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_PluginFunctions));
124 api->cls = plugin;
125 api->get = &template_plugin_get;
126 api->put = &template_plugin_put;
127 api->del = &template_plugin_del;
128 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
129 "template", _("Template datacache running\n"));
130 return api;
131}
132
133
134/**
135 * Exit point from the plugin.
136 */
137void *
138libgnunet_plugin_datacache_template_done (void *cls)
139{
140 struct GNUNET_DATACACHE_PluginFunctions *api = cls;
141 struct Plugin *plugin = api->cls;
142
143 GNUNET_free (plugin);
144 GNUNET_free (api);
145 return NULL;
146}
147
148
149
150/* end of plugin_datacache_template.c */
151
diff --git a/src/datacache/test_datacache_api.c b/src/datacache/test_datacache_api.c
new file mode 100644
index 000000000..00b63cda8
--- /dev/null
+++ b/src/datacache/test_datacache_api.c
@@ -0,0 +1,120 @@
1/*
2 This file is part of GNUnet.
3 (C) 2006 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20/*
21 * @file applications/dstore/dstore_test.c
22 * @brief Test for the dstore implementations.
23 * @author Nils Durner
24 */
25
26#include "platform.h"
27#include "gnunet_util.h"
28#include "gnunet_protocols.h"
29#include "gnunet_dstore_service.h"
30#include "core.h"
31
32#define ASSERT(x) do { if (! (x)) { printf("Error at %s:%d\n", __FILE__, __LINE__); goto FAILURE;} } while (0)
33
34static int error;
35
36static int
37checkIt (const GNUNET_HashCode * key,
38 unsigned int type, unsigned int size, const char *data, void *cls)
39{
40 if (size != sizeof (GNUNET_HashCode))
41 {
42 printf ("ERROR: Invalid size\n");
43 error = 2;
44 }
45 if (0 != memcmp (data, cls, size))
46 {
47 printf ("ERROR: Invalid data\n");
48 error = 3;
49 }
50 return GNUNET_OK;
51}
52
53/**
54 * Add testcode here!
55 */
56static int
57test (GNUNET_Dstore_ServiceAPI * api)
58{
59 GNUNET_HashCode k;
60 GNUNET_HashCode n;
61 GNUNET_CronTime exp;
62 unsigned int i;
63
64 exp = GNUNET_get_time () + 5 * GNUNET_CRON_MINUTES;
65 memset (&k, 0, sizeof (GNUNET_HashCode));
66 for (i = 0; i < 100; i++)
67 {
68 GNUNET_hash (&k, sizeof (GNUNET_HashCode), &n);
69 ASSERT (GNUNET_OK == api->put (&k,
70 i % 2,
71 exp, sizeof (GNUNET_HashCode),
72 (const char *) &n));
73 k = n;
74 }
75 memset (&k, 0, sizeof (GNUNET_HashCode));
76 for (i = 0; i < 100; i++)
77 {
78 GNUNET_hash (&k, sizeof (GNUNET_HashCode), &n);
79 ASSERT (1 == api->get (&k, i % 2, &checkIt, &n));
80 k = n;
81 }
82 return GNUNET_OK;
83FAILURE:
84 return GNUNET_SYSERR;
85}
86
87#define TEST_DB "/tmp/GNUnet_dstore_test/"
88
89int
90main (int argc, char *argv[])
91{
92 GNUNET_Dstore_ServiceAPI *api;
93 int ok;
94 struct GNUNET_GC_Configuration *cfg;
95 struct GNUNET_CronManager *cron;
96
97 GNUNET_disable_entropy_gathering ();
98 cfg = GNUNET_GC_create ();
99 if (-1 == GNUNET_GC_parse_configuration (cfg, "check.conf"))
100 {
101 GNUNET_GC_free (cfg);
102 return -1;
103 }
104 cron = GNUNET_cron_create (NULL);
105 GNUNET_CORE_init (NULL, cfg, cron, NULL);
106 api = GNUNET_CORE_request_service ("dstore");
107 if (api != NULL)
108 {
109 ok = test (api);
110 GNUNET_CORE_release_service (api);
111 }
112 else
113 ok = GNUNET_SYSERR;
114 GNUNET_CORE_done ();
115 if (ok == GNUNET_SYSERR)
116 return 1;
117 return error;
118}
119
120/* end of dstore_test.c */
diff --git a/src/datastore/Makefile.am b/src/datastore/Makefile.am
index 07a14e534..1ca588926 100644
--- a/src/datastore/Makefile.am
+++ b/src/datastore/Makefile.am
@@ -16,7 +16,7 @@ lib_LTLIBRARIES = \
16 libgnunetdatastore.la 16 libgnunetdatastore.la
17 17
18libgnunetdatastore_la_SOURCES = \ 18libgnunetdatastore_la_SOURCES = \
19 datastore_api.c datastore.h 19 datastore_api.c datastore.h plugin_datastore.h
20libgnunetdatastore_la_LIBADD = \ 20libgnunetdatastore_la_LIBADD = \
21 $(top_builddir)/src/util/libgnunetutil.la \ 21 $(top_builddir)/src/util/libgnunetutil.la \
22 $(GN_LIBINTL) 22 $(GN_LIBINTL)
diff --git a/src/datastore/plugin_datastore_template.c b/src/datastore/plugin_datastore_template.c
index a364a0faa..4bfb452ed 100644
--- a/src/datastore/plugin_datastore_template.c
+++ b/src/datastore/plugin_datastore_template.c
@@ -47,6 +47,7 @@ struct Plugin
47 */ 47 */
48static unsigned long long template_plugin_get_size (void *cls) 48static unsigned long long template_plugin_get_size (void *cls)
49{ 49{
50 GNUNET_break (0);
50 return 0; 51 return 0;
51} 52}
52 53
@@ -76,6 +77,7 @@ template_plugin_put (void *cls,
76 struct GNUNET_TIME_Absolute expiration, 77 struct GNUNET_TIME_Absolute expiration,
77 char **msg) 78 char **msg)
78{ 79{
80 GNUNET_break (0);
79 *msg = GNUNET_strdup ("not implemented"); 81 *msg = GNUNET_strdup ("not implemented");
80 return GNUNET_SYSERR; 82 return GNUNET_SYSERR;
81} 83}
@@ -94,9 +96,10 @@ template_plugin_put (void *cls,
94 * to signal the end of the iteration). 96 * to signal the end of the iteration).
95 */ 97 */
96static void 98static void
97template_next_request (void *next_cls, 99template_plugin_next_request (void *next_cls,
98 int end_it) 100 int end_it)
99{ 101{
102 GNUNET_break (0);
100} 103}
101 104
102 105
@@ -124,6 +127,7 @@ template_plugin_get (void *cls,
124 uint32_t type, 127 uint32_t type,
125 PluginIterator iter, void *iter_cls) 128 PluginIterator iter, void *iter_cls)
126{ 129{
130 GNUNET_break (0);
127} 131}
128 132
129 133
@@ -155,6 +159,7 @@ template_plugin_update (void *cls,
155 int delta, struct GNUNET_TIME_Absolute expire, 159 int delta, struct GNUNET_TIME_Absolute expire,
156 char **msg) 160 char **msg)
157{ 161{
162 GNUNET_break (0);
158 *msg = GNUNET_strdup ("not implemented"); 163 *msg = GNUNET_strdup ("not implemented");
159 return GNUNET_SYSERR; 164 return GNUNET_SYSERR;
160} 165}
@@ -176,6 +181,7 @@ template_plugin_iter_low_priority (void *cls,
176 PluginIterator iter, 181 PluginIterator iter,
177 void *iter_cls) 182 void *iter_cls)
178{ 183{
184 GNUNET_break (0);
179} 185}
180 186
181 187
@@ -196,6 +202,7 @@ template_plugin_iter_zero_anonymity (void *cls,
196 PluginIterator iter, 202 PluginIterator iter,
197 void *iter_cls) 203 void *iter_cls)
198{ 204{
205 GNUNET_break (0);
199} 206}
200 207
201 208
@@ -216,6 +223,7 @@ template_plugin_iter_ascending_expiration (void *cls,
216 PluginIterator iter, 223 PluginIterator iter,
217 void *iter_cls) 224 void *iter_cls)
218{ 225{
226 GNUNET_break (0);
219} 227}
220 228
221 229
@@ -236,6 +244,7 @@ template_plugin_iter_migration_order (void *cls,
236 PluginIterator iter, 244 PluginIterator iter,
237 void *iter_cls) 245 void *iter_cls)
238{ 246{
247 GNUNET_break (0);
239} 248}
240 249
241 250
@@ -256,6 +265,7 @@ template_plugin_iter_all_now (void *cls,
256 PluginIterator iter, 265 PluginIterator iter,
257 void *iter_cls) 266 void *iter_cls)
258{ 267{
268 GNUNET_break (0);
259} 269}
260 270
261 271
@@ -265,6 +275,7 @@ template_plugin_iter_all_now (void *cls,
265static void 275static void
266template_plugin_drop (void *cls) 276template_plugin_drop (void *cls)
267{ 277{
278 GNUNET_break (0);
268} 279}
269 280
270 281
@@ -284,7 +295,7 @@ libgnunet_plugin_datastore_template_init (void *cls)
284 api->cls = plugin; 295 api->cls = plugin;
285 api->get_size = &template_plugin_get_size; 296 api->get_size = &template_plugin_get_size;
286 api->put = &template_plugin_put; 297 api->put = &template_plugin_put;
287 api->next_request = &template_next_request; 298 api->next_request = &template_plugin_next_request;
288 api->get = &template_plugin_get; 299 api->get = &template_plugin_get;
289 api->update = &template_plugin_update; 300 api->update = &template_plugin_update;
290 api->iter_low_priority = &template_plugin_iter_low_priority; 301 api->iter_low_priority = &template_plugin_iter_low_priority;
diff --git a/src/include/gnunet_datacache_lib.h b/src/include/gnunet_datacache_lib.h
index 64d1d4883..1ee8eb8e2 100644
--- a/src/include/gnunet_datacache_lib.h
+++ b/src/include/gnunet_datacache_lib.h
@@ -51,12 +51,14 @@ struct GNUNET_DATACACHE_Handle;
51/** 51/**
52 * Create a data cache. 52 * Create a data cache.
53 * 53 *
54 * @param sched scheduler to use
54 * @param cfg configuration to use 55 * @param cfg configuration to use
55 * @param section section in the configuration that contains our options 56 * @param section section in the configuration that contains our options
56 * @return handle to use to access the service 57 * @return handle to use to access the service
57 */ 58 */
58struct GNUNET_DATACACHE_Handle * 59struct GNUNET_DATACACHE_Handle *
59GNUNET_DATACACHE_create (struct GNUNET_CONFIGURATION_Handle *cfg, 60GNUNET_DATACACHE_create (struct GNUNET_SCHEDULER_Handle *sched,
61 struct GNUNET_CONFIGURATION_Handle *cfg,
60 const char *section); 62 const char *section);
61 63
62 64
@@ -85,8 +87,9 @@ typedef void (*GNUNET_DATACACHE_Iterator) (void *cls,
85 87
86 88
87/** 89/**
88 * Store an item in the datastore. 90 * Store an item in the datacache.
89 * 91 *
92 * @param h handle to the datacache
90 * @param key key to store data under 93 * @param key key to store data under
91 * @param size number of bytes in data 94 * @param size number of bytes in data
92 * @param data data to store 95 * @param data data to store
@@ -95,7 +98,8 @@ typedef void (*GNUNET_DATACACHE_Iterator) (void *cls,
95 * @return GNUNET_OK on success, GNUNET_SYSERR on error (full, etc.) 98 * @return GNUNET_OK on success, GNUNET_SYSERR on error (full, etc.)
96 */ 99 */
97int 100int
98GNUNET_DATACACHE_put (const GNUNET_HashCode * key, 101GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h,
102 const GNUNET_HashCode * key,
99 uint32_t size, 103 uint32_t size,
100 const char *data, 104 const char *data,
101 unsigned int type, 105 unsigned int type,
@@ -104,8 +108,9 @@ GNUNET_DATACACHE_put (const GNUNET_HashCode * key,
104 108
105/** 109/**
106 * Iterate over the results for a particular key 110 * Iterate over the results for a particular key
107 * in the datastore. 111 * in the datacache.
108 * 112 *
113 * @param h handle to the datacache
109 * @param key what to look up 114 * @param key what to look up
110 * @param type entries of which type are relevant? 115 * @param type entries of which type are relevant?
111 * @param iter maybe NULL (to just count) 116 * @param iter maybe NULL (to just count)
@@ -113,7 +118,8 @@ GNUNET_DATACACHE_put (const GNUNET_HashCode * key,
113 * @return the number of results found 118 * @return the number of results found
114 */ 119 */
115unsigned int 120unsigned int
116GNUNET_DATACACHE_get (const GNUNET_HashCode * key, 121GNUNET_DATACACHE_get (struct GNUNET_DATACACHE_Handle *h,
122 const GNUNET_HashCode * key,
117 unsigned int type, 123 unsigned int type,
118 GNUNET_DATACACHE_Iterator iter, 124 GNUNET_DATACACHE_Iterator iter,
119 void *iter_cls); 125 void *iter_cls);