2 This file is part of GNUnet
3 Copyright (C) 2012, 2015 GNUnet e.V.
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.
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.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file datacache/plugin_datacache_heap.c
23 * @brief heap-only implementation of a database backend for the datacache
24 * @author Christian Grothoff
27 #include "gnunet_util_lib.h"
28 #include "gnunet_datacache_plugin.h"
30 #define LOG(kind,...) GNUNET_log_from (kind, "datacache-heap", __VA_ARGS__)
32 #define LOG_STRERROR_FILE(kind,op,fn) GNUNET_log_from_strerror_file (kind, "datacache-heap", op, fn)
37 * Context for all functions in this plugin.
42 * Our execution environment.
44 struct GNUNET_DATACACHE_PluginEnvironment *env;
49 struct GNUNET_CONTAINER_MultiHashMap *map;
52 * Heap for expirations.
54 struct GNUNET_CONTAINER_Heap *heap;
60 * Entry in the hash map.
67 struct GNUNET_HashCode key;
72 struct GNUNET_TIME_Absolute discard_time;
75 * Corresponding node in the heap.
77 struct GNUNET_CONTAINER_HeapNode *hn;
82 struct GNUNET_PeerIdentity *path_info;
85 * Payload (actual payload follows this struct)
90 * Number of entries in @e path_info.
92 unsigned int path_info_len;
97 enum GNUNET_BLOCK_Type type;
102 #define OVERHEAD (sizeof (struct Value) + 64)
106 * Closure for #put_cb().
111 * Expiration time for the new value.
113 struct GNUNET_TIME_Absolute discard_time;
116 * Data for the new value.
121 * Heap from the plugin.
123 struct GNUNET_CONTAINER_Heap *heap;
128 const struct GNUNET_PeerIdentity *path_info;
131 * Number of bytes in @e data.
138 enum GNUNET_BLOCK_Type type;
141 * Number of entries in @e path_info.
143 unsigned int path_info_len;
146 * Value to set to #GNUNET_YES if an equivalent block was found.
153 * Function called during PUT to detect if an equivalent block
156 * @param cls the `struct PutContext`
157 * @param key the key for the value(s)
158 * @param value an existing value
159 * @return #GNUNET_YES if not found (to continue to iterate)
163 const struct GNUNET_HashCode *key,
166 struct PutContext *put_ctx = cls;
167 struct Value *val = value;
169 if ( (val->size == put_ctx->size) &&
170 (val->type == put_ctx->type) &&
171 (0 == memcmp (&val[1], put_ctx->data, put_ctx->size)) )
173 put_ctx->found = GNUNET_YES;
174 val->discard_time = GNUNET_TIME_absolute_max (val->discard_time,
175 put_ctx->discard_time);
176 /* replace old path with new path */
177 GNUNET_array_grow (val->path_info,
179 put_ctx->path_info_len);
180 GNUNET_memcpy (val->path_info,
182 put_ctx->path_info_len * sizeof (struct GNUNET_PeerIdentity));
183 GNUNET_CONTAINER_heap_update_cost (put_ctx->heap,
185 val->discard_time.abs_value_us);
186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
187 "Got same value for key %s and type %d (size %u vs %u)\n",
190 (unsigned int) val->size,
191 (unsigned int) put_ctx->size);
199 * Store an item in the datastore.
201 * @param cls closure (our `struct Plugin`)
202 * @param key key to store data under
203 * @param size number of bytes in @a data
204 * @param data data to store
205 * @param type type of the value
206 * @param discard_time when to discard the value in any case
207 * @param path_info_len number of entries in @a path_info
208 * @param path_info a path through the network
209 * @return 0 if duplicate, -1 on error, number of bytes used otherwise
212 heap_plugin_put (void *cls,
213 const struct GNUNET_HashCode *key,
216 enum GNUNET_BLOCK_Type type,
217 struct GNUNET_TIME_Absolute discard_time,
218 unsigned int path_info_len,
219 const struct GNUNET_PeerIdentity *path_info)
221 struct Plugin *plugin = cls;
223 struct PutContext put_ctx;
225 put_ctx.found = GNUNET_NO;
226 put_ctx.heap = plugin->heap;
229 put_ctx.path_info = path_info;
230 put_ctx.path_info_len = path_info_len;
231 put_ctx.discard_time = discard_time;
233 GNUNET_CONTAINER_multihashmap_get_multiple (plugin->map,
237 if (GNUNET_YES == put_ctx.found)
239 val = GNUNET_malloc (sizeof (struct Value) + size);
240 GNUNET_memcpy (&val[1], data, size);
243 val->discard_time = discard_time;
245 GNUNET_array_grow (val->path_info,
248 GNUNET_memcpy (val->path_info,
250 path_info_len * sizeof (struct GNUNET_PeerIdentity));
251 (void) GNUNET_CONTAINER_multihashmap_put (plugin->map,
254 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
255 val->hn = GNUNET_CONTAINER_heap_insert (plugin->heap,
257 val->discard_time.abs_value_us);
258 return size + OVERHEAD;
263 * Closure for #get_cb().
268 * Function to call for each result.
270 GNUNET_DATACACHE_Iterator iter;
273 * Closure for @e iter.
278 * Number of results found.
283 * Block type requested.
285 enum GNUNET_BLOCK_Type type;
291 * Function called during GET to find matching blocks.
292 * Only matches by type.
294 * @param cls the `struct GetContext`
295 * @param key the key for the value(s)
296 * @param value an existing value
297 * @return #GNUNET_YES to continue to iterate
301 const struct GNUNET_HashCode *key,
304 struct GetContext *get_ctx = cls;
305 struct Value *val = value;
308 if ( (get_ctx->type != val->type) &&
309 (GNUNET_BLOCK_TYPE_ANY != get_ctx->type) )
311 if (NULL != get_ctx->iter)
312 ret = get_ctx->iter (get_ctx->iter_cls,
315 (const char *) &val[1],
328 * Iterate over the results for a particular key
331 * @param cls closure (our `struct Plugin`)
333 * @param type entries of which type are relevant?
334 * @param iter maybe NULL (to just count)
335 * @param iter_cls closure for @a iter
336 * @return the number of results found
339 heap_plugin_get (void *cls,
340 const struct GNUNET_HashCode *key,
341 enum GNUNET_BLOCK_Type type,
342 GNUNET_DATACACHE_Iterator iter,
345 struct Plugin *plugin = cls;
346 struct GetContext get_ctx;
350 get_ctx.iter_cls = iter_cls;
352 GNUNET_CONTAINER_multihashmap_get_multiple (plugin->map,
361 * Delete the entry with the lowest expiration value
362 * from the datacache right now.
364 * @param cls closure (our `struct Plugin`)
365 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
368 heap_plugin_del (void *cls)
370 struct Plugin *plugin = cls;
373 val = GNUNET_CONTAINER_heap_remove_root (plugin->heap);
375 return GNUNET_SYSERR;
376 GNUNET_assert (GNUNET_YES ==
377 GNUNET_CONTAINER_multihashmap_remove (plugin->map,
380 plugin->env->delete_notify (plugin->env->cls,
382 val->size + OVERHEAD);
383 GNUNET_free_non_null (val->path_info);
390 * Return a random value from the datastore.
392 * @param cls closure (our `struct Plugin`)
393 * @param iter maybe NULL (to just count)
394 * @param iter_cls closure for @a iter
395 * @return the number of results found
398 heap_plugin_get_random (void *cls,
399 GNUNET_DATACACHE_Iterator iter,
402 struct Plugin *plugin = cls;
403 struct GetContext get_ctx;
405 get_ctx.type = GNUNET_BLOCK_TYPE_ANY;
407 get_ctx.iter_cls = iter_cls;
409 GNUNET_CONTAINER_multihashmap_get_random (plugin->map,
417 * Iterate over the results that are "close" to a particular key in
418 * the datacache. "close" is defined as numerically larger than @a
419 * key (when interpreted as a circular address space), with small
422 * @param cls closure (internal context for the plugin)
423 * @param key area of the keyspace to look into
424 * @param num_results number of results that should be returned to @a iter
425 * @param iter maybe NULL (to just count)
426 * @param iter_cls closure for @a iter
427 * @return the number of results found
430 heap_plugin_get_closest (void *cls,
431 const struct GNUNET_HashCode *key,
432 unsigned int num_results,
433 GNUNET_DATACACHE_Iterator iter,
436 GNUNET_break (0); // not implemented!
442 * Entry point for the plugin.
444 * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironmnet`)
445 * @return the plugin's closure (our `struct Plugin`)
448 libgnunet_plugin_datacache_heap_init (void *cls)
450 struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
451 struct GNUNET_DATACACHE_PluginFunctions *api;
452 struct Plugin *plugin;
454 plugin = GNUNET_new (struct Plugin);
455 plugin->map = GNUNET_CONTAINER_multihashmap_create (1024, /* FIXME: base on quota! */
457 plugin->heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
459 api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
461 api->get = &heap_plugin_get;
462 api->put = &heap_plugin_put;
463 api->del = &heap_plugin_del;
464 api->get_random = &heap_plugin_get_random;
465 api->get_closest = &heap_plugin_get_closest;
466 LOG (GNUNET_ERROR_TYPE_INFO,
467 _("Heap datacache running\n"));
473 * Exit point from the plugin.
475 * @param cls closure (our "struct Plugin")
479 libgnunet_plugin_datacache_heap_done (void *cls)
481 struct GNUNET_DATACACHE_PluginFunctions *api = cls;
482 struct Plugin *plugin = api->cls;
485 while (NULL != (val = GNUNET_CONTAINER_heap_remove_root (plugin->heap)))
487 GNUNET_assert (GNUNET_YES ==
488 GNUNET_CONTAINER_multihashmap_remove (plugin->map,
491 GNUNET_free_non_null (val->path_info);
494 GNUNET_CONTAINER_heap_destroy (plugin->heap);
495 GNUNET_CONTAINER_multihashmap_destroy (plugin->map);
496 GNUNET_free (plugin);
503 /* end of plugin_datacache_heap.c */