GNUnet 0.28.1-dev.6-3-gbc381df64
 
Loading...
Searching...
No Matches
plugin_datacache_heap.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet
3 Copyright (C) 2012, 2015, 2022 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
26#include "platform.h"
27#include "gnunet_util_lib.h"
29
30#define LOG(kind, ...) GNUNET_log_from (kind, "datacache-heap", __VA_ARGS__)
31
32#define LOG_STRERROR_FILE(kind, op, fn) GNUNET_log_from_strerror_file (kind, \
33 "datacache-heap", \
34 op, fn)
35
36#define NUM_HEAPS 24
37
41struct Plugin
42{
47
52
57};
58
59
86
87
88#define OVERHEAD (sizeof(struct Value) + 64)
89
90
95{
100
104 bool found;
105};
106
107
118put_cb (void *cls,
119 const struct GNUNET_HashCode *key,
120 void *value)
121{
122 struct PutContext *put_ctx = cls;
123 struct Value *val = value;
124
125 if ((val->block.data_size == put_ctx->block->data_size) &&
126 (val->block.type == put_ctx->block->type) &&
127 (0 == memcmp (val->block.data,
128 put_ctx->block->data,
129 put_ctx->block->data_size)))
130 {
131 put_ctx->found = true;
134 put_ctx->block->expiration_time);
135 /* replace old path with new path */
136 GNUNET_free (val->put_path);
137 val->put_path = GNUNET_memdup (put_ctx->block->put_path,
138 put_ctx->block->put_path_length
139 * sizeof (struct GNUNET_DHT_PathElement));
140 val->block.put_path = val->put_path;
145 "Got same value for key %s and type %u (size %u vs %u)\n",
146 GNUNET_h2s (key),
147 (unsigned int) val->block.type,
148 (unsigned int) val->block.data_size,
149 (unsigned int) put_ctx->block->data_size);
150 return GNUNET_NO;
151 }
152 return GNUNET_YES;
153}
154
155
164static ssize_t
166 uint32_t xor_distance,
167 const struct GNUNET_DATACACHE_Block *block)
168{
169 struct Plugin *plugin = cls;
170 struct Value *val;
171 struct PutContext put_ctx = {
172 .block = block,
173 .found = false
174 };
175
177 "Storing %u bytes under key %s with path length %u\n",
178 (unsigned int) block->data_size,
179 GNUNET_h2s (&block->key),
182 &block->key,
183 &put_cb,
184 &put_ctx);
185 if (GNUNET_YES == put_ctx.found)
186 return 0;
187 val = GNUNET_malloc (sizeof(struct Value)
188 + block->data_size);
189 GNUNET_memcpy (&val[1],
190 block->data,
192 val->block = *block;
193 val->block.data = &val[1];
194 if (xor_distance >= NUM_HEAPS)
195 val->distance = NUM_HEAPS - 1;
196 else
197 val->distance = xor_distance;
198 if (0 != block->put_path_length)
199 {
200 val->put_path
203 * sizeof (struct GNUNET_DHT_PathElement));
204 val->block.put_path = val->put_path;
205 }
207 &val->block.key,
208 val,
211 plugin->heaps[val->distance],
212 val,
214 return val->block.data_size + OVERHEAD;
215}
216
217
222{
227 struct Value **values;
228
232 unsigned int cnt;
233
238};
239
240
251get_cb (void *cls,
252 const struct GNUNET_HashCode *key,
253 void *value)
254{
255 struct GetContext *get_ctx = cls;
256 struct Value *val = value;
257
258 if ( (get_ctx->type != val->block.type) &&
259 (GNUNET_BLOCK_TYPE_ANY != get_ctx->type) )
260 {
262 "Result for key %s does not match block type %d\n",
263 GNUNET_h2s (key),
264 get_ctx->type);
265 return GNUNET_OK;
266 }
268 {
270 "Result for key %s is expired\n",
271 GNUNET_h2s (key));
272 return GNUNET_OK;
273 }
275 "Found result for key %s\n",
276 GNUNET_h2s (key));
277 GNUNET_array_append (get_ctx->values,
278 get_ctx->cnt,
279 val);
280 return GNUNET_OK;
281}
282
283
287static int
288cmp_expiration (const void *a,
289 const void *b)
290{
291 const struct Value *va = *(struct Value **) a;
292 const struct Value *vb = *(struct Value **) b;
293
296 return -1;
299 return 1;
300 return 0;
301}
302
303
315static unsigned int
317 const struct GNUNET_HashCode *key,
320 void *iter_cls)
321{
322 struct Plugin *plugin = cls;
323 struct GetContext get_ctx = {
324 .type = type
325 };
326 unsigned int ret;
327
329 key,
330 &get_cb,
331 &get_ctx);
332 /* Hand out the freshest block first: a key may hold several
333 versions of the same (mutable) block, and a requester that stops
334 at the first reply must not be given a nearly expired one. */
335 qsort (get_ctx.values,
336 get_ctx.cnt,
337 sizeof (struct Value *),
339 ret = 0;
340 for (unsigned int i = 0; i < get_ctx.cnt; i++)
341 {
342 ret++;
343 if ( (NULL != iter) &&
344 (GNUNET_OK != iter (iter_cls,
345 &get_ctx.values[i]->block)) )
346 break;
347 }
348 GNUNET_array_grow (get_ctx.values,
349 get_ctx.cnt,
350 0);
351 return ret;
352}
353
354
364{
365 struct Plugin *plugin = cls;
366 struct Value *val;
367
368 for (unsigned int i = 0; i < NUM_HEAPS; i++)
369 {
371 if (NULL != val)
372 break;
373 }
374 if (NULL == val)
375 return GNUNET_SYSERR;
378 &val->block.key,
379 val));
380 plugin->env->delete_notify (plugin->env->cls,
381 &val->block.key,
382 val->block.data_size + OVERHEAD);
383 GNUNET_free (val->put_path);
384 GNUNET_free (val);
385 return GNUNET_OK;
386}
387
388
393{
394 struct Value **values;
395
396 const struct GNUNET_HashCode *key;
397
399
400 unsigned int num_results;
401
402};
403
404
406find_closest (void *cls,
407 const struct GNUNET_HashCode *key,
408 void *value)
409{
410 struct GetClosestContext *gcc = cls;
411 struct Value *val = value;
412 unsigned int j;
413
414 if (1 != GNUNET_CRYPTO_hash_cmp (key,
415 gcc->key))
416 return GNUNET_OK; /* useless */
417 if ( (val->block.type != gcc->type) &&
418 (GNUNET_BLOCK_TYPE_ANY != gcc->type) )
419 return GNUNET_OK; /* useless */
420 j = gcc->num_results;
421 for (unsigned int i = 0; i < gcc->num_results; i++)
422 {
423 if (NULL == gcc->values[i])
424 {
425 j = i;
426 break;
427 }
428 if (1 ==
430 key))
431 {
432 j = i;
433 break;
434 }
435 }
436 if (j == gcc->num_results)
437 return GNUNET_OK;
438 gcc->values[j] = val;
439 return GNUNET_OK;
440}
441
442
457static unsigned int
459 const struct GNUNET_HashCode *key,
461 unsigned int num_results,
463 void *iter_cls)
464{
465 struct Plugin *plugin = cls;
466 struct Value *values[num_results];
467 struct GetClosestContext gcc = {
468 .values = values,
469 .type = type,
470 .num_results = num_results * 2,
471 .key = key
472 };
473
476 &gcc);
477 for (unsigned int i = 0; i < num_results * 2; i++)
478 {
479 if (NULL == values[i])
480 return i;
481 if ( (NULL != iter) &&
482 (GNUNET_SYSERR ==
483 iter (iter_cls,
484 &values[i]->block)) )
485 {
487 "Ending iteration (client error)\n");
488 return i;
489 }
490 }
491 return num_results * 2;
492}
493
494
495void *
497
504void *
506{
509 struct Plugin *plugin;
510
511 plugin = GNUNET_new (struct Plugin);
512 plugin->map = GNUNET_CONTAINER_multihashmap_create (1024, /* FIXME: base on quota! */
513 GNUNET_YES);
514 for (unsigned int i = 0; i < NUM_HEAPS; i++)
517 plugin->env = env;
519 api->cls = plugin;
520 api->get = &heap_plugin_get;
521 api->put = &heap_plugin_put;
522 api->del = &heap_plugin_del;
523 api->get_closest = &heap_plugin_get_closest;
525 _ ("Heap datacache running\n"));
526 return api;
527}
528
529
530void *
532
539void *
541{
543 struct Plugin *plugin = api->cls;
544 struct Value *val;
545
546 for (unsigned int i = 0; i < NUM_HEAPS; i++)
547 {
548 while (NULL != (val = GNUNET_CONTAINER_heap_remove_root (plugin->heaps[i])))
549 {
552 &val->block.key,
553 val));
554 GNUNET_free (val->put_path);
555 GNUNET_free (val);
556 }
558 }
561 GNUNET_free (api);
562 return NULL;
563}
564
565
566/* end of plugin_datacache_heap.c */
struct GNUNET_MQ_Envelope * env
Definition 005.c:1
static int ret
Final status code.
Definition gnunet-arm.c:93
static struct GNUNET_TESTING_PluginFunctions * plugin
Plugin to dynamically load a test case.
struct GNUNET_HashCode key
The key used in the DHT.
static char * value
Value of the record to add/remove.
static uint32_t type
Type string converted to DNS type value.
static struct GNUNET_CONTAINER_MultiHashMap * values
Collection of all values (represented with ValueSet).
API for database backends for the datacache.
GNUNET_BLOCK_Type
WARNING: This header is generated! In order to add DHT block types, you must register them in GANA,...
@ GNUNET_BLOCK_TYPE_ANY
Identifier for any block.
enum GNUNET_GenericReturnValue(* GNUNET_DATACACHE_Iterator)(void *cls, const struct GNUNET_DATACACHE_Block *block)
An iterator over a set of items stored in the datacache.
int GNUNET_CRYPTO_hash_cmp(const struct GNUNET_HashCode *h1, const struct GNUNET_HashCode *h2)
Compare function for HashCodes, producing a total ordering of all hashcodes.
int GNUNET_CONTAINER_multihashmap_iterate(struct GNUNET_CONTAINER_MultiHashMap *map, GNUNET_CONTAINER_MultiHashMapIteratorCallback it, void *it_cls)
Iterate over all entries in the map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap_remove(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, const void *value)
Remove the given key-value pair from the map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap_put(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
void GNUNET_CONTAINER_multihashmap_destroy(struct GNUNET_CONTAINER_MultiHashMap *map)
Destroy a hash map.
struct GNUNET_CONTAINER_MultiHashMap * GNUNET_CONTAINER_multihashmap_create(unsigned int len, int do_not_copy_keys)
Create a multi hash map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap_get_multiple(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, GNUNET_CONTAINER_MultiHashMapIteratorCallback it, void *it_cls)
Iterate over all entries in the map that match a particular key.
@ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE
Allow multiple values with the same key.
void * GNUNET_CONTAINER_heap_remove_root(struct GNUNET_CONTAINER_Heap *heap)
Remove root of the heap.
void GNUNET_CONTAINER_heap_update_cost(struct GNUNET_CONTAINER_HeapNode *node, GNUNET_CONTAINER_HeapCostType new_cost)
Updates the cost of any node in the tree.
struct GNUNET_CONTAINER_HeapNode * GNUNET_CONTAINER_heap_insert(struct GNUNET_CONTAINER_Heap *heap, void *element, GNUNET_CONTAINER_HeapCostType cost)
Inserts a new element into the heap.
struct GNUNET_CONTAINER_Heap * GNUNET_CONTAINER_heap_create(enum GNUNET_CONTAINER_HeapOrder order)
Create a new heap.
void GNUNET_CONTAINER_heap_destroy(struct GNUNET_CONTAINER_Heap *heap)
Destroys the heap.
@ GNUNET_CONTAINER_HEAP_ORDER_MIN
Heap with the minimum cost at the root.
#define GNUNET_log(kind,...)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
const char * GNUNET_h2s(const struct GNUNET_HashCode *hc)
Convert a hash value to a string (for printing debug messages).
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_array_append(arr, len, element)
Append an element to an array (growing the array by one).
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_memdup(buf, size)
Allocate and initialize a block of memory.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_max(struct GNUNET_TIME_Absolute t1, struct GNUNET_TIME_Absolute t2)
Return the maximum of two absolute time values.
Definition time.c:368
bool GNUNET_TIME_absolute_is_past(struct GNUNET_TIME_Absolute abs)
Test if abs is truly in the past (excluding now).
Definition time.c:667
#define _(String)
GNU gettext support macro.
Definition platform.h:179
static int cmp_expiration(const void *a, const void *b)
Sort values by expiration time, latest first.
static enum GNUNET_GenericReturnValue get_cb(void *cls, const struct GNUNET_HashCode *key, void *value)
Function called during GET to find matching blocks.
void * libgnunet_plugin_datacache_heap_init(void *cls)
Entry point for the plugin.
#define OVERHEAD
static enum GNUNET_GenericReturnValue put_cb(void *cls, const struct GNUNET_HashCode *key, void *value)
Function called during PUT to detect if an equivalent block already exists.
static unsigned int heap_plugin_get(void *cls, const struct GNUNET_HashCode *key, enum GNUNET_BLOCK_Type type, GNUNET_DATACACHE_Iterator iter, void *iter_cls)
Iterate over the results for a particular key in the datastore.
static unsigned int heap_plugin_get_closest(void *cls, const struct GNUNET_HashCode *key, enum GNUNET_BLOCK_Type type, unsigned int num_results, GNUNET_DATACACHE_Iterator iter, void *iter_cls)
Iterate over the results that are "close" to a particular key in the datacache.
static enum GNUNET_GenericReturnValue find_closest(void *cls, const struct GNUNET_HashCode *key, void *value)
#define NUM_HEAPS
void * libgnunet_plugin_datacache_heap_done(void *cls)
Exit point from the plugin.
static enum GNUNET_GenericReturnValue heap_plugin_del(void *cls)
Delete the entry with the lowest expiration value from the datacache right now.
static ssize_t heap_plugin_put(void *cls, uint32_t xor_distance, const struct GNUNET_DATACACHE_Block *block)
Store an item in the datastore.
#define LOG(kind,...)
void * cls
Closure for all of the callbacks.
Handle to a node in a heap.
Internal representation of the hash map.
Information about a block stored in the datacache.
const struct GNUNET_DHT_PathElement * put_path
PUT path taken by the block, array of peer identities.
enum GNUNET_BLOCK_Type type
Type of the block.
const void * data
Actual block data.
struct GNUNET_HashCode key
Key of the block.
size_t data_size
Number of bytes in data.
unsigned int put_path_length
Length of the put_path array.
struct GNUNET_TIME_Absolute expiration_time
When does the block expire?
The datastore service will pass a pointer to a struct of this type as the first and only argument to ...
void * cls
Closure to use for callbacks.
struct returned by the initialization function of the plugin
void * cls
Closure to pass to all plugin functions.
A (signed) path tracking a block's flow through the DHT is represented by an array of path elements,...
A 512-bit hashcode.
void * cls
Closure to pass to start_testcase.
uint64_t abs_value_us
The actual value.
Closure for find_closest().
enum GNUNET_BLOCK_Type type
const struct GNUNET_HashCode * key
Closure for get_cb().
enum GNUNET_BLOCK_Type type
Block type requested.
struct Value ** values
Matching values, collected before they are handed to the iterator so that they can be sorted by expir...
unsigned int cnt
Number of entries in values.
Handle for a plugin.
Definition block.c:38
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition block.c:47
struct GNUNET_DATACACHE_PluginEnvironment * env
Our execution environment.
struct GNUNET_CONTAINER_MultiHashMap * map
Our hash map.
struct GNUNET_CONTAINER_Heap * heaps[24]
Heaps sorted by distance.
Closure for put_cb().
const struct GNUNET_DATACACHE_Block * block
Block data.
bool found
Value to set to true if an equivalent block was found.
Entry in the hash map.
struct GNUNET_CONTAINER_HeapNode * hn
Corresponding node in the heap.
struct GNUNET_DATACACHE_Block block
Block data.
struct GNUNET_DHT_PathElement * put_path
Put path as a non-const pointer.
uint32_t distance
How close is the hash to us? Determines which heap we are in!