-remove debug message
[oweals/gnunet.git] / src / datastore / plugin_datastore_heap.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2012 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
21 /**
22  * @file datastore/plugin_datastore_heap.c
23  * @brief heap-based datastore backend; usually we want the datastore
24  *        to be persistent, and storing data in the heap is obviously
25  *        NOT going to be persistent; still, this plugin is useful for
26  *        testing/benchmarking --- but never for production!
27  * @author Christian Grothoff
28  */
29
30 #include "platform.h"
31 #include "gnunet_datastore_plugin.h"
32
33
34 /**
35  * A value that we are storing.
36  */
37 struct Value
38 {
39   /**
40    * Key for the value.
41    */
42   struct GNUNET_HashCode key;
43
44   /**
45    * Pointer to the value's data (allocated at the end of this struct).
46    */
47   const void *data;
48
49   /**
50    * Entry for this value in the 'expire' heap.
51    */
52   struct GNUNET_CONTAINER_HeapNode *expire_heap;
53
54   /**
55    * Entry for this value in the 'replication' heap.
56    */
57   struct GNUNET_CONTAINER_HeapNode *replication_heap;
58
59   /**
60    * Expiration time for this value.
61    */
62   struct GNUNET_TIME_Absolute expiration;
63
64   /**
65    * Offset of this value in the array of the 'struct ZeroAnonByType';
66    * only used if anonymity is zero.
67    */
68   unsigned int zero_anon_offset;
69
70   /**
71    * Number of bytes in 'data'.
72    */
73   uint32_t size;
74
75   /**
76    * Priority of the value.
77    */
78   uint32_t priority;
79
80   /**
81    * Anonymity level for the value.
82    */
83   uint32_t anonymity;
84
85   /**
86    * Replication level for the value.
87    */
88   uint32_t replication;
89
90   /**
91    * Type of 'data'.
92    */
93   enum GNUNET_BLOCK_Type type;
94 };
95
96
97 /**
98  * We organize 0-anonymity values in arrays "by type".
99  */
100 struct ZeroAnonByType
101 {
102   /**
103    * We keep these in a DLL.
104    */
105   struct ZeroAnonByType *next;
106
107   /**
108    * We keep these in a DLL.
109    */
110   struct ZeroAnonByType *prev;
111
112   /**
113    * Array of 0-anonymity items of the given type.
114    */
115   struct Value **array;
116
117   /**
118    * Allocated size of the array.
119    */
120   unsigned int array_size;
121
122   /**
123    * First unused offset in 'array'.
124    */
125   unsigned int array_pos;
126
127   /**
128    * Type of all of the values in 'array'.
129    */
130   enum GNUNET_BLOCK_Type type;
131 };
132
133
134 /**
135  * Context for all functions in this plugin.
136  */
137 struct Plugin
138 {
139   /**
140    * Our execution environment.
141    */
142   struct GNUNET_DATASTORE_PluginEnvironment *env;
143
144   /**
145    * Mapping from keys to 'struct Value's.
146    */
147   struct GNUNET_CONTAINER_MultiHashMap *keyvalue;
148
149   /**
150    * Heap organized by minimum expiration time.
151    */
152   struct GNUNET_CONTAINER_Heap *by_expiration;
153
154   /**
155    * Heap organized by maximum replication value.
156    */
157   struct GNUNET_CONTAINER_Heap *by_replication;
158
159   /**
160    * Head of list of arrays containing zero-anonymity values by type.
161    */
162   struct ZeroAnonByType *zero_head;
163
164   /**
165    * Tail of list of arrays containing zero-anonymity values by type.
166    */
167   struct ZeroAnonByType *zero_tail;
168
169   /**
170    * Size of all values we're storing.
171    */
172   unsigned long long size;
173 };
174
175
176 /**
177  * Get an estimate of how much space the database is
178  * currently using.
179  *
180  * @param cls our "struct Plugin*"
181  * @return number of bytes used on disk
182  */
183 static void
184 heap_plugin_estimate_size (void *cls, unsigned long long *estimate)
185 {
186   struct Plugin *plugin = cls;
187
188   if (NULL != estimate)
189     *estimate = plugin->size;
190 }
191
192
193 /**
194  * Closure for iterator for updating.
195  */
196 struct UpdateContext
197 {
198   /**
199    * Number of bytes in 'data'.
200    */
201   uint32_t size;
202
203   /**
204    * Pointer to the data.
205    */
206   const void *data;
207
208   /**
209    * Priority of the value.
210    */
211   uint32_t priority;
212
213   /**
214    * Replication level for the value.
215    */
216   uint32_t replication;
217
218   /**
219    * Expiration time for this value.
220    */
221   struct GNUNET_TIME_Absolute expiration;
222
223   /**
224    * True if the value was found and updated.
225    */
226   bool updated;
227 };
228
229
230 /**
231  * Update the matching value.
232  *
233  * @param cls the 'struct UpdateContext'
234  * @param key unused
235  * @param val the 'struct Value'
236  * @return GNUNET_YES (continue iteration), GNUNET_NO if value was found
237  */
238 static int
239 update_iterator (void *cls,
240                  const struct GNUNET_HashCode *key,
241                  void *val)
242 {
243   struct UpdateContext *uc = cls;
244   struct Value *value = val;
245
246   if (value->size != uc->size)
247     return GNUNET_YES;
248   if (0 != memcmp (value->data, uc->data, uc->size))
249     return GNUNET_YES;
250   uc->expiration = GNUNET_TIME_absolute_max (value->expiration,
251                                              uc->expiration);
252   if (value->expiration.abs_value_us != uc->expiration.abs_value_us)
253   {
254     value->expiration = uc->expiration;
255     GNUNET_CONTAINER_heap_update_cost (value->expire_heap,
256                                        value->expiration.abs_value_us);
257   }
258   /* Saturating adds, don't overflow */
259   if (value->priority > UINT32_MAX - uc->priority)
260     value->priority = UINT32_MAX;
261   else
262     value->priority += uc->priority;
263   if (value->replication > UINT32_MAX - uc->replication)
264     value->replication = UINT32_MAX;
265   else
266     value->replication += uc->replication;
267   uc->updated = true;
268   return GNUNET_NO;
269 }
270
271
272 /**
273  * Store an item in the datastore.
274  *
275  * @param cls closure
276  * @param key key for the item
277  * @param absent true if the key was not found in the bloom filter
278  * @param size number of bytes in data
279  * @param data content stored
280  * @param type type of the content
281  * @param priority priority of the content
282  * @param anonymity anonymity-level for the content
283  * @param replication replication-level for the content
284  * @param expiration expiration time for the content
285  * @param cont continuation called with success or failure status
286  * @param cont_cls continuation closure
287  */
288 static void
289 heap_plugin_put (void *cls,
290                  const struct GNUNET_HashCode *key,
291                  bool absent,
292                  uint32_t size,
293                  const void *data,
294                  enum GNUNET_BLOCK_Type type,
295                  uint32_t priority,
296                  uint32_t anonymity,
297                  uint32_t replication,
298                  struct GNUNET_TIME_Absolute expiration,
299                  PluginPutCont cont,
300                  void *cont_cls)
301 {
302   struct Plugin *plugin = cls;
303   struct Value *value;
304
305   if (! absent)
306   {
307     struct UpdateContext uc;
308
309     uc.size = size;
310     uc.data = data;
311     uc.priority = priority;
312     uc.replication = replication;
313     uc.expiration = expiration;
314     uc.updated = false;
315     GNUNET_CONTAINER_multihashmap_get_multiple (plugin->keyvalue,
316                                                 key,
317                                                 &update_iterator,
318                                                 &uc);
319     if (uc.updated)
320     {
321       cont (cont_cls, key, size, GNUNET_NO, NULL);
322       return;
323     }
324   }
325   value = GNUNET_malloc (sizeof(struct Value) + size);
326   value->key = *key;
327   value->data = &value[1];
328   value->expire_heap = GNUNET_CONTAINER_heap_insert (plugin->by_expiration,
329                                                      value,
330                                                      expiration.abs_value_us);
331   value->replication_heap = GNUNET_CONTAINER_heap_insert (
332     plugin->by_replication,
333     value,
334     replication);
335   value->expiration = expiration;
336   if (0 == anonymity)
337   {
338     struct ZeroAnonByType *zabt;
339
340     for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next)
341       if (zabt->type == type)
342         break;
343     if (NULL == zabt)
344     {
345       zabt = GNUNET_new (struct ZeroAnonByType);
346       zabt->type = type;
347       GNUNET_CONTAINER_DLL_insert (plugin->zero_head,
348                                    plugin->zero_tail,
349                                    zabt);
350     }
351     if (zabt->array_size == zabt->array_pos)
352     {
353       GNUNET_array_grow (zabt->array,
354                          zabt->array_size,
355                          zabt->array_size * 2 + 4);
356     }
357     value->zero_anon_offset = zabt->array_pos;
358     zabt->array[zabt->array_pos++] = value;
359   }
360   value->size = size;
361   value->priority = priority;
362   value->anonymity = anonymity;
363   value->replication = replication;
364   value->type = type;
365   GNUNET_memcpy (&value[1], data, size);
366   GNUNET_CONTAINER_multihashmap_put (plugin->keyvalue,
367                                      &value->key,
368                                      value,
369                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
370   plugin->size += size;
371   cont (cont_cls, key, size, GNUNET_OK, NULL);
372 }
373
374
375 /**
376  * Delete the given value, removing it from the plugin's data
377  * structures.
378  *
379  * @param plugin the plugin
380  * @param value value to delete
381  */
382 static void
383 delete_value (struct Plugin *plugin,
384               struct Value *value)
385 {
386   GNUNET_assert (GNUNET_YES ==
387                  GNUNET_CONTAINER_multihashmap_remove (plugin->keyvalue,
388                                                        &value->key,
389                                                        value));
390   GNUNET_assert (value == GNUNET_CONTAINER_heap_remove_node (
391                    value->expire_heap));
392   GNUNET_assert (value == GNUNET_CONTAINER_heap_remove_node (
393                    value->replication_heap));
394   if (0 == value->anonymity)
395   {
396     struct ZeroAnonByType *zabt;
397
398     for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next)
399       if (zabt->type == value->type)
400         break;
401     GNUNET_assert (NULL != zabt);
402     zabt->array[value->zero_anon_offset] = zabt->array[--zabt->array_pos];
403     zabt->array[value->zero_anon_offset]->zero_anon_offset =
404       value->zero_anon_offset;
405     if (0 == zabt->array_pos)
406     {
407       GNUNET_array_grow (zabt->array,
408                          zabt->array_size,
409                          0);
410       GNUNET_CONTAINER_DLL_remove (plugin->zero_head,
411                                    plugin->zero_tail,
412                                    zabt);
413       GNUNET_free (zabt);
414     }
415   }
416   plugin->size -= value->size;
417   GNUNET_free (value);
418 }
419
420
421 /**
422  * Closure for iterator called during 'get_key'.
423  */
424 struct GetContext
425 {
426   /**
427    * Lowest uid to consider.
428    */
429   uint64_t next_uid;
430
431   /**
432    * Value with lowest uid >= next_uid found so far.
433    */
434   struct Value *value;
435
436   /**
437    * Requested type.
438    */
439   enum GNUNET_BLOCK_Type type;
440
441   /**
442    * If true, return a random value
443    */
444   bool random;
445 };
446
447
448 /**
449  * Obtain the matching value with the lowest uid >= next_uid.
450  *
451  * @param cls the 'struct GetContext'
452  * @param key unused
453  * @param val the 'struct Value'
454  * @return GNUNET_YES (continue iteration), GNUNET_NO if result was found
455  */
456 static int
457 get_iterator (void *cls,
458               const struct GNUNET_HashCode *key,
459               void *val)
460 {
461   struct GetContext *gc = cls;
462   struct Value *value = val;
463
464   if ((gc->type != GNUNET_BLOCK_TYPE_ANY) &&
465       (gc->type != value->type))
466     return GNUNET_OK;
467   if (gc->random)
468   {
469     gc->value = value;
470     return GNUNET_NO;
471   }
472   if ((uint64_t) (intptr_t) value < gc->next_uid)
473     return GNUNET_OK;
474   if ((NULL != gc->value) &&
475       (value > gc->value))
476     return GNUNET_OK;
477   gc->value = value;
478   return GNUNET_OK;
479 }
480
481
482 /**
483  * Get one of the results for a particular key in the datastore.
484  *
485  * @param cls closure
486  * @param next_uid return the result with lowest uid >= next_uid
487  * @param random if true, return a random result instead of using next_uid
488  * @param key maybe NULL (to match all entries)
489  * @param type entries of which type are relevant?
490  *     Use 0 for any type.
491  * @param proc function to call on the matching value;
492  *        will be called with NULL if nothing matches
493  * @param proc_cls closure for @a proc
494  */
495 static void
496 heap_plugin_get_key (void *cls,
497                      uint64_t next_uid,
498                      bool random,
499                      const struct GNUNET_HashCode *key,
500                      enum GNUNET_BLOCK_Type type,
501                      PluginDatumProcessor proc,
502                      void *proc_cls)
503 {
504   struct Plugin *plugin = cls;
505   struct GetContext gc;
506
507   gc.value = NULL;
508   gc.next_uid = next_uid;
509   gc.random = random;
510   gc.type = type;
511   if (NULL == key)
512   {
513     GNUNET_CONTAINER_multihashmap_iterate (plugin->keyvalue,
514                                            &get_iterator,
515                                            &gc);
516   }
517   else
518   {
519     GNUNET_CONTAINER_multihashmap_get_multiple (plugin->keyvalue,
520                                                 key,
521                                                 &get_iterator,
522                                                 &gc);
523   }
524   if (NULL == gc.value)
525   {
526     proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
527     return;
528   }
529   GNUNET_assert (GNUNET_OK ==
530                  proc (proc_cls,
531                        &gc.value->key,
532                        gc.value->size,
533                        &gc.value[1],
534                        gc.value->type,
535                        gc.value->priority,
536                        gc.value->anonymity,
537                        gc.value->replication,
538                        gc.value->expiration,
539                        (uint64_t) (intptr_t) gc.value));
540 }
541
542
543 /**
544  * Get a random item for replication.  Returns a single, not expired,
545  * random item from those with the highest replication counters.  The
546  * item's replication counter is decremented by one IF it was positive
547  * before.  Call 'proc' with all values ZERO or NULL if the datastore
548  * is empty.
549  *
550  * @param cls closure
551  * @param proc function to call the value (once only).
552  * @param proc_cls closure for proc
553  */
554 static void
555 heap_plugin_get_replication (void *cls,
556                              PluginDatumProcessor proc,
557                              void *proc_cls)
558 {
559   struct Plugin *plugin = cls;
560   struct Value *value;
561
562   value = GNUNET_CONTAINER_heap_remove_root (plugin->by_replication);
563   if (NULL == value)
564   {
565     proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
566     return;
567   }
568   if (value->replication > 0)
569   {
570     value->replication--;
571     value->replication_heap = GNUNET_CONTAINER_heap_insert (
572       plugin->by_replication,
573       value,
574       value->replication);
575   }
576   else
577   {
578     /* need a better way to pick a random item, replication level is always 0 */
579     value->replication_heap = GNUNET_CONTAINER_heap_insert (
580       plugin->by_replication,
581       value,
582       value->replication);
583     value = GNUNET_CONTAINER_heap_walk_get_next (plugin->by_replication);
584   }
585   GNUNET_assert (GNUNET_OK ==
586                  proc (proc_cls,
587                        &value->key,
588                        value->size,
589                        &value[1],
590                        value->type,
591                        value->priority,
592                        value->anonymity,
593                        value->replication,
594                        value->expiration,
595                        (uint64_t) (intptr_t) value));
596 }
597
598
599 /**
600  * Get a random item for expiration.  Call 'proc' with all values ZERO
601  * or NULL if the datastore is empty.
602  *
603  * @param cls closure
604  * @param proc function to call the value (once only).
605  * @param proc_cls closure for proc
606  */
607 static void
608 heap_plugin_get_expiration (void *cls, PluginDatumProcessor proc,
609                             void *proc_cls)
610 {
611   struct Plugin *plugin = cls;
612   struct Value *value;
613
614   value = GNUNET_CONTAINER_heap_peek (plugin->by_expiration);
615   if (NULL == value)
616   {
617     proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
618     return;
619   }
620   if (GNUNET_NO ==
621       proc (proc_cls,
622             &value->key,
623             value->size,
624             &value[1],
625             value->type,
626             value->priority,
627             value->anonymity,
628             value->replication,
629             value->expiration,
630             (uint64_t) (intptr_t) value))
631     delete_value (plugin, value);
632 }
633
634
635 /**
636  * Call the given processor on an item with zero anonymity.
637  *
638  * @param cls our "struct Plugin*"
639  * @param next_uid return the result with lowest uid >= next_uid
640  * @param type entries of which type should be considered?
641  *        Must not be zero (ANY).
642  * @param proc function to call on each matching value;
643  *        will be called with NULL if no value matches
644  * @param proc_cls closure for proc
645  */
646 static void
647 heap_plugin_get_zero_anonymity (void *cls, uint64_t next_uid,
648                                 enum GNUNET_BLOCK_Type type,
649                                 PluginDatumProcessor proc, void *proc_cls)
650 {
651   struct Plugin *plugin = cls;
652   struct ZeroAnonByType *zabt;
653   struct Value *value = NULL;
654
655   for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next)
656   {
657     if ((type != GNUNET_BLOCK_TYPE_ANY) &&
658         (type != zabt->type))
659       continue;
660     for (int i = 0; i < zabt->array_pos; ++i)
661     {
662       if ((uint64_t) (intptr_t) zabt->array[i] < next_uid)
663         continue;
664       if ((NULL != value) &&
665           (zabt->array[i] > value))
666         continue;
667       value = zabt->array[i];
668     }
669   }
670   if (NULL == value)
671   {
672     proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
673     return;
674   }
675   GNUNET_assert (GNUNET_OK ==
676                  proc (proc_cls,
677                        &value->key,
678                        value->size,
679                        &value[1],
680                        value->type,
681                        value->priority,
682                        value->anonymity,
683                        value->replication,
684                        value->expiration,
685                        (uint64_t) (intptr_t) value));
686 }
687
688
689 /**
690  * Drop database.
691  */
692 static void
693 heap_plugin_drop (void *cls)
694 {
695   /* nothing needs to be done */
696 }
697
698
699 /**
700  * Closure for the 'return_value' function.
701  */
702 struct GetAllContext
703 {
704   /**
705    * Function to call.
706    */
707   PluginKeyProcessor proc;
708
709   /**
710    * Closure for 'proc'.
711    */
712   void *proc_cls;
713 };
714
715
716 /**
717  * Callback invoked to call callback on each value.
718  *
719  * @param cls the plugin
720  * @param key unused
721  * @param val the value
722  * @return GNUNET_OK (continue to iterate)
723  */
724 static int
725 return_value (void *cls,
726               const struct GNUNET_HashCode *key,
727               void *val)
728 {
729   struct GetAllContext *gac = cls;
730
731   gac->proc (gac->proc_cls,
732              key,
733              1);
734   return GNUNET_OK;
735 }
736
737
738 /**
739  * Get all of the keys in the datastore.
740  *
741  * @param cls closure
742  * @param proc function to call on each key
743  * @param proc_cls closure for proc
744  */
745 static void
746 heap_get_keys (void *cls,
747                PluginKeyProcessor proc,
748                void *proc_cls)
749 {
750   struct Plugin *plugin = cls;
751   struct GetAllContext gac;
752
753   gac.proc = proc;
754   gac.proc_cls = proc_cls;
755   GNUNET_CONTAINER_multihashmap_iterate (plugin->keyvalue,
756                                          &return_value,
757                                          &gac);
758   proc (proc_cls, NULL, 0);
759 }
760
761
762 /**
763  * Closure for iterator called during 'remove_key'.
764  */
765 struct RemoveContext
766 {
767   /**
768    * Value found.
769    */
770   struct Value *value;
771
772   /**
773    * Size of data.
774    */
775   uint32_t size;
776
777   /**
778    * Data to remove.
779    */
780   const void *data;
781 };
782
783
784 /**
785  * Obtain the matching value with the lowest uid >= next_uid.
786  *
787  * @param cls the 'struct GetContext'
788  * @param key unused
789  * @param val the 'struct Value'
790  * @return GNUNET_YES (continue iteration), GNUNET_NO if result was found
791  */
792 static int
793 remove_iterator (void *cls,
794                  const struct GNUNET_HashCode *key,
795                  void *val)
796 {
797   struct RemoveContext *rc = cls;
798   struct Value *value = val;
799
800   if (value->size != rc->size)
801     return GNUNET_YES;
802   if (0 != memcmp (value->data, rc->data, rc->size))
803     return GNUNET_YES;
804   rc->value = value;
805   return GNUNET_NO;
806 }
807
808
809 /**
810  * Remove a particular key in the datastore.
811  *
812  * @param cls closure
813  * @param key key for the content
814  * @param size number of bytes in data
815  * @param data content stored
816  * @param cont continuation called with success or failure status
817  * @param cont_cls continuation closure for @a cont
818  */
819 static void
820 heap_plugin_remove_key (void *cls,
821                         const struct GNUNET_HashCode *key,
822                         uint32_t size,
823                         const void *data,
824                         PluginRemoveCont cont,
825                         void *cont_cls)
826 {
827   struct Plugin *plugin = cls;
828   struct RemoveContext rc;
829
830   rc.value = NULL;
831   rc.size = size;
832   rc.data = data;
833   GNUNET_CONTAINER_multihashmap_get_multiple (plugin->keyvalue,
834                                               key,
835                                               &remove_iterator,
836                                               &rc);
837   if (NULL == rc.value)
838   {
839     cont (cont_cls,
840           key,
841           size,
842           GNUNET_NO,
843           NULL);
844     return;
845   }
846   delete_value (plugin,
847                 rc.value);
848   cont (cont_cls,
849         key,
850         size,
851         GNUNET_OK,
852         NULL);
853 }
854
855
856 /**
857  * Entry point for the plugin.
858  *
859  * @param cls the "struct GNUNET_DATASTORE_PluginEnvironment*"
860  * @return our "struct Plugin*"
861  */
862 void *
863 libgnunet_plugin_datastore_heap_init (void *cls)
864 {
865   struct GNUNET_DATASTORE_PluginEnvironment *env = cls;
866   struct GNUNET_DATASTORE_PluginFunctions *api;
867   struct Plugin *plugin;
868   unsigned long long esize;
869
870   if (GNUNET_OK !=
871       GNUNET_CONFIGURATION_get_value_number (env->cfg,
872                                              "datastore-heap",
873                                              "HASHMAPSIZE",
874                                              &esize))
875     esize = 128 * 1024;
876   plugin = GNUNET_new (struct Plugin);
877   plugin->env = env;
878   plugin->keyvalue = GNUNET_CONTAINER_multihashmap_create (esize, GNUNET_YES);
879   plugin->by_expiration = GNUNET_CONTAINER_heap_create (
880     GNUNET_CONTAINER_HEAP_ORDER_MIN);
881   plugin->by_replication = GNUNET_CONTAINER_heap_create (
882     GNUNET_CONTAINER_HEAP_ORDER_MAX);
883   api = GNUNET_new (struct GNUNET_DATASTORE_PluginFunctions);
884   api->cls = plugin;
885   api->estimate_size = &heap_plugin_estimate_size;
886   api->put = &heap_plugin_put;
887   api->get_key = &heap_plugin_get_key;
888   api->get_replication = &heap_plugin_get_replication;
889   api->get_expiration = &heap_plugin_get_expiration;
890   api->get_zero_anonymity = &heap_plugin_get_zero_anonymity;
891   api->drop = &heap_plugin_drop;
892   api->get_keys = &heap_get_keys;
893   api->remove_key = &heap_plugin_remove_key;
894   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "heap",
895                    _ ("Heap database running\n"));
896   return api;
897 }
898
899
900 /**
901  * Callback invoked to free all value.
902  *
903  * @param cls the plugin
904  * @param key unused
905  * @param val the value
906  * @return GNUNET_OK (continue to iterate)
907  */
908 static int
909 free_value (void *cls,
910             const struct GNUNET_HashCode *key,
911             void *val)
912 {
913   struct Plugin *plugin = cls;
914   struct Value *value = val;
915
916   delete_value (plugin, value);
917   return GNUNET_OK;
918 }
919
920
921 /**
922  * Exit point from the plugin.
923  * @param cls our "struct Plugin*"
924  * @return always NULL
925  */
926 void *
927 libgnunet_plugin_datastore_heap_done (void *cls)
928 {
929   struct GNUNET_DATASTORE_PluginFunctions *api = cls;
930   struct Plugin *plugin = api->cls;
931
932   GNUNET_CONTAINER_multihashmap_iterate (plugin->keyvalue,
933                                          &free_value,
934                                          plugin);
935   GNUNET_CONTAINER_multihashmap_destroy (plugin->keyvalue);
936   GNUNET_CONTAINER_heap_destroy (plugin->by_expiration);
937   GNUNET_CONTAINER_heap_destroy (plugin->by_replication);
938   GNUNET_free (plugin);
939   GNUNET_free (api);
940   return NULL;
941 }
942
943
944 /* end of plugin_datastore_heap.c */