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