aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-11-13 20:05:40 +0000
committerChristian Grothoff <christian@grothoff.org>2012-11-13 20:05:40 +0000
commit4e1d85bac66209e6655f3fb4d3ddef7929f0f3fc (patch)
treedf5c5a0d972f35d741b51c3a3fc8d2298ac8b4fd
parent855362e698928b0a5a8f72fc6427c2ea42af4e79 (diff)
downloadgnunet-4e1d85bac66209e6655f3fb4d3ddef7929f0f3fc.tar.gz
gnunet-4e1d85bac66209e6655f3fb4d3ddef7929f0f3fc.zip
changing datacache API to separate put-paths from data (so that plugins can test for duplicates), removing support for MySQL
-rw-r--r--src/datacache/Makefile.am48
-rw-r--r--src/datacache/datacache.c24
-rw-r--r--src/datacache/perf_datacache.c10
-rw-r--r--src/datacache/perf_datacache_data_heap.conf5
-rw-r--r--src/datacache/perf_datacache_data_mysql.conf13
-rw-r--r--src/datacache/plugin_datacache_heap.c73
-rw-r--r--src/datacache/plugin_datacache_mysql.c474
-rw-r--r--src/datacache/plugin_datacache_postgres.c69
-rw-r--r--src/datacache/plugin_datacache_sqlite.c53
-rw-r--r--src/datacache/plugin_datacache_template.c12
-rw-r--r--src/datacache/test_datacache.c16
-rw-r--r--src/datacache/test_datacache_data_heap.conf4
-rw-r--r--src/datacache/test_datacache_data_mysql.conf13
-rw-r--r--src/datacache/test_datacache_quota.c2
-rw-r--r--src/dht/gnunet-service-dht_datacache.c80
-rw-r--r--src/include/gnunet_datacache_lib.h20
-rw-r--r--src/include/gnunet_datacache_plugin.h12
17 files changed, 253 insertions, 675 deletions
diff --git a/src/datacache/Makefile.am b/src/datacache/Makefile.am
index 99e333dc9..c6c27b327 100644
--- a/src/datacache/Makefile.am
+++ b/src/datacache/Makefile.am
@@ -19,9 +19,6 @@ endif
19if HAVE_SQLITE 19if HAVE_SQLITE
20 SQLITE_PLUGIN = libgnunet_plugin_datacache_sqlite.la 20 SQLITE_PLUGIN = libgnunet_plugin_datacache_sqlite.la
21endif 21endif
22if HAVE_MYSQL
23 MYSQL_PLUGIN = libgnunet_plugin_datacache_mysql.la
24endif
25if HAVE_POSTGRES 22if HAVE_POSTGRES
26 POSTGRES_PLUGIN = libgnunet_plugin_datacache_postgres.la 23 POSTGRES_PLUGIN = libgnunet_plugin_datacache_postgres.la
27endif 24endif
@@ -42,7 +39,6 @@ libgnunetdatacache_la_LDFLAGS = \
42 39
43plugin_LTLIBRARIES = \ 40plugin_LTLIBRARIES = \
44 $(SQLITE_PLUGIN) \ 41 $(SQLITE_PLUGIN) \
45 $(MYSQL_PLUGIN) \
46 $(POSTGRES_PLUGIN) \ 42 $(POSTGRES_PLUGIN) \
47 libgnunet_plugin_datacache_heap.la \ 43 libgnunet_plugin_datacache_heap.la \
48 libgnunet_plugin_datacache_template.la 44 libgnunet_plugin_datacache_template.la
@@ -66,18 +62,6 @@ libgnunet_plugin_datacache_heap_la_LIBADD = \
66libgnunet_plugin_datacache_heap_la_LDFLAGS = \ 62libgnunet_plugin_datacache_heap_la_LDFLAGS = \
67 $(GN_PLUGIN_LDFLAGS) 63 $(GN_PLUGIN_LDFLAGS)
68 64
69libgnunet_plugin_datacache_mysql_la_SOURCES = \
70 plugin_datacache_mysql.c
71libgnunet_plugin_datacache_mysql_la_LIBADD = \
72 $(top_builddir)/src/statistics/libgnunetstatistics.la \
73 $(top_builddir)/src/mysql/libgnunetmysql.la \
74 $(top_builddir)/src/util/libgnunetutil.la \
75 $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient
76libgnunet_plugin_datacache_mysql_la_CPPFLAGS = \
77 $(MYSQL_CPPFLAGS)
78libgnunet_plugin_datacache_mysql_la_LDFLAGS = \
79 $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient
80
81libgnunet_plugin_datacache_postgres_la_SOURCES = \ 65libgnunet_plugin_datacache_postgres_la_SOURCES = \
82 plugin_datacache_postgres.c 66 plugin_datacache_postgres.c
83libgnunet_plugin_datacache_postgres_la_LIBADD = \ 67libgnunet_plugin_datacache_postgres_la_LIBADD = \
@@ -110,16 +94,14 @@ SQLITE_TESTS = \
110 $(SQLITE_BENCHMARKS) 94 $(SQLITE_BENCHMARKS)
111endif 95endif
112 96
113if HAVE_MYSQL
114if HAVE_BENCHMARKS 97if HAVE_BENCHMARKS
115 MYSQL_BENCHMARKS = \ 98 HEAP_BENCHMARKS = \
116 perf_datacache_mysql 99 perf_datacache_heap
117endif
118MYSQL_TESTS = \
119 test_datacache_mysql \
120 test_datacache_quota_mysql \
121 $(MYSQL_BENCHMARKS)
122endif 100endif
101HEAP_TESTS = \
102 test_datacache_heap \
103 test_datacache_quota_heap \
104 $(HEAP_BENCHMARKS)
123 105
124if HAVE_POSTGRES 106if HAVE_POSTGRES
125if HAVE_BENCHMARKS 107if HAVE_BENCHMARKS
@@ -134,7 +116,7 @@ endif
134 116
135check_PROGRAMS = \ 117check_PROGRAMS = \
136 $(SQLITE_TESTS) \ 118 $(SQLITE_TESTS) \
137 $(MYSQL_TESTS) \ 119 $(HEAP_TESTS) \
138 $(POSTGRES_TESTS) 120 $(POSTGRES_TESTS)
139 121
140if ENABLE_TEST_RUN 122if ENABLE_TEST_RUN
@@ -162,23 +144,23 @@ perf_datacache_sqlite_LDADD = \
162 $(top_builddir)/src/datacache/libgnunetdatacache.la \ 144 $(top_builddir)/src/datacache/libgnunetdatacache.la \
163 $(top_builddir)/src/util/libgnunetutil.la 145 $(top_builddir)/src/util/libgnunetutil.la
164 146
165test_datacache_mysql_SOURCES = \ 147test_datacache_heap_SOURCES = \
166 test_datacache.c 148 test_datacache.c
167test_datacache_mysql_LDADD = \ 149test_datacache_heap_LDADD = \
168 $(top_builddir)/src/testing/libgnunettesting.la \ 150 $(top_builddir)/src/testing/libgnunettesting.la \
169 $(top_builddir)/src/datacache/libgnunetdatacache.la \ 151 $(top_builddir)/src/datacache/libgnunetdatacache.la \
170 $(top_builddir)/src/util/libgnunetutil.la 152 $(top_builddir)/src/util/libgnunetutil.la
171 153
172test_datacache_quota_mysql_SOURCES = \ 154test_datacache_quota_heap_SOURCES = \
173 test_datacache_quota.c 155 test_datacache_quota.c
174test_datacache_quota_mysql_LDADD = \ 156test_datacache_quota_heap_LDADD = \
175 $(top_builddir)/src/testing/libgnunettesting.la \ 157 $(top_builddir)/src/testing/libgnunettesting.la \
176 $(top_builddir)/src/datacache/libgnunetdatacache.la \ 158 $(top_builddir)/src/datacache/libgnunetdatacache.la \
177 $(top_builddir)/src/util/libgnunetutil.la 159 $(top_builddir)/src/util/libgnunetutil.la
178 160
179perf_datacache_mysql_SOURCES = \ 161perf_datacache_heap_SOURCES = \
180 perf_datacache.c 162 perf_datacache.c
181perf_datacache_mysql_LDADD = \ 163perf_datacache_heap_LDADD = \
182 $(top_builddir)/src/testing/libgnunettesting.la \ 164 $(top_builddir)/src/testing/libgnunettesting.la \
183 $(top_builddir)/src/datacache/libgnunetdatacache.la \ 165 $(top_builddir)/src/datacache/libgnunetdatacache.la \
184 $(top_builddir)/src/util/libgnunetutil.la 166 $(top_builddir)/src/util/libgnunetutil.la
@@ -207,7 +189,7 @@ perf_datacache_postgres_LDADD = \
207EXTRA_DIST = \ 189EXTRA_DIST = \
208 test_datacache_data_sqlite.conf \ 190 test_datacache_data_sqlite.conf \
209 perf_datacache_data_sqlite.conf \ 191 perf_datacache_data_sqlite.conf \
210 test_datacache_data_mysql.conf \ 192 test_datacache_data_heap.conf \
211 perf_datacache_data_mysql.conf \ 193 perf_datacache_data_heap.conf \
212 test_datacache_data_postgres.conf \ 194 test_datacache_data_postgres.conf \
213 perf_datacache_data_postgres.conf 195 perf_datacache_data_postgres.conf
diff --git a/src/datacache/datacache.c b/src/datacache/datacache.c
index e5dbfac16..0cd6f884b 100644
--- a/src/datacache/datacache.c
+++ b/src/datacache/datacache.c
@@ -233,22 +233,34 @@ GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h)
233 * @param data data to store 233 * @param data data to store
234 * @param type type of the value 234 * @param type type of the value
235 * @param discard_time when to discard the value in any case 235 * @param discard_time when to discard the value in any case
236 * @return GNUNET_OK on success, GNUNET_SYSERR on error (full, etc.) 236 * @param path_info_len number of entries in 'path_info'
237 * @param path_info a path through the network
238 * @return GNUNET_OK on success, GNUNET_SYSERR on error, GNUNET_NO if duplicate
237 */ 239 */
238int 240int
239GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h, 241GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h,
240 const struct GNUNET_HashCode * key, size_t size, 242 const struct GNUNET_HashCode * key, size_t size,
241 const char *data, enum GNUNET_BLOCK_Type type, 243 const char *data, enum GNUNET_BLOCK_Type type,
242 struct GNUNET_TIME_Absolute discard_time) 244 struct GNUNET_TIME_Absolute discard_time,
245 unsigned int path_info_len,
246 const struct GNUNET_PeerIdentity *path_info)
243{ 247{
244 uint32_t used; 248 ssize_t used;
245 249
246 used = h->api->put (h->api->cls, key, size, data, type, discard_time); 250 used = h->api->put (h->api->cls, key,
247 if (0 == used) 251 size, data,
252 type, discard_time,
253 path_info_len, path_info);
254 if (-1 == used)
248 { 255 {
249 /* error or duplicate */ 256 GNUNET_break (0);
250 return GNUNET_SYSERR; 257 return GNUNET_SYSERR;
251 } 258 }
259 if (0 == used)
260 {
261 /* duplicate */
262 return GNUNET_NO;
263 }
252 LOG (GNUNET_ERROR_TYPE_DEBUG, "Stored data under key `%s' in cache\n", 264 LOG (GNUNET_ERROR_TYPE_DEBUG, "Stored data under key `%s' in cache\n",
253 GNUNET_h2s (key)); 265 GNUNET_h2s (key));
254 GNUNET_STATISTICS_update (h->stats, gettext_noop ("# bytes stored"), size, 266 GNUNET_STATISTICS_update (h->stats, gettext_noop ("# bytes stored"), size,
diff --git a/src/datacache/perf_datacache.c b/src/datacache/perf_datacache.c
index 10289ec68..e30ae869d 100644
--- a/src/datacache/perf_datacache.c
+++ b/src/datacache/perf_datacache.c
@@ -44,9 +44,12 @@ static const char *plugin_name;
44 44
45 45
46static int 46static int
47checkIt (void *cls, struct GNUNET_TIME_Absolute exp, 47checkIt (void *cls,
48 const struct GNUNET_HashCode * key, size_t size, const char *data, 48 const struct GNUNET_HashCode * key, size_t size, const char *data,
49 enum GNUNET_BLOCK_Type type) 49 enum GNUNET_BLOCK_Type type,
50 struct GNUNET_TIME_Absolute exp,
51 unsigned int path_len,
52 const struct GNUNET_PeerIdentity *path)
50{ 53{
51 if ((size == sizeof (struct GNUNET_HashCode)) && (0 == memcmp (data, cls, size))) 54 if ((size == sizeof (struct GNUNET_HashCode)) && (0 == memcmp (data, cls, size)))
52 found++; 55 found++;
@@ -84,7 +87,8 @@ run (void *cls, char *const *args, const char *cfgfile,
84 GNUNET_CRYPTO_hash (&k, sizeof (struct GNUNET_HashCode), &n); 87 GNUNET_CRYPTO_hash (&k, sizeof (struct GNUNET_HashCode), &n);
85 ASSERT (GNUNET_OK == 88 ASSERT (GNUNET_OK ==
86 GNUNET_DATACACHE_put (h, &k, sizeof (struct GNUNET_HashCode), 89 GNUNET_DATACACHE_put (h, &k, sizeof (struct GNUNET_HashCode),
87 (const char *) &n, 1 + i % 16, exp)); 90 (const char *) &n, 1 + i % 16, exp,
91 0, NULL));
88 k = n; 92 k = n;
89 } 93 }
90 FPRINTF (stderr, "%s", "\n"); 94 FPRINTF (stderr, "%s", "\n");
diff --git a/src/datacache/perf_datacache_data_heap.conf b/src/datacache/perf_datacache_data_heap.conf
new file mode 100644
index 000000000..3680c020b
--- /dev/null
+++ b/src/datacache/perf_datacache_data_heap.conf
@@ -0,0 +1,5 @@
1[perfcache]
2QUOTA = 500 KB
3DATABASE = heap
4
5
diff --git a/src/datacache/perf_datacache_data_mysql.conf b/src/datacache/perf_datacache_data_mysql.conf
deleted file mode 100644
index 1760f7d08..000000000
--- a/src/datacache/perf_datacache_data_mysql.conf
+++ /dev/null
@@ -1,13 +0,0 @@
1[perfcache]
2QUOTA = 500 KB
3DATABASE = mysql
4
5[datacache-mysql]
6DATABASE = gnunetcheck
7# CONFIG = ~/.my.cnf
8# USER =
9# PASSWORD =
10# HOST =
11# PORT =
12
13
diff --git a/src/datacache/plugin_datacache_heap.c b/src/datacache/plugin_datacache_heap.c
index 2f55bcf53..8bc9b29f6 100644
--- a/src/datacache/plugin_datacache_heap.c
+++ b/src/datacache/plugin_datacache_heap.c
@@ -32,6 +32,7 @@
32#define LOG_STRERROR_FILE(kind,op,fn) GNUNET_log_from_strerror_file (kind, "datacache-heap", op, fn) 32#define LOG_STRERROR_FILE(kind,op,fn) GNUNET_log_from_strerror_file (kind, "datacache-heap", op, fn)
33 33
34 34
35
35/** 36/**
36 * Context for all functions in this plugin. 37 * Context for all functions in this plugin.
37 */ 38 */
@@ -76,11 +77,21 @@ struct Value
76 struct GNUNET_CONTAINER_HeapNode *hn; 77 struct GNUNET_CONTAINER_HeapNode *hn;
77 78
78 /** 79 /**
80 * Path information.
81 */
82 struct GNUNET_PeerIdentity *path_info;
83
84 /**
79 * Payload (actual payload follows this struct) 85 * Payload (actual payload follows this struct)
80 */ 86 */
81 size_t size; 87 size_t size;
82 88
83 /** 89 /**
90 * Number of entries in 'path_info'.
91 */
92 unsigned int path_info_len;
93
94 /**
84 * Type of the block. 95 * Type of the block.
85 */ 96 */
86 enum GNUNET_BLOCK_Type type; 97 enum GNUNET_BLOCK_Type type;
@@ -88,6 +99,9 @@ struct Value
88}; 99};
89 100
90 101
102#define OVERHEAD (sizeof (struct Value) + 64)
103
104
91/** 105/**
92 * Closure for 'put_cb'. 106 * Closure for 'put_cb'.
93 */ 107 */
@@ -109,6 +123,11 @@ struct PutContext
109 struct GNUNET_CONTAINER_Heap *heap; 123 struct GNUNET_CONTAINER_Heap *heap;
110 124
111 /** 125 /**
126 * Path information.
127 */
128 const struct GNUNET_PeerIdentity *path_info;
129
130 /**
112 * Number of bytes in 'data'. 131 * Number of bytes in 'data'.
113 */ 132 */
114 size_t size; 133 size_t size;
@@ -119,6 +138,11 @@ struct PutContext
119 enum GNUNET_BLOCK_Type type; 138 enum GNUNET_BLOCK_Type type;
120 139
121 /** 140 /**
141 * Number of entries in 'path_info'.
142 */
143 unsigned int path_info_len;
144
145 /**
122 * Value to set to GNUNET_YES if an equivalent block was found. 146 * Value to set to GNUNET_YES if an equivalent block was found.
123 */ 147 */
124 int found; 148 int found;
@@ -149,13 +173,20 @@ put_cb (void *cls,
149 put_ctx->found = GNUNET_YES; 173 put_ctx->found = GNUNET_YES;
150 val->discard_time = GNUNET_TIME_absolute_max (val->discard_time, 174 val->discard_time = GNUNET_TIME_absolute_max (val->discard_time,
151 put_ctx->discard_time); 175 put_ctx->discard_time);
176 /* replace old path with new path */
177 GNUNET_array_grow (val->path_info,
178 val->path_info_len,
179 put_ctx->path_info_len);
180 memcpy (val->path_info,
181 put_ctx->path_info,
182 put_ctx->path_info_len * sizeof (struct GNUNET_PeerIdentity));
152 GNUNET_CONTAINER_heap_update_cost (put_ctx->heap, 183 GNUNET_CONTAINER_heap_update_cost (put_ctx->heap,
153 val->hn, 184 val->hn,
154 val->discard_time.abs_value); 185 val->discard_time.abs_value);
155 return GNUNET_NO; 186 return GNUNET_NO;
156 } 187 }
157 if (val->type == put_ctx->type) 188 if (val->type == put_ctx->type)
158 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
159 "Got another value for key %s and type %d (size %u vs %u)\n", 190 "Got another value for key %s and type %d (size %u vs %u)\n",
160 GNUNET_h2s (key), 191 GNUNET_h2s (key),
161 val->type, 192 val->type,
@@ -174,12 +205,16 @@ put_cb (void *cls,
174 * @param data data to store 205 * @param data data to store
175 * @param type type of the value 206 * @param type type of the value
176 * @param discard_time when to discard the value in any case 207 * @param discard_time when to discard the value in any case
177 * @return 0 on error, number of bytes used otherwise 208 * @param path_info_len number of entries in 'path_info'
209 * @param path_info a path through the network
210 * @return 0 if duplicate, -1 on error, number of bytes used otherwise
178 */ 211 */
179static size_t 212static ssize_t
180heap_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size, 213heap_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
181 const char *data, enum GNUNET_BLOCK_Type type, 214 const char *data, enum GNUNET_BLOCK_Type type,
182 struct GNUNET_TIME_Absolute discard_time) 215 struct GNUNET_TIME_Absolute discard_time,
216 unsigned int path_info_len,
217 const struct GNUNET_PeerIdentity *path_info)
183{ 218{
184 struct Plugin *plugin = cls; 219 struct Plugin *plugin = cls;
185 struct Value *val; 220 struct Value *val;
@@ -189,6 +224,8 @@ heap_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
189 put_ctx.heap = plugin->heap; 224 put_ctx.heap = plugin->heap;
190 put_ctx.data = data; 225 put_ctx.data = data;
191 put_ctx.size = size; 226 put_ctx.size = size;
227 put_ctx.path_info = path_info;
228 put_ctx.path_info_len = path_info_len;
192 put_ctx.discard_time = discard_time; 229 put_ctx.discard_time = discard_time;
193 put_ctx.type = type; 230 put_ctx.type = type;
194 GNUNET_CONTAINER_multihashmap_get_multiple (plugin->map, 231 GNUNET_CONTAINER_multihashmap_get_multiple (plugin->map,
@@ -203,6 +240,11 @@ heap_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
203 val->type = type; 240 val->type = type;
204 val->discard_time = discard_time; 241 val->discard_time = discard_time;
205 val->size = size; 242 val->size = size;
243 GNUNET_array_grow (val->path_info,
244 val->path_info_len,
245 path_info_len);
246 memcpy (val->path_info, path_info,
247 path_info_len * sizeof (struct GNUNET_PeerIdentity));
206 (void) GNUNET_CONTAINER_multihashmap_put (plugin->map, 248 (void) GNUNET_CONTAINER_multihashmap_put (plugin->map,
207 &val->key, 249 &val->key,
208 val, 250 val,
@@ -210,7 +252,7 @@ heap_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
210 val->hn = GNUNET_CONTAINER_heap_insert (plugin->heap, 252 val->hn = GNUNET_CONTAINER_heap_insert (plugin->heap,
211 val, 253 val,
212 val->discard_time.abs_value); 254 val->discard_time.abs_value);
213 return size; 255 return size + OVERHEAD;
214} 256}
215 257
216 258
@@ -263,13 +305,17 @@ get_cb (void *cls,
263 if ( (get_ctx->type != val->type) && 305 if ( (get_ctx->type != val->type) &&
264 (GNUNET_BLOCK_TYPE_ANY != get_ctx->type) ) 306 (GNUNET_BLOCK_TYPE_ANY != get_ctx->type) )
265 return GNUNET_OK; 307 return GNUNET_OK;
266 ret = get_ctx->iter (get_ctx->iter_cls, 308 if (NULL != get_ctx->iter)
309 ret = get_ctx->iter (get_ctx->iter_cls,
310 key,
311 val->size,
312 (const char *) &val[1],
313 val->type,
267 val->discard_time, 314 val->discard_time,
268 key, 315 val->path_info_len,
269 val->size, 316 val->path_info);
270 (const char *) &val[1], 317 else
271 val->type); 318 ret = GNUNET_YES;
272
273 get_ctx->cnt++; 319 get_ctx->cnt++;
274 return ret; 320 return ret;
275} 321}
@@ -328,7 +374,8 @@ heap_plugin_del (void *cls)
328 val)); 374 val));
329 plugin->env->delete_notify (plugin->env->cls, 375 plugin->env->delete_notify (plugin->env->cls,
330 &val->key, 376 &val->key,
331 val->size); 377 val->size + OVERHEAD);
378 GNUNET_free_non_null (val->path_info);
332 GNUNET_free (val); 379 GNUNET_free (val);
333 return GNUNET_OK; 380 return GNUNET_OK;
334} 381}
diff --git a/src/datacache/plugin_datacache_mysql.c b/src/datacache/plugin_datacache_mysql.c
deleted file mode 100644
index 1457eddfb..000000000
--- a/src/datacache/plugin_datacache_mysql.c
+++ /dev/null
@@ -1,474 +0,0 @@
1/*
2 This file is part of GNUnet
3 (C) 2006, 2009, 2010 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 3, 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_mysql.c
23 * @brief mysql for an implementation of a database backend for the datacache
24 * @author Christian Grothoff
25 *
26 * SETUP INSTRUCTIONS:
27 *
28 * 1) Access mysql as root,
29 * <pre>
30 *
31 * $ mysql -u root -p
32 *
33 * </pre>
34 * and do the following. [You should replace $USER with the username
35 * that will be running the gnunetd process].
36 * @verbatim
37 CREATE DATABASE gnunet;
38 GRANT select,insert,update,delete,create,alter,drop,create temporary tables
39 ON gnunet.* TO $USER@localhost;
40 SET PASSWORD FOR $USER@localhost=PASSWORD('$the_password_you_like');
41 FLUSH PRIVILEGES;
42 @endverbatim
43 * 2) In the $HOME directory of $USER, create a ".my.cnf" file
44 * with the following lines
45 * @verbatim
46 [client]
47 user=$USER
48 password=$the_password_you_like
49 @endverbatim
50 *
51 * Thats it -- now you can configure your datastores in GNUnet to
52 * use MySQL. Note that .my.cnf file is a security risk unless its on
53 * a safe partition etc. The $HOME/.my.cnf can of course be a symbolic
54 * link. Even greater security risk can be achieved by setting no
55 * password for $USER. Luckily $USER has only priviledges to mess
56 * up GNUnet's tables, nothing else (unless you give him more,
57 * of course).<p>
58 *
59 * 3) Still, perhaps you should briefly try if the DB connection
60 * works. First, login as $USER. Then use,
61 * @verbatim
62 $ mysql -u $USER -p $the_password_you_like
63 mysql> use gnunet;
64 @endverbatim
65 *
66 * If you get the message &quot;Database changed&quot; it probably works.
67 *
68 * [If you get &quot;ERROR 2002: Can't connect to local MySQL server
69 * through socket '/tmp/mysql.sock' (2)&quot; it may be resolvable by
70 * &quot;ln -s /var/run/mysqld/mysqld.sock /tmp/mysql.sock&quot;
71 * so there may be some additional trouble depending on your mysql setup.]
72 *
73 * PROBLEMS?
74 *
75 * If you have problems related to the mysql module, your best
76 * friend is probably the mysql manual. The first thing to check
77 * is that mysql is basically operational, that you can connect
78 * to it, create tables, issue queries etc.
79 */
80#include "platform.h"
81#include "gnunet_util_lib.h"
82#include "gnunet_datacache_plugin.h"
83#include "gnunet_mysql_lib.h"
84#include <mysql/mysql.h>
85
86
87/**
88 * Estimate of the per-entry overhead (including indices).
89 */
90#define OVERHEAD ((4*2+4*2+8*2+8*2+sizeof(struct GNUNET_HashCode)*5+8))
91
92/**
93 * Die with an error message that indicates
94 * a failure of the command 'cmd' with the message given
95 * by strerror(errno).
96 */
97#define DIE_MYSQL(cmd, dbh) do { GNUNET_log(GNUNET_ERROR_TYPE__ERROR, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); GNUNET_abort(); } while(0);
98
99/**
100 * Log an error message at log-level 'level' that indicates
101 * a failure of the command 'cmd' on file 'filename'
102 * with the message given by strerror(errno).
103 */
104#define LOG_MYSQL(level, cmd, dbh) do { GNUNET_log(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); } while(0);
105
106
107/**
108 * Context for all functions in this plugin.
109 */
110struct Plugin
111{
112 /**
113 * Our execution environment.
114 */
115 struct GNUNET_DATACACHE_PluginEnvironment *env;
116
117 /**
118 * Handle to the mysql database.
119 */
120 struct GNUNET_MYSQL_Context *mc;
121
122#define SELECT_VALUE_STMT "SELECT value,expire FROM gn080dstore FORCE INDEX (hashidx) WHERE hash=? AND type=? AND expire >= ? LIMIT 1 OFFSET ?"
123 struct GNUNET_MYSQL_StatementHandle *select_value;
124
125#define COUNT_VALUE_STMT "SELECT count(*) FROM gn080dstore FORCE INDEX (hashidx) WHERE hash=? AND type=? AND expire >= ?"
126 struct GNUNET_MYSQL_StatementHandle *count_value;
127
128#define SELECT_OLD_VALUE_STMT "SELECT hash, vhash, type, value FROM gn080dstore FORCE INDEX (expireidx) ORDER BY puttime ASC LIMIT 1"
129 struct GNUNET_MYSQL_StatementHandle *select_old_value;
130
131#define DELETE_VALUE_STMT "DELETE FROM gn080dstore WHERE hash = ? AND vhash = ? AND type = ? AND value = ?"
132 struct GNUNET_MYSQL_StatementHandle *delete_value;
133
134#define INSERT_VALUE_STMT "INSERT INTO gn080dstore (type, puttime, expire, hash, vhash, value) "\
135 "VALUES (?, ?, ?, ?, ?, ?)"
136 struct GNUNET_MYSQL_StatementHandle *insert_value;
137
138#define UPDATE_VALUE_STMT "UPDATE gn080dstore FORCE INDEX (allidx) SET puttime=?, expire=? "\
139 "WHERE hash=? AND vhash=? AND type=?"
140 struct GNUNET_MYSQL_StatementHandle *update_value;
141
142};
143
144
145/**
146 * Create temporary table and prepare statements.
147 *
148 * @param plugin plugin context
149 * @return GNUNET_OK on success
150 */
151static int
152itable (struct Plugin *plugin)
153{
154#define MRUNS(a) (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, a) )
155 if (MRUNS
156 ("CREATE TEMPORARY TABLE gn080dstore ("
157 " type INT(11) UNSIGNED NOT NULL DEFAULT 0,"
158 " puttime BIGINT UNSIGNED NOT NULL DEFAULT 0,"
159 " expire BIGINT UNSIGNED NOT NULL DEFAULT 0,"
160 " hash BINARY(64) NOT NULL DEFAULT '',"
161 " vhash BINARY(64) NOT NULL DEFAULT '',"
162 " value BLOB NOT NULL DEFAULT '',"
163 " INDEX hashidx (hash(64),type,expire),"
164 " INDEX allidx (hash(64),vhash(64),type)," " INDEX expireidx (puttime)"
165 ") ENGINE=InnoDB") || MRUNS ("SET AUTOCOMMIT = 1"))
166 return GNUNET_SYSERR;
167#undef MRUNS
168#define PINIT(a,b) (NULL == (a = GNUNET_MYSQL_statement_prepare (plugin->mc, b)))
169 if (PINIT (plugin->select_value, SELECT_VALUE_STMT) ||
170 PINIT (plugin->count_value, COUNT_VALUE_STMT) ||
171 PINIT (plugin->select_old_value, SELECT_OLD_VALUE_STMT) ||
172 PINIT (plugin->delete_value, DELETE_VALUE_STMT) ||
173 PINIT (plugin->insert_value, INSERT_VALUE_STMT) ||
174 PINIT (plugin->update_value, UPDATE_VALUE_STMT))
175 return GNUNET_SYSERR;
176#undef PINIT
177 return GNUNET_OK;
178}
179
180
181/**
182 * Store an item in the datastore.
183 *
184 * @param cls closure (our "struct Plugin")
185 * @param key key to store data under
186 * @param size number of bytes in data
187 * @param data data to store
188 * @param type type of the value
189 * @param discard_time when to discard the value in any case
190 * @return 0 on error, number of bytes used otherwise
191 */
192static size_t
193mysql_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
194 const char *data, enum GNUNET_BLOCK_Type type,
195 struct GNUNET_TIME_Absolute discard_time)
196{
197 struct Plugin *plugin = cls;
198 struct GNUNET_TIME_Absolute now;
199 unsigned long k_length;
200 unsigned long h_length;
201 unsigned long v_length;
202 unsigned long long v_now;
203 unsigned long long v_discard_time;
204 unsigned int v_type;
205 struct GNUNET_HashCode vhash;
206 int ret;
207
208 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
209 return GNUNET_SYSERR;
210 GNUNET_CRYPTO_hash (data, size, &vhash);
211 now = GNUNET_TIME_absolute_get ();
212
213 /* first try UPDATE */
214 h_length = sizeof (struct GNUNET_HashCode);
215 k_length = sizeof (struct GNUNET_HashCode);
216 v_length = size;
217 v_type = type;
218 v_now = (unsigned long long) now.abs_value;
219 v_discard_time = (unsigned long long) discard_time.abs_value;
220 if (GNUNET_OK ==
221 GNUNET_MYSQL_statement_run_prepared (plugin->mc, plugin->update_value, NULL,
222 MYSQL_TYPE_LONGLONG, &v_now, GNUNET_YES,
223 MYSQL_TYPE_LONGLONG, &v_discard_time, GNUNET_YES,
224 MYSQL_TYPE_BLOB, key, sizeof (struct GNUNET_HashCode),
225 &k_length, MYSQL_TYPE_BLOB, &vhash,
226 sizeof (struct GNUNET_HashCode), &h_length,
227 MYSQL_TYPE_LONG, &v_type, GNUNET_YES, -1))
228 return GNUNET_OK;
229
230 /* now try INSERT */
231 h_length = sizeof (struct GNUNET_HashCode);
232 k_length = sizeof (struct GNUNET_HashCode);
233 v_length = size;
234 if (GNUNET_OK !=
235 (ret =
236 GNUNET_MYSQL_statement_run_prepared (plugin->mc, plugin->insert_value, NULL,
237 MYSQL_TYPE_LONG, &type, GNUNET_YES,
238 MYSQL_TYPE_LONGLONG, &v_now, GNUNET_YES,
239 MYSQL_TYPE_LONGLONG, &v_discard_time, GNUNET_YES,
240 MYSQL_TYPE_BLOB, key, sizeof (struct GNUNET_HashCode),
241 &k_length, MYSQL_TYPE_BLOB, &vhash,
242 sizeof (struct GNUNET_HashCode), &h_length,
243 MYSQL_TYPE_BLOB, data, (unsigned long) size,
244 &v_length, -1)))
245 {
246 if (ret == GNUNET_SYSERR)
247 itable (plugin);
248 return GNUNET_SYSERR;
249 }
250 return size + OVERHEAD;
251}
252
253
254static int
255return_ok (void *cls, unsigned int num_values, MYSQL_BIND * values)
256{
257 return GNUNET_OK;
258}
259
260
261/**
262 * Iterate over the results for a particular key
263 * in the datastore.
264 *
265 * @param cls closure (our "struct Plugin")
266 * @param key
267 * @param type entries of which type are relevant?
268 * @param iter maybe NULL (to just count)
269 * @param iter_cls closure for iter
270 * @return the number of results found
271 */
272static unsigned int
273mysql_plugin_get (void *cls, const struct GNUNET_HashCode * key,
274 enum GNUNET_BLOCK_Type type, GNUNET_DATACACHE_Iterator iter,
275 void *iter_cls)
276{
277 struct Plugin *plugin = cls;
278 MYSQL_BIND rbind[3];
279 unsigned long h_length;
280 unsigned long v_length;
281 unsigned long long v_expire;
282 struct GNUNET_TIME_Absolute now;
283 struct GNUNET_TIME_Absolute expire;
284 unsigned int cnt;
285 unsigned long long total;
286 unsigned long long v_now;
287 unsigned int off;
288 unsigned int v_type;
289 int ret;
290 char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
291
292 now = GNUNET_TIME_absolute_get ();
293 h_length = sizeof (struct GNUNET_HashCode);
294 v_length = sizeof (buffer);
295 total = -1;
296 memset (rbind, 0, sizeof (rbind));
297 rbind[0].buffer_type = MYSQL_TYPE_LONGLONG;
298 rbind[0].buffer = &total;
299 rbind[0].is_unsigned = GNUNET_YES;
300 v_type = type;
301 v_now = (unsigned long long) now.abs_value;
302 if ((GNUNET_OK !=
303 (ret =
304 GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->count_value, 1, rbind,
305 return_ok, NULL, MYSQL_TYPE_BLOB, key,
306 sizeof (struct GNUNET_HashCode), &h_length,
307 MYSQL_TYPE_LONG, &v_type, GNUNET_YES,
308 MYSQL_TYPE_LONGLONG, &v_now, GNUNET_YES,
309 -1))) || (-1 == total))
310 {
311 if (ret == GNUNET_SYSERR)
312 itable (plugin);
313 return GNUNET_SYSERR;
314 }
315 if ((iter == NULL) || (total == 0))
316 return (int) total;
317
318 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total);
319 cnt = 0;
320 while (cnt < total)
321 {
322 memset (rbind, 0, sizeof (rbind));
323 rbind[0].buffer_type = MYSQL_TYPE_BLOB;
324 rbind[0].buffer_length = sizeof (buffer);
325 rbind[0].length = &v_length;
326 rbind[0].buffer = buffer;
327 rbind[1].buffer_type = MYSQL_TYPE_LONGLONG;
328 rbind[1].is_unsigned = 1;
329 rbind[1].buffer = &v_expire;
330 off = (off + 1) % total;
331 if (GNUNET_OK !=
332 (ret =
333 GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->select_value, 2, rbind,
334 return_ok, NULL, MYSQL_TYPE_BLOB, key,
335 sizeof (struct GNUNET_HashCode), &h_length,
336 MYSQL_TYPE_LONG, &v_type, GNUNET_YES,
337 MYSQL_TYPE_LONGLONG, &v_now, GNUNET_YES,
338 MYSQL_TYPE_LONG, &off, GNUNET_YES, -1)))
339 {
340 if (ret == GNUNET_SYSERR)
341 itable (plugin);
342 return GNUNET_SYSERR;
343 }
344 cnt++;
345 expire.abs_value = v_expire;
346 if (GNUNET_OK != iter (iter_cls, expire, key, v_length, buffer, type))
347 break;
348 }
349 return cnt;
350}
351
352
353/**
354 * Delete the entry with the lowest expiration value
355 * from the datacache right now.
356 *
357 * @param cls closure (our "struct Plugin")
358 * @return GNUNET_OK on success, GNUNET_SYSERR on error
359 */
360static int
361mysql_plugin_del (void *cls)
362{
363 struct Plugin *plugin = cls;
364
365 MYSQL_BIND rbind[5];
366 unsigned int v_type;
367 struct GNUNET_HashCode v_key;
368 struct GNUNET_HashCode vhash;
369 unsigned long k_length;
370 unsigned long h_length;
371 unsigned long v_length;
372 int ret;
373 char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
374
375 k_length = sizeof (struct GNUNET_HashCode);
376 h_length = sizeof (struct GNUNET_HashCode);
377 v_length = sizeof (buffer);
378 memset (rbind, 0, sizeof (rbind));
379 rbind[0].buffer_type = MYSQL_TYPE_BLOB;
380 rbind[0].buffer_length = sizeof (struct GNUNET_HashCode);
381 rbind[0].length = &k_length;
382 rbind[0].buffer = &v_key;
383 rbind[1].buffer_type = MYSQL_TYPE_BLOB;
384 rbind[1].buffer_length = sizeof (struct GNUNET_HashCode);
385 rbind[1].length = &h_length;
386 rbind[1].buffer = &vhash;
387 rbind[2].buffer_type = MYSQL_TYPE_LONG;
388 rbind[2].is_unsigned = 1;
389 rbind[2].buffer = &v_type;
390 rbind[3].buffer_type = MYSQL_TYPE_BLOB;
391 rbind[3].buffer_length = sizeof (buffer);
392 rbind[3].length = &v_length;
393 rbind[3].buffer = buffer;
394 if ((GNUNET_OK !=
395 (ret =
396 GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->select_old_value, 4,
397 rbind, return_ok, NULL, -1))) ||
398 (GNUNET_OK !=
399 (ret =
400 GNUNET_MYSQL_statement_run_prepared (plugin->mc, plugin->delete_value, NULL,
401 MYSQL_TYPE_BLOB, &v_key,
402 sizeof (struct GNUNET_HashCode), &k_length,
403 MYSQL_TYPE_BLOB, &vhash,
404 sizeof (struct GNUNET_HashCode), &h_length,
405 MYSQL_TYPE_LONG, &v_type, GNUNET_YES,
406 MYSQL_TYPE_BLOB, buffer,
407 (unsigned long) sizeof (buffer), &v_length,
408 -1))))
409 {
410 if (ret == GNUNET_SYSERR)
411 itable (plugin);
412 return GNUNET_SYSERR;
413 }
414 plugin->env->delete_notify (plugin->env->cls, &v_key, v_length + OVERHEAD);
415
416 return GNUNET_OK;
417}
418
419
420/**
421 * Entry point for the plugin.
422 *
423 * @param cls closure (the "struct GNUNET_DATACACHE_PluginEnvironmnet")
424 * @return the plugin's closure (our "struct Plugin")
425 */
426void *
427libgnunet_plugin_datacache_mysql_init (void *cls)
428{
429 struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
430 struct GNUNET_DATACACHE_PluginFunctions *api;
431 struct Plugin *plugin;
432
433 plugin = GNUNET_malloc (sizeof (struct Plugin));
434 plugin->env = env;
435 plugin->mc = GNUNET_MYSQL_context_create (env->cfg, "datacache-mysql");
436 if ( (NULL == plugin->mc) ||
437 (GNUNET_OK != itable (plugin)) )
438 {
439 if (NULL != plugin->mc)
440 GNUNET_MYSQL_context_destroy (plugin->mc);
441 GNUNET_free (plugin);
442 return NULL;
443 }
444 api = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_PluginFunctions));
445 api->cls = plugin;
446 api->get = &mysql_plugin_get;
447 api->put = &mysql_plugin_put;
448 api->del = &mysql_plugin_del;
449 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "mysql",
450 _("MySQL datacache running\n"));
451 return api;
452}
453
454
455/**
456 * Exit point from the plugin.
457 *
458 * @param cls closure (our "struct Plugin")
459 * @return NULL
460 */
461void *
462libgnunet_plugin_datacache_mysql_done (void *cls)
463{
464 struct GNUNET_DATACACHE_PluginFunctions *api = cls;
465 struct Plugin *plugin = api->cls;
466
467 GNUNET_MYSQL_context_destroy (plugin->mc);
468 GNUNET_free (plugin);
469 GNUNET_free (api);
470 return NULL;
471}
472
473
474/* end of plugin_datacache_mysql.c */
diff --git a/src/datacache/plugin_datacache_postgres.c b/src/datacache/plugin_datacache_postgres.c
index e9157742c..e7d2e72c2 100644
--- a/src/datacache/plugin_datacache_postgres.c
+++ b/src/datacache/plugin_datacache_postgres.c
@@ -75,13 +75,18 @@ init_connection (struct Plugin *plugin)
75 " type INTEGER NOT NULL DEFAULT 0," 75 " type INTEGER NOT NULL DEFAULT 0,"
76 " discard_time BIGINT NOT NULL DEFAULT 0," 76 " discard_time BIGINT NOT NULL DEFAULT 0,"
77 " key BYTEA NOT NULL DEFAULT ''," 77 " key BYTEA NOT NULL DEFAULT '',"
78 " value BYTEA NOT NULL DEFAULT '')" "WITH OIDS"); 78 " value BYTEA NOT NULL DEFAULT '',"
79 if ((ret == NULL) || ((PQresultStatus (ret) != PGRES_COMMAND_OK) && (0 != strcmp ("42P07", /* duplicate table */ 79 " path BYTEA DEFAULT '')"
80 PQresultErrorField 80 "WITH OIDS");
81 (ret, 81 if ( (ret == NULL) ||
82 PG_DIAG_SQLSTATE))))) 82 ((PQresultStatus (ret) != PGRES_COMMAND_OK) &&
83 (0 != strcmp ("42P07", /* duplicate table */
84 PQresultErrorField
85 (ret,
86 PG_DIAG_SQLSTATE)))))
83 { 87 {
84 (void) GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "CREATE TABLE", 88 (void) GNUNET_POSTGRES_check_result (plugin->dbh, ret,
89 PGRES_COMMAND_OK, "CREATE TABLE",
85 "gn090dc"); 90 "gn090dc");
86 PQfinish (plugin->dbh); 91 PQfinish (plugin->dbh);
87 plugin->dbh = NULL; 92 plugin->dbh = NULL;
@@ -123,11 +128,11 @@ init_connection (struct Plugin *plugin)
123 PQclear (ret); 128 PQclear (ret);
124 if ((GNUNET_OK != 129 if ((GNUNET_OK !=
125 GNUNET_POSTGRES_prepare (plugin->dbh, "getkt", 130 GNUNET_POSTGRES_prepare (plugin->dbh, "getkt",
126 "SELECT discard_time,type,value FROM gn090dc " 131 "SELECT discard_time,type,value,path FROM gn090dc "
127 "WHERE key=$1 AND type=$2 ", 2)) || 132 "WHERE key=$1 AND type=$2 ", 2)) ||
128 (GNUNET_OK != 133 (GNUNET_OK !=
129 GNUNET_POSTGRES_prepare (plugin->dbh, "getk", 134 GNUNET_POSTGRES_prepare (plugin->dbh, "getk",
130 "SELECT discard_time,type,value FROM gn090dc " 135 "SELECT discard_time,type,value,path FROM gn090dc "
131 "WHERE key=$1", 1)) || 136 "WHERE key=$1", 1)) ||
132 (GNUNET_OK != 137 (GNUNET_OK !=
133 GNUNET_POSTGRES_prepare (plugin->dbh, "getm", 138 GNUNET_POSTGRES_prepare (plugin->dbh, "getm",
@@ -137,8 +142,8 @@ init_connection (struct Plugin *plugin)
137 GNUNET_POSTGRES_prepare (plugin->dbh, "delrow", "DELETE FROM gn090dc WHERE oid=$1", 1)) || 142 GNUNET_POSTGRES_prepare (plugin->dbh, "delrow", "DELETE FROM gn090dc WHERE oid=$1", 1)) ||
138 (GNUNET_OK != 143 (GNUNET_OK !=
139 GNUNET_POSTGRES_prepare (plugin->dbh, "put", 144 GNUNET_POSTGRES_prepare (plugin->dbh, "put",
140 "INSERT INTO gn090dc (type, discard_time, key, value) " 145 "INSERT INTO gn090dc (type, discard_time, key, value, path) "
141 "VALUES ($1, $2, $3, $4)", 4))) 146 "VALUES ($1, $2, $3, $4, $5)", 5)))
142 { 147 {
143 PQfinish (plugin->dbh); 148 PQfinish (plugin->dbh);
144 plugin->dbh = NULL; 149 plugin->dbh = NULL;
@@ -157,12 +162,16 @@ init_connection (struct Plugin *plugin)
157 * @param data data to store 162 * @param data data to store
158 * @param type type of the value 163 * @param type type of the value
159 * @param discard_time when to discard the value in any case 164 * @param discard_time when to discard the value in any case
160 * @return 0 on error, number of bytes used otherwise 165 * @param path_info_len number of entries in 'path_info'
166 * @param path_info a path through the network
167 * @return 0 if duplicate, -1 on error, number of bytes used otherwise
161 */ 168 */
162static size_t 169static ssize_t
163postgres_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size, 170postgres_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
164 const char *data, enum GNUNET_BLOCK_Type type, 171 const char *data, enum GNUNET_BLOCK_Type type,
165 struct GNUNET_TIME_Absolute discard_time) 172 struct GNUNET_TIME_Absolute discard_time,
173 unsigned int path_info_len,
174 const struct GNUNET_PeerIdentity *path_info)
166{ 175{
167 struct Plugin *plugin = cls; 176 struct Plugin *plugin = cls;
168 PGresult *ret; 177 PGresult *ret;
@@ -173,22 +182,25 @@ postgres_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
173 (const char *) &btype, 182 (const char *) &btype,
174 (const char *) &bexpi, 183 (const char *) &bexpi,
175 (const char *) key, 184 (const char *) key,
176 (const char *) data 185 (const char *) data,
186 (const char *) path_info
177 }; 187 };
178 int paramLengths[] = { 188 int paramLengths[] = {
179 sizeof (btype), 189 sizeof (btype),
180 sizeof (bexpi), 190 sizeof (bexpi),
181 sizeof (struct GNUNET_HashCode), 191 sizeof (struct GNUNET_HashCode),
182 size 192 size,
193 path_info_len * sizeof (struct GNUNET_PeerIdentity)
183 }; 194 };
184 const int paramFormats[] = { 1, 1, 1, 1 }; 195 const int paramFormats[] = { 1, 1, 1, 1, 1 };
185 196
186 ret = 197 ret =
187 PQexecPrepared (plugin->dbh, "put", 4, paramValues, paramLengths, 198 PQexecPrepared (plugin->dbh, "put", 5, paramValues, paramLengths,
188 paramFormats, 1); 199 paramFormats, 1);
189 if (GNUNET_OK != 200 if (GNUNET_OK !=
190 GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "PQexecPrepared", "put")) 201 GNUNET_POSTGRES_check_result (plugin->dbh, ret,
191 return GNUNET_SYSERR; 202 PGRES_COMMAND_OK, "PQexecPrepared", "put"))
203 return -1;
192 PQclear (ret); 204 PQclear (ret);
193 return size + OVERHEAD; 205 return size + OVERHEAD;
194} 206}
@@ -226,6 +238,8 @@ postgres_plugin_get (void *cls, const struct GNUNET_HashCode * key,
226 uint32_t size; 238 uint32_t size;
227 unsigned int cnt; 239 unsigned int cnt;
228 unsigned int i; 240 unsigned int i;
241 unsigned int path_len;
242 const struct GNUNET_PeerIdentity *path;
229 PGresult *res; 243 PGresult *res;
230 244
231 res = 245 res =
@@ -254,7 +268,7 @@ postgres_plugin_get (void *cls, const struct GNUNET_HashCode * key,
254 PQclear (res); 268 PQclear (res);
255 return cnt; 269 return cnt;
256 } 270 }
257 if ((3 != PQnfields (res)) || (sizeof (uint64_t) != PQfsize (res, 0)) || 271 if ((4 != PQnfields (res)) || (sizeof (uint64_t) != PQfsize (res, 0)) ||
258 (sizeof (uint32_t) != PQfsize (res, 1))) 272 (sizeof (uint32_t) != PQfsize (res, 1)))
259 { 273 {
260 GNUNET_break (0); 274 GNUNET_break (0);
@@ -267,12 +281,23 @@ postgres_plugin_get (void *cls, const struct GNUNET_HashCode * key,
267 GNUNET_ntohll (*(uint64_t *) PQgetvalue (res, i, 0)); 281 GNUNET_ntohll (*(uint64_t *) PQgetvalue (res, i, 0));
268 type = ntohl (*(uint32_t *) PQgetvalue (res, i, 1)); 282 type = ntohl (*(uint32_t *) PQgetvalue (res, i, 1));
269 size = PQgetlength (res, i, 2); 283 size = PQgetlength (res, i, 2);
284 path_len = PQgetlength (res, i, 3);
285 if (0 != (path_len % sizeof (struct GNUNET_PeerIdentity)))
286 {
287 GNUNET_break (0);
288 path_len = 0;
289 }
290 path_len %= sizeof (struct GNUNET_PeerIdentity);
291 path = (const struct GNUNET_PeerIdentity *) PQgetvalue (res, i, 3);
270 LOG (GNUNET_ERROR_TYPE_DEBUG, 292 LOG (GNUNET_ERROR_TYPE_DEBUG,
271 "Found result of size %u bytes and type %u in database\n", 293 "Found result of size %u bytes and type %u in database\n",
272 (unsigned int) size, (unsigned int) type); 294 (unsigned int) size, (unsigned int) type);
273 if (GNUNET_SYSERR == 295 if (GNUNET_SYSERR ==
274 iter (iter_cls, expiration_time, key, size, PQgetvalue (res, i, 2), 296 iter (iter_cls, key, size, PQgetvalue (res, i, 2),
275 (enum GNUNET_BLOCK_Type) type)) 297 (enum GNUNET_BLOCK_Type) type,
298 expiration_time,
299 path_len,
300 path))
276 { 301 {
277 LOG (GNUNET_ERROR_TYPE_DEBUG, 302 LOG (GNUNET_ERROR_TYPE_DEBUG,
278 "Ending iteration (client error)\n"); 303 "Ending iteration (client error)\n");
diff --git a/src/datacache/plugin_datacache_sqlite.c b/src/datacache/plugin_datacache_sqlite.c
index 74fa38544..3dae4643a 100644
--- a/src/datacache/plugin_datacache_sqlite.c
+++ b/src/datacache/plugin_datacache_sqlite.c
@@ -95,12 +95,16 @@ sq_prepare (sqlite3 * dbh, const char *zSql, /* SQL statement, UTF-8 encoded
95 * @param data data to store 95 * @param data data to store
96 * @param type type of the value 96 * @param type type of the value
97 * @param discard_time when to discard the value in any case 97 * @param discard_time when to discard the value in any case
98 * @return 0 on error, number of bytes used otherwise 98 * @return 0 if duplicate, -1 on error, number of bytes used otherwise
99 */ 99 */
100static size_t 100static ssize_t
101sqlite_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size, 101sqlite_plugin_put (void *cls,
102 const char *data, enum GNUNET_BLOCK_Type type, 102 const struct GNUNET_HashCode *key,
103 struct GNUNET_TIME_Absolute discard_time) 103 size_t size, const char *data,
104 enum GNUNET_BLOCK_Type type,
105 struct GNUNET_TIME_Absolute discard_time,
106 unsigned int path_info_len,
107 const struct GNUNET_PeerIdentity *path_info)
104{ 108{
105 struct Plugin *plugin = cls; 109 struct Plugin *plugin = cls;
106 sqlite3_stmt *stmt; 110 sqlite3_stmt *stmt;
@@ -115,31 +119,38 @@ sqlite_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
115 dval = INT64_MAX; 119 dval = INT64_MAX;
116 if (sq_prepare 120 if (sq_prepare
117 (plugin->dbh, 121 (plugin->dbh,
118 "INSERT INTO ds090 (type, expire, key, value) VALUES (?, ?, ?, ?)", 122 "INSERT INTO ds090 (type, expire, key, value, path) VALUES (?, ?, ?, ?, ?)",
119 &stmt) != SQLITE_OK) 123 &stmt) != SQLITE_OK)
120 { 124 {
121 LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 125 LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
122 "sq_prepare"); 126 "sq_prepare");
123 return 0; 127 return -1;
124 } 128 }
125 if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, type)) || 129 if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, type)) ||
126 (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, dval)) || 130 (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, dval)) ||
127 (SQLITE_OK != 131 (SQLITE_OK !=
128 sqlite3_bind_blob (stmt, 3, key, sizeof (struct GNUNET_HashCode), 132 sqlite3_bind_blob (stmt, 3,
133 key, sizeof (struct GNUNET_HashCode),
129 SQLITE_TRANSIENT)) || 134 SQLITE_TRANSIENT)) ||
130 (SQLITE_OK != sqlite3_bind_blob (stmt, 4, data, size, SQLITE_TRANSIENT))) 135 (SQLITE_OK != sqlite3_bind_blob (stmt, 4,
136 data, size,
137 SQLITE_TRANSIENT)) ||
138 (SQLITE_OK != sqlite3_bind_blob (stmt, 5,
139 path_info,
140 path_info_len * sizeof (struct GNUNET_PeerIdentity),
141 SQLITE_TRANSIENT)))
131 { 142 {
132 LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 143 LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
133 "sqlite3_bind_xxx"); 144 "sqlite3_bind_xxx");
134 sqlite3_finalize (stmt); 145 sqlite3_finalize (stmt);
135 return 0; 146 return -1;
136 } 147 }
137 if (SQLITE_DONE != sqlite3_step (stmt)) 148 if (SQLITE_DONE != sqlite3_step (stmt))
138 { 149 {
139 LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 150 LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
140 "sqlite3_step"); 151 "sqlite3_step");
141 sqlite3_finalize (stmt); 152 sqlite3_finalize (stmt);
142 return 0; 153 return -1;
143 } 154 }
144 if (SQLITE_OK != sqlite3_finalize (stmt)) 155 if (SQLITE_OK != sqlite3_finalize (stmt))
145 LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 156 LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
@@ -173,8 +184,10 @@ sqlite_plugin_get (void *cls, const struct GNUNET_HashCode * key,
173 unsigned int cnt; 184 unsigned int cnt;
174 unsigned int off; 185 unsigned int off;
175 unsigned int total; 186 unsigned int total;
187 unsigned int psize;
176 char scratch[256]; 188 char scratch[256];
177 int64_t ntime; 189 int64_t ntime;
190 const struct GNUNET_PeerIdentity *path;
178 191
179 now = GNUNET_TIME_absolute_get (); 192 now = GNUNET_TIME_absolute_get ();
180 LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' for key `%4s'\n", "GET", 193 LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' for key `%4s'\n", "GET",
@@ -229,7 +242,7 @@ sqlite_plugin_get (void *cls, const struct GNUNET_HashCode * key,
229 { 242 {
230 off = (off + 1) % total; 243 off = (off + 1) % total;
231 GNUNET_snprintf (scratch, sizeof (scratch), 244 GNUNET_snprintf (scratch, sizeof (scratch),
232 "SELECT value,expire FROM ds090 WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET %u", 245 "SELECT value,expire,path FROM ds090 WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET %u",
233 off); 246 off);
234 if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK) 247 if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK)
235 { 248 {
@@ -253,6 +266,17 @@ sqlite_plugin_get (void *cls, const struct GNUNET_HashCode * key,
253 size = sqlite3_column_bytes (stmt, 0); 266 size = sqlite3_column_bytes (stmt, 0);
254 dat = sqlite3_column_blob (stmt, 0); 267 dat = sqlite3_column_blob (stmt, 0);
255 exp.abs_value = sqlite3_column_int64 (stmt, 1); 268 exp.abs_value = sqlite3_column_int64 (stmt, 1);
269 psize = sqlite3_column_bytes (stmt, 2);
270 if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
271 {
272 GNUNET_break (0);
273 psize = 0;
274 }
275 psize /= sizeof (struct GNUNET_PeerIdentity);
276 if (0 != psize)
277 path = sqlite3_column_blob (stmt, 2);
278 else
279 path = NULL;
256 ntime = (int64_t) exp.abs_value; 280 ntime = (int64_t) exp.abs_value;
257 if (ntime == INT64_MAX) 281 if (ntime == INT64_MAX)
258 exp = GNUNET_TIME_UNIT_FOREVER_ABS; 282 exp = GNUNET_TIME_UNIT_FOREVER_ABS;
@@ -260,7 +284,7 @@ sqlite_plugin_get (void *cls, const struct GNUNET_HashCode * key,
260 LOG (GNUNET_ERROR_TYPE_DEBUG, 284 LOG (GNUNET_ERROR_TYPE_DEBUG,
261 "Found %u-byte result when processing `%s' for key `%4s'\n", 285 "Found %u-byte result when processing `%s' for key `%4s'\n",
262 (unsigned int) size, "GET", GNUNET_h2s (key)); 286 (unsigned int) size, "GET", GNUNET_h2s (key));
263 if (GNUNET_OK != iter (iter_cls, exp, key, size, dat, type)) 287 if (GNUNET_OK != iter (iter_cls, key, size, dat, type, exp, psize, path))
264 { 288 {
265 sqlite3_finalize (stmt); 289 sqlite3_finalize (stmt);
266 break; 290 break;
@@ -408,7 +432,8 @@ libgnunet_plugin_datacache_sqlite_init (void *cls)
408 "CREATE TABLE ds090 (" " type INTEGER NOT NULL DEFAULT 0," 432 "CREATE TABLE ds090 (" " type INTEGER NOT NULL DEFAULT 0,"
409 " expire INTEGER NOT NULL DEFAULT 0," 433 " expire INTEGER NOT NULL DEFAULT 0,"
410 " key BLOB NOT NULL DEFAULT ''," 434 " key BLOB NOT NULL DEFAULT '',"
411 " value BLOB NOT NULL DEFAULT '')"); 435 " value BLOB NOT NULL DEFAULT '',"
436 " path BLOB DEFAULT '')");
412 SQLITE3_EXEC (dbh, "CREATE INDEX idx_hashidx ON ds090 (key,type,expire)"); 437 SQLITE3_EXEC (dbh, "CREATE INDEX idx_hashidx ON ds090 (key,type,expire)");
413 SQLITE3_EXEC (dbh, "CREATE INDEX idx_expire ON ds090 (expire)"); 438 SQLITE3_EXEC (dbh, "CREATE INDEX idx_expire ON ds090 (expire)");
414 plugin = GNUNET_malloc (sizeof (struct Plugin)); 439 plugin = GNUNET_malloc (sizeof (struct Plugin));
diff --git a/src/datacache/plugin_datacache_template.c b/src/datacache/plugin_datacache_template.c
index 6c4395982..306615571 100644
--- a/src/datacache/plugin_datacache_template.c
+++ b/src/datacache/plugin_datacache_template.c
@@ -49,15 +49,19 @@ struct Plugin
49 * @param data data to store 49 * @param data data to store
50 * @param type type of the value 50 * @param type type of the value
51 * @param discard_time when to discard the value in any case 51 * @param discard_time when to discard the value in any case
52 * @return 0 on error, number of bytes used otherwise 52 * @param path_info_len number of entries in 'path_info'
53 * @param path_info a path through the network
54 * @return 0 if duplicate, -1 on error, number of bytes used otherwise
53 */ 55 */
54static size_t 56static ssize_t
55template_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size, 57template_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
56 const char *data, enum GNUNET_BLOCK_Type type, 58 const char *data, enum GNUNET_BLOCK_Type type,
57 struct GNUNET_TIME_Absolute discard_time) 59 struct GNUNET_TIME_Absolute discard_time,
60 unsigned int path_info_len,
61 const struct GNUNET_PeerIdentity *path_info)
58{ 62{
59 GNUNET_break (0); 63 GNUNET_break (0);
60 return 0; 64 return -1;
61} 65}
62 66
63 67
diff --git a/src/datacache/test_datacache.c b/src/datacache/test_datacache.c
index 1d8cd3295..5162924f7 100644
--- a/src/datacache/test_datacache.c
+++ b/src/datacache/test_datacache.c
@@ -38,9 +38,13 @@ static const char *plugin_name;
38 38
39 39
40static int 40static int
41checkIt (void *cls, struct GNUNET_TIME_Absolute exp, 41checkIt (void *cls,
42 const struct GNUNET_HashCode * key, size_t size, const char *data, 42 const struct GNUNET_HashCode *key,
43 enum GNUNET_BLOCK_Type type) 43 size_t size, const char *data,
44 enum GNUNET_BLOCK_Type type,
45 struct GNUNET_TIME_Absolute exp,
46 unsigned int path_len,
47 const struct GNUNET_PeerIdentity *path)
44{ 48{
45 if (size != sizeof (struct GNUNET_HashCode)) 49 if (size != sizeof (struct GNUNET_HashCode))
46 { 50 {
@@ -83,7 +87,8 @@ run (void *cls, char *const *args, const char *cfgfile,
83 GNUNET_CRYPTO_hash (&k, sizeof (struct GNUNET_HashCode), &n); 87 GNUNET_CRYPTO_hash (&k, sizeof (struct GNUNET_HashCode), &n);
84 ASSERT (GNUNET_OK == 88 ASSERT (GNUNET_OK ==
85 GNUNET_DATACACHE_put (h, &k, sizeof (struct GNUNET_HashCode), 89 GNUNET_DATACACHE_put (h, &k, sizeof (struct GNUNET_HashCode),
86 (const char *) &n, 1 + i % 16, exp)); 90 (const char *) &n, 1 + i % 16, exp,
91 0, NULL));
87 k = n; 92 k = n;
88 } 93 }
89 memset (&k, 0, sizeof (struct GNUNET_HashCode)); 94 memset (&k, 0, sizeof (struct GNUNET_HashCode));
@@ -99,7 +104,8 @@ run (void *cls, char *const *args, const char *cfgfile,
99 ASSERT (GNUNET_OK == 104 ASSERT (GNUNET_OK ==
100 GNUNET_DATACACHE_put (h, &k, sizeof (struct GNUNET_HashCode), 105 GNUNET_DATACACHE_put (h, &k, sizeof (struct GNUNET_HashCode),
101 (const char *) &n, 792, 106 (const char *) &n, 792,
102 GNUNET_TIME_UNIT_FOREVER_ABS)); 107 GNUNET_TIME_UNIT_FOREVER_ABS,
108 0, NULL));
103 ASSERT (0 != GNUNET_DATACACHE_get (h, &k, 792, &checkIt, &n)); 109 ASSERT (0 != GNUNET_DATACACHE_get (h, &k, 792, &checkIt, &n));
104 110
105 GNUNET_DATACACHE_destroy (h); 111 GNUNET_DATACACHE_destroy (h);
diff --git a/src/datacache/test_datacache_data_heap.conf b/src/datacache/test_datacache_data_heap.conf
new file mode 100644
index 000000000..082cf48f4
--- /dev/null
+++ b/src/datacache/test_datacache_data_heap.conf
@@ -0,0 +1,4 @@
1[testcache]
2QUOTA = 1 MB
3DATABASE = heap
4
diff --git a/src/datacache/test_datacache_data_mysql.conf b/src/datacache/test_datacache_data_mysql.conf
deleted file mode 100644
index bc9daa3ad..000000000
--- a/src/datacache/test_datacache_data_mysql.conf
+++ /dev/null
@@ -1,13 +0,0 @@
1[testcache]
2QUOTA = 1 MB
3DATABASE = mysql
4
5[datacache-mysql]
6DATABASE = gnunetcheck
7# CONFIG = ~/.my.cnf
8# USER =
9# PASSWORD =
10# HOST =
11# PORT =
12
13
diff --git a/src/datacache/test_datacache_quota.c b/src/datacache/test_datacache_quota.c
index 1f252c14a..cac4d1878 100644
--- a/src/datacache/test_datacache_quota.c
+++ b/src/datacache/test_datacache_quota.c
@@ -73,7 +73,7 @@ run (void *cls, char *const *args, const char *cfgfile,
73 { 73 {
74 exp.abs_value++; 74 exp.abs_value++;
75 buf[j] = i; 75 buf[j] = i;
76 ASSERT (GNUNET_OK == GNUNET_DATACACHE_put (h, &k, j, buf, 1 + i, exp)); 76 ASSERT (GNUNET_OK == GNUNET_DATACACHE_put (h, &k, j, buf, 1 + i, exp, 0, NULL));
77 ASSERT (0 < GNUNET_DATACACHE_get (h, &k, 1 + i, NULL, NULL)); 77 ASSERT (0 < GNUNET_DATACACHE_get (h, &k, 1 + i, NULL, NULL));
78 } 78 }
79 k = n; 79 k = n;
diff --git a/src/dht/gnunet-service-dht_datacache.c b/src/dht/gnunet-service-dht_datacache.c
index b2cb93d12..4768c14fd 100644
--- a/src/dht/gnunet-service-dht_datacache.c
+++ b/src/dht/gnunet-service-dht_datacache.c
@@ -39,28 +39,6 @@ static struct GNUNET_DATACACHE_Handle *datacache;
39 39
40 40
41/** 41/**
42 * Entry for inserting data into datacache from the DHT.
43 */
44struct DHTPutEntry
45{
46 /**
47 * Size of data.
48 */
49 uint16_t data_size;
50
51 /**
52 * Length of recorded path.
53 */
54 uint16_t path_length;
55
56 /* PATH ENTRIES */
57
58 /* PUT DATA */
59
60};
61
62
63/**
64 * Handle a datum we've received from another peer. Cache if 42 * Handle a datum we've received from another peer. Cache if
65 * possible. 43 * possible.
66 * 44 *
@@ -80,14 +58,7 @@ GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration,
80 enum GNUNET_BLOCK_Type type, size_t data_size, 58 enum GNUNET_BLOCK_Type type, size_t data_size,
81 const void *data) 59 const void *data)
82{ 60{
83 size_t plen = 61 if (NULL == datacache)
84 data_size + put_path_length * sizeof (struct GNUNET_PeerIdentity) +
85 sizeof (struct DHTPutEntry);
86 char buf[plen];
87 struct DHTPutEntry *pe;
88 struct GNUNET_PeerIdentity *pp;
89
90 if (datacache == NULL)
91 { 62 {
92 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 63 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
93 _("%s request received, but have no datacache!\n"), "PUT"); 64 _("%s request received, but have no datacache!\n"), "PUT");
@@ -102,14 +73,9 @@ GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration,
102 GNUNET_STATISTICS_update (GDS_stats, 73 GNUNET_STATISTICS_update (GDS_stats,
103 gettext_noop ("# ITEMS stored in datacache"), 1, 74 gettext_noop ("# ITEMS stored in datacache"), 1,
104 GNUNET_NO); 75 GNUNET_NO);
105 pe = (struct DHTPutEntry *) buf; 76 (void) GNUNET_DATACACHE_put (datacache, key,
106 pe->data_size = htons (data_size); 77 data_size, data, type,
107 pe->path_length = htons ((uint16_t) put_path_length); 78 expiration, put_path_length, put_path);
108 pp = (struct GNUNET_PeerIdentity *) &pe[1];
109 memcpy (pp, put_path, put_path_length * sizeof (struct GNUNET_PeerIdentity));
110 memcpy (&pp[put_path_length], data, data_size);
111 (void) GNUNET_DATACACHE_put (datacache, key, plen, (const char *) pe, type,
112 expiration);
113} 79}
114 80
115 81
@@ -159,40 +125,26 @@ struct GetRequestContext
159 * @param size the size of the data identified by key 125 * @param size the size of the data identified by key
160 * @param data the actual data 126 * @param data the actual data
161 * @param type the type of the data 127 * @param type the type of the data
162 * 128 * @param put_path_length number of peers in 'put_path'
129 * @param put_path path the reply took on put
163 * @return GNUNET_OK to continue iteration, anything else 130 * @return GNUNET_OK to continue iteration, anything else
164 * to stop iteration. 131 * to stop iteration.
165 */ 132 */
166static int 133static int
167datacache_get_iterator (void *cls, struct GNUNET_TIME_Absolute exp, 134datacache_get_iterator (void *cls,
168 const struct GNUNET_HashCode * key, size_t size, 135 const struct GNUNET_HashCode * key, size_t size,
169 const char *data, enum GNUNET_BLOCK_Type type) 136 const char *data, enum GNUNET_BLOCK_Type type,
137 struct GNUNET_TIME_Absolute exp,
138 unsigned int put_path_length,
139 const struct GNUNET_PeerIdentity *put_path)
170{ 140{
171 struct GetRequestContext *ctx = cls; 141 struct GetRequestContext *ctx = cls;
172 const struct DHTPutEntry *pe;
173 const struct GNUNET_PeerIdentity *pp;
174 const char *rdata;
175 size_t rdata_size;
176 uint16_t put_path_length;
177 enum GNUNET_BLOCK_EvaluationResult eval; 142 enum GNUNET_BLOCK_EvaluationResult eval;
178 143
179 pe = (const struct DHTPutEntry *) data;
180 put_path_length = ntohs (pe->path_length);
181 rdata_size = ntohs (pe->data_size);
182
183 if (size !=
184 sizeof (struct DHTPutEntry) + rdata_size +
185 (put_path_length * sizeof (struct GNUNET_PeerIdentity)))
186 {
187 GNUNET_break (0);
188 return GNUNET_OK;
189 }
190 pp = (const struct GNUNET_PeerIdentity *) &pe[1];
191 rdata = (const char *) &pp[put_path_length];
192 eval = 144 eval =
193 GNUNET_BLOCK_evaluate (GDS_block_context, type, key, ctx->reply_bf, 145 GNUNET_BLOCK_evaluate (GDS_block_context, type, key, ctx->reply_bf,
194 ctx->reply_bf_mutator, ctx->xquery, 146 ctx->reply_bf_mutator, ctx->xquery,
195 ctx->xquery_size, rdata, rdata_size); 147 ctx->xquery_size, data, size);
196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
197 "Found reply for query %s in datacache, evaluation result is %d\n", 149 "Found reply for query %s in datacache, evaluation result is %d\n",
198 GNUNET_h2s (key), (int) eval); 150 GNUNET_h2s (key), (int) eval);
@@ -206,11 +158,11 @@ datacache_get_iterator (void *cls, struct GNUNET_TIME_Absolute exp,
206 gettext_noop 158 gettext_noop
207 ("# Good RESULTS found in datacache"), 1, 159 ("# Good RESULTS found in datacache"), 1,
208 GNUNET_NO); 160 GNUNET_NO);
209 GDS_CLIENTS_handle_reply (exp, key, 0, NULL, put_path_length, pp, type, 161 GDS_CLIENTS_handle_reply (exp, key, 0, NULL, put_path_length, put_path, type,
210 rdata_size, rdata); 162 size, data);
211 /* forward to other peers */ 163 /* forward to other peers */
212 GDS_ROUTING_process (type, exp, key, put_path_length, pp, 0, NULL, rdata, 164 GDS_ROUTING_process (type, exp, key, put_path_length, put_path, 0, NULL, data,
213 rdata_size); 165 size);
214 break; 166 break;
215 case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE: 167 case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
216 GNUNET_STATISTICS_update (GDS_stats, 168 GNUNET_STATISTICS_update (GDS_stats,
diff --git a/src/include/gnunet_datacache_lib.h b/src/include/gnunet_datacache_lib.h
index 071b304be..4f97ee526 100644
--- a/src/include/gnunet_datacache_lib.h
+++ b/src/include/gnunet_datacache_lib.h
@@ -74,18 +74,22 @@ GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h);
74 * An iterator over a set of items stored in the datacache. 74 * An iterator over a set of items stored in the datacache.
75 * 75 *
76 * @param cls closure 76 * @param cls closure
77 * @param exp when will the content expire?
78 * @param key key for the content 77 * @param key key for the content
79 * @param size number of bytes in data 78 * @param size number of bytes in data
80 * @param data content stored 79 * @param data content stored
81 * @param type type of the content 80 * @param type type of the content
81 * @param exp when will the content expire?
82 * @param path_info_len number of entries in 'path_info'
83 * @param path_info a path through the network
82 * @return GNUNET_OK to continue iterating, GNUNET_SYSERR to abort 84 * @return GNUNET_OK to continue iterating, GNUNET_SYSERR to abort
83 */ 85 */
84typedef int (*GNUNET_DATACACHE_Iterator) (void *cls, 86typedef int (*GNUNET_DATACACHE_Iterator) (void *cls,
85 struct GNUNET_TIME_Absolute exp, 87 const struct GNUNET_HashCode *key,
86 const struct GNUNET_HashCode * key,
87 size_t size, const char *data, 88 size_t size, const char *data,
88 enum GNUNET_BLOCK_Type type); 89 enum GNUNET_BLOCK_Type type,
90 struct GNUNET_TIME_Absolute exp,
91 unsigned int path_info_len,
92 const struct GNUNET_PeerIdentity *path_info);
89 93
90 94
91/** 95/**
@@ -97,13 +101,17 @@ typedef int (*GNUNET_DATACACHE_Iterator) (void *cls,
97 * @param data data to store 101 * @param data data to store
98 * @param type type of the value 102 * @param type type of the value
99 * @param discard_time when to discard the value in any case 103 * @param discard_time when to discard the value in any case
100 * @return GNUNET_OK on success, GNUNET_SYSERR on error (full, etc.) 104 * @param path_info_len number of entries in 'path_info'
105 * @param path_info a path through the network
106 * @return GNUNET_OK on success, GNUNET_SYSERR on error, GNUNET_NO if duplicate
101 */ 107 */
102int 108int
103GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h, 109GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h,
104 const struct GNUNET_HashCode * key, size_t size, 110 const struct GNUNET_HashCode * key, size_t size,
105 const char *data, enum GNUNET_BLOCK_Type type, 111 const char *data, enum GNUNET_BLOCK_Type type,
106 struct GNUNET_TIME_Absolute discard_time); 112 struct GNUNET_TIME_Absolute discard_time,
113 unsigned int path_info_len,
114 const struct GNUNET_PeerIdentity *path_info);
107 115
108 116
109/** 117/**
diff --git a/src/include/gnunet_datacache_plugin.h b/src/include/gnunet_datacache_plugin.h
index 18268efd7..2e0750160 100644
--- a/src/include/gnunet_datacache_plugin.h
+++ b/src/include/gnunet_datacache_plugin.h
@@ -107,11 +107,15 @@ struct GNUNET_DATACACHE_PluginFunctions
107 * @param data data to store 107 * @param data data to store
108 * @param type type of the value 108 * @param type type of the value
109 * @param discard_time when to discard the value in any case 109 * @param discard_time when to discard the value in any case
110 * @return 0 on error, number of bytes used otherwise 110 * @param path_info_len number of entries in 'path_info'
111 * @param path_info a path through the network
112 * @return 0 if duplicate, -1 on error, number of bytes used otherwise
111 */ 113 */
112 size_t (*put) (void *cls, const struct GNUNET_HashCode * key, size_t size, 114 ssize_t (*put) (void *cls, const struct GNUNET_HashCode * key, size_t size,
113 const char *data, enum GNUNET_BLOCK_Type type, 115 const char *data, enum GNUNET_BLOCK_Type type,
114 struct GNUNET_TIME_Absolute discard_time); 116 struct GNUNET_TIME_Absolute discard_time,
117 unsigned int path_info_len,
118 const struct GNUNET_PeerIdentity *path_info);
115 119
116 120
117 /** 121 /**