diff options
author | David Barksdale <amatus@amat.us> | 2017-03-19 15:55:32 -0500 |
---|---|---|
committer | David Barksdale <amatus@amat.us> | 2017-03-19 17:38:36 -0500 |
commit | 2dde0202c5590eeb051c1346f2b66293d83b87ce (patch) | |
tree | 7997191912ee4c70959934d6c9783a0c9f450fec /src/datastore/plugin_datastore_heap.c | |
parent | d17d833dfd93a81f3540d472d1be4dfb7e9cbd03 (diff) | |
download | gnunet-2dde0202c5590eeb051c1346f2b66293d83b87ce.tar.gz gnunet-2dde0202c5590eeb051c1346f2b66293d83b87ce.zip |
[datastore] Fix #3743
This change adds support for key == NULL to the datastore plugins
and replaces the offset argument with a next_uid and random arguments to
increase performance in the key == NULL case.
With the offset argument a datastore plugin would have to count all
matching keys before fetching the key at the right offset, which would
iterate over the entire database in the case of key == NULL.
The offset argument was used in two ways: to iterate over a set of
matching values and to start iteration at a random matching value. The new API
seperates these into two arguments: if random is true it will return a
random matching value, otherwise next_uid can be set to uid + 1 to return the
next matching value.
The random argument was not added to get_zero_anonymity. This function
is used to periodically insert zero anonymity values into the DHT. I
don't think it's necessary to randomize this.
Diffstat (limited to 'src/datastore/plugin_datastore_heap.c')
-rw-r--r-- | src/datastore/plugin_datastore_heap.c | 207 |
1 files changed, 73 insertions, 134 deletions
diff --git a/src/datastore/plugin_datastore_heap.c b/src/datastore/plugin_datastore_heap.c index 199c03a50..e15cacb5b 100644 --- a/src/datastore/plugin_datastore_heap.c +++ b/src/datastore/plugin_datastore_heap.c | |||
@@ -323,19 +323,19 @@ struct GetContext | |||
323 | { | 323 | { |
324 | 324 | ||
325 | /** | 325 | /** |
326 | * Desired result offset / number of results. | 326 | * Lowest uid to consider. |
327 | */ | 327 | */ |
328 | uint64_t offset; | 328 | uint64_t next_uid; |
329 | 329 | ||
330 | /** | 330 | /** |
331 | * The plugin. | 331 | * Value with lowest uid >= next_uid found so far. |
332 | */ | 332 | */ |
333 | struct Plugin *plugin; | 333 | struct Value *value; |
334 | 334 | ||
335 | /** | 335 | /** |
336 | * Requested value hash. | 336 | * Requested value hash. |
337 | */ | 337 | */ |
338 | const struct GNUNET_HashCode * vhash; | 338 | const struct GNUNET_HashCode *vhash; |
339 | 339 | ||
340 | /** | 340 | /** |
341 | * Requested type. | 341 | * Requested type. |
@@ -343,68 +343,15 @@ struct GetContext | |||
343 | enum GNUNET_BLOCK_Type type; | 343 | enum GNUNET_BLOCK_Type type; |
344 | 344 | ||
345 | /** | 345 | /** |
346 | * Function to call with the result. | 346 | * If true, return a random value |
347 | */ | 347 | */ |
348 | PluginDatumProcessor proc; | 348 | bool random; |
349 | 349 | ||
350 | /** | ||
351 | * Closure for 'proc'. | ||
352 | */ | ||
353 | void *proc_cls; | ||
354 | }; | 350 | }; |
355 | 351 | ||
356 | 352 | ||
357 | /** | 353 | /** |
358 | * Test if a value matches the specification from the 'get' context | 354 | * Obtain the matching value with the lowest uid >= next_uid. |
359 | * | ||
360 | * @param gc query | ||
361 | * @param value the value to check against the query | ||
362 | * @return GNUNET_YES if the value matches | ||
363 | */ | ||
364 | static int | ||
365 | match (const struct GetContext *gc, | ||
366 | struct Value *value) | ||
367 | { | ||
368 | struct GNUNET_HashCode vh; | ||
369 | |||
370 | if ( (gc->type != GNUNET_BLOCK_TYPE_ANY) && | ||
371 | (gc->type != value->type) ) | ||
372 | return GNUNET_NO; | ||
373 | if (NULL != gc->vhash) | ||
374 | { | ||
375 | GNUNET_CRYPTO_hash (&value[1], value->size, &vh); | ||
376 | if (0 != memcmp (&vh, gc->vhash, sizeof (struct GNUNET_HashCode))) | ||
377 | return GNUNET_NO; | ||
378 | } | ||
379 | return GNUNET_YES; | ||
380 | } | ||
381 | |||
382 | |||
383 | /** | ||
384 | * Count number of matching values. | ||
385 | * | ||
386 | * @param cls the 'struct GetContext' | ||
387 | * @param key unused | ||
388 | * @param val the 'struct Value' | ||
389 | * @return GNUNET_YES (continue iteration) | ||
390 | */ | ||
391 | static int | ||
392 | count_iterator (void *cls, | ||
393 | const struct GNUNET_HashCode *key, | ||
394 | void *val) | ||
395 | { | ||
396 | struct GetContext *gc = cls; | ||
397 | struct Value *value = val; | ||
398 | |||
399 | if (GNUNET_NO == match (gc, value)) | ||
400 | return GNUNET_OK; | ||
401 | gc->offset++; | ||
402 | return GNUNET_OK; | ||
403 | } | ||
404 | |||
405 | |||
406 | /** | ||
407 | * Obtain matching value at 'offset'. | ||
408 | * | 355 | * |
409 | * @param cls the 'struct GetContext' | 356 | * @param cls the 'struct GetContext' |
410 | * @param key unused | 357 | * @param key unused |
@@ -418,23 +365,29 @@ get_iterator (void *cls, | |||
418 | { | 365 | { |
419 | struct GetContext *gc = cls; | 366 | struct GetContext *gc = cls; |
420 | struct Value *value = val; | 367 | struct Value *value = val; |
368 | struct GNUNET_HashCode vh; | ||
421 | 369 | ||
422 | if (GNUNET_NO == match (gc, value)) | 370 | if ( (gc->type != GNUNET_BLOCK_TYPE_ANY) && |
371 | (gc->type != value->type) ) | ||
423 | return GNUNET_OK; | 372 | return GNUNET_OK; |
424 | if (0 != gc->offset--) | 373 | if (NULL != gc->vhash) |
374 | { | ||
375 | GNUNET_CRYPTO_hash (&value[1], value->size, &vh); | ||
376 | if (0 != memcmp (&vh, gc->vhash, sizeof (struct GNUNET_HashCode))) | ||
377 | return GNUNET_OK; | ||
378 | } | ||
379 | if (gc->random) | ||
380 | { | ||
381 | gc->value = value; | ||
382 | return GNUNET_NO; | ||
383 | } | ||
384 | if ( (uint64_t) (intptr_t) value < gc->next_uid) | ||
425 | return GNUNET_OK; | 385 | return GNUNET_OK; |
426 | if (GNUNET_NO == | 386 | if ( (NULL != gc->value) && |
427 | gc->proc (gc->proc_cls, | 387 | (value > gc->value) ) |
428 | key, | 388 | return GNUNET_OK; |
429 | value->size, | 389 | gc->value = value; |
430 | &value[1], | 390 | return GNUNET_OK; |
431 | value->type, | ||
432 | value->priority, | ||
433 | value->anonymity, | ||
434 | value->expiration, | ||
435 | (uint64_t) (long) value)) | ||
436 | delete_value (gc->plugin, value); | ||
437 | return GNUNET_NO; | ||
438 | } | 391 | } |
439 | 392 | ||
440 | 393 | ||
@@ -442,8 +395,8 @@ get_iterator (void *cls, | |||
442 | * Get one of the results for a particular key in the datastore. | 395 | * Get one of the results for a particular key in the datastore. |
443 | * | 396 | * |
444 | * @param cls closure | 397 | * @param cls closure |
445 | * @param offset offset of the result (modulo num-results); | 398 | * @param next_uid return the result with lowest uid >= next_uid |
446 | * specific ordering does not matter for the offset | 399 | * @param random if true, return a random result instead of using next_uid |
447 | * @param key maybe NULL (to match all entries) | 400 | * @param key maybe NULL (to match all entries) |
448 | * @param vhash hash of the value, maybe NULL (to | 401 | * @param vhash hash of the value, maybe NULL (to |
449 | * match all values that have the right key). | 402 | * match all values that have the right key). |
@@ -457,7 +410,7 @@ get_iterator (void *cls, | |||
457 | * @param proc_cls closure for proc | 410 | * @param proc_cls closure for proc |
458 | */ | 411 | */ |
459 | static void | 412 | static void |
460 | heap_plugin_get_key (void *cls, uint64_t offset, | 413 | heap_plugin_get_key (void *cls, uint64_t next_uid, bool random, |
461 | const struct GNUNET_HashCode *key, | 414 | const struct GNUNET_HashCode *key, |
462 | const struct GNUNET_HashCode *vhash, | 415 | const struct GNUNET_HashCode *vhash, |
463 | enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, | 416 | enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, |
@@ -466,25 +419,14 @@ heap_plugin_get_key (void *cls, uint64_t offset, | |||
466 | struct Plugin *plugin = cls; | 419 | struct Plugin *plugin = cls; |
467 | struct GetContext gc; | 420 | struct GetContext gc; |
468 | 421 | ||
469 | gc.plugin = plugin; | 422 | gc.value = NULL; |
470 | gc.offset = 0; | 423 | gc.next_uid = next_uid; |
424 | gc.random = random; | ||
471 | gc.vhash = vhash; | 425 | gc.vhash = vhash; |
472 | gc.type = type; | 426 | gc.type = type; |
473 | gc.proc = proc; | ||
474 | gc.proc_cls = proc_cls; | ||
475 | if (NULL == key) | 427 | if (NULL == key) |
476 | { | 428 | { |
477 | GNUNET_CONTAINER_multihashmap_iterate (plugin->keyvalue, | 429 | GNUNET_CONTAINER_multihashmap_iterate (plugin->keyvalue, |
478 | &count_iterator, | ||
479 | &gc); | ||
480 | if (0 == gc.offset) | ||
481 | { | ||
482 | proc (proc_cls, | ||
483 | NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | ||
484 | return; | ||
485 | } | ||
486 | gc.offset = offset % gc.offset; | ||
487 | GNUNET_CONTAINER_multihashmap_iterate (plugin->keyvalue, | ||
488 | &get_iterator, | 430 | &get_iterator, |
489 | &gc); | 431 | &gc); |
490 | } | 432 | } |
@@ -492,20 +434,27 @@ heap_plugin_get_key (void *cls, uint64_t offset, | |||
492 | { | 434 | { |
493 | GNUNET_CONTAINER_multihashmap_get_multiple (plugin->keyvalue, | 435 | GNUNET_CONTAINER_multihashmap_get_multiple (plugin->keyvalue, |
494 | key, | 436 | key, |
495 | &count_iterator, | ||
496 | &gc); | ||
497 | if (0 == gc.offset) | ||
498 | { | ||
499 | proc (proc_cls, | ||
500 | NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | ||
501 | return; | ||
502 | } | ||
503 | gc.offset = offset % gc.offset; | ||
504 | GNUNET_CONTAINER_multihashmap_get_multiple (plugin->keyvalue, | ||
505 | key, | ||
506 | &get_iterator, | 437 | &get_iterator, |
507 | &gc); | 438 | &gc); |
508 | } | 439 | } |
440 | if (NULL == gc.value) | ||
441 | { | ||
442 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | ||
443 | return; | ||
444 | } | ||
445 | if (GNUNET_NO == | ||
446 | proc (proc_cls, | ||
447 | &gc.value->key, | ||
448 | gc.value->size, | ||
449 | &gc.value[1], | ||
450 | gc.value->type, | ||
451 | gc.value->priority, | ||
452 | gc.value->anonymity, | ||
453 | gc.value->expiration, | ||
454 | (uint64_t) (intptr_t) gc.value)) | ||
455 | { | ||
456 | delete_value (plugin, gc.value); | ||
457 | } | ||
509 | } | 458 | } |
510 | 459 | ||
511 | 460 | ||
@@ -559,7 +508,7 @@ heap_plugin_get_replication (void *cls, | |||
559 | value->priority, | 508 | value->priority, |
560 | value->anonymity, | 509 | value->anonymity, |
561 | value->expiration, | 510 | value->expiration, |
562 | (uint64_t) (long) value)) | 511 | (uint64_t) (intptr_t) value)) |
563 | delete_value (plugin, value); | 512 | delete_value (plugin, value); |
564 | } | 513 | } |
565 | 514 | ||
@@ -595,7 +544,7 @@ heap_plugin_get_expiration (void *cls, PluginDatumProcessor proc, | |||
595 | value->priority, | 544 | value->priority, |
596 | value->anonymity, | 545 | value->anonymity, |
597 | value->expiration, | 546 | value->expiration, |
598 | (uint64_t) (long) value)) | 547 | (uint64_t) (intptr_t) value)) |
599 | delete_value (plugin, value); | 548 | delete_value (plugin, value); |
600 | } | 549 | } |
601 | 550 | ||
@@ -628,7 +577,7 @@ heap_plugin_update (void *cls, | |||
628 | { | 577 | { |
629 | struct Value *value; | 578 | struct Value *value; |
630 | 579 | ||
631 | value = (struct Value*) (long) uid; | 580 | value = (struct Value*) (intptr_t) uid; |
632 | GNUNET_assert (NULL != value); | 581 | GNUNET_assert (NULL != value); |
633 | if (value->expiration.abs_value_us != expire.abs_value_us) | 582 | if (value->expiration.abs_value_us != expire.abs_value_us) |
634 | { | 583 | { |
@@ -649,53 +598,43 @@ heap_plugin_update (void *cls, | |||
649 | * Call the given processor on an item with zero anonymity. | 598 | * Call the given processor on an item with zero anonymity. |
650 | * | 599 | * |
651 | * @param cls our "struct Plugin*" | 600 | * @param cls our "struct Plugin*" |
652 | * @param offset offset of the result (modulo num-results); | 601 | * @param next_uid return the result with lowest uid >= next_uid |
653 | * specific ordering does not matter for the offset | ||
654 | * @param type entries of which type should be considered? | 602 | * @param type entries of which type should be considered? |
655 | * Use 0 for any type. | 603 | * Must not be zero (ANY). |
656 | * @param proc function to call on each matching value; | 604 | * @param proc function to call on each matching value; |
657 | * will be called with NULL if no value matches | 605 | * will be called with NULL if no value matches |
658 | * @param proc_cls closure for proc | 606 | * @param proc_cls closure for proc |
659 | */ | 607 | */ |
660 | static void | 608 | static void |
661 | heap_plugin_get_zero_anonymity (void *cls, uint64_t offset, | 609 | heap_plugin_get_zero_anonymity (void *cls, uint64_t next_uid, |
662 | enum GNUNET_BLOCK_Type type, | 610 | enum GNUNET_BLOCK_Type type, |
663 | PluginDatumProcessor proc, void *proc_cls) | 611 | PluginDatumProcessor proc, void *proc_cls) |
664 | { | 612 | { |
665 | struct Plugin *plugin = cls; | 613 | struct Plugin *plugin = cls; |
666 | struct ZeroAnonByType *zabt; | 614 | struct ZeroAnonByType *zabt; |
667 | struct Value *value; | 615 | struct Value *value = NULL; |
668 | uint64_t count; | ||
669 | 616 | ||
670 | count = 0; | ||
671 | for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next) | 617 | for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next) |
672 | { | 618 | { |
673 | if ( (type != GNUNET_BLOCK_TYPE_ANY) && | 619 | if ( (type != GNUNET_BLOCK_TYPE_ANY) && |
674 | (type != zabt->type) ) | 620 | (type != zabt->type) ) |
675 | continue; | 621 | continue; |
676 | count += zabt->array_pos; | 622 | for (int i = 0; i < zabt->array_pos; ++i) |
623 | { | ||
624 | if ( (uint64_t) (intptr_t) zabt->array[i] < next_uid) | ||
625 | continue; | ||
626 | if ( (NULL != value) && | ||
627 | (zabt->array[i] > value) ) | ||
628 | continue; | ||
629 | value = zabt->array[i]; | ||
630 | } | ||
677 | } | 631 | } |
678 | if (0 == count) | 632 | if (NULL == value) |
679 | { | 633 | { |
680 | proc (proc_cls, | 634 | proc (proc_cls, |
681 | NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | 635 | NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); |
682 | return; | 636 | return; |
683 | } | 637 | } |
684 | offset = offset % count; | ||
685 | for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next) | ||
686 | { | ||
687 | if ( (type != GNUNET_BLOCK_TYPE_ANY) && | ||
688 | (type != zabt->type) ) | ||
689 | continue; | ||
690 | if (offset >= zabt->array_pos) | ||
691 | { | ||
692 | offset -= zabt->array_pos; | ||
693 | continue; | ||
694 | } | ||
695 | break; | ||
696 | } | ||
697 | GNUNET_assert (NULL != zabt); | ||
698 | value = zabt->array[offset]; | ||
699 | if (GNUNET_NO == | 638 | if (GNUNET_NO == |
700 | proc (proc_cls, | 639 | proc (proc_cls, |
701 | &value->key, | 640 | &value->key, |
@@ -705,7 +644,7 @@ heap_plugin_get_zero_anonymity (void *cls, uint64_t offset, | |||
705 | value->priority, | 644 | value->priority, |
706 | value->anonymity, | 645 | value->anonymity, |
707 | value->expiration, | 646 | value->expiration, |
708 | (uint64_t) (long) value)) | 647 | (uint64_t) (intptr_t) value)) |
709 | delete_value (plugin, value); | 648 | delete_value (plugin, value); |
710 | } | 649 | } |
711 | 650 | ||