src: for every AGPL3.0 file, add SPDX identifier.
[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   /**
41    * Key for the value.
42    */
43   struct GNUNET_HashCode key;
44
45   /**
46    * Pointer to the value's data (allocated at the end of this struct).
47    */
48   const void *data;
49
50   /**
51    * Entry for this value in the 'expire' heap.
52    */
53   struct GNUNET_CONTAINER_HeapNode *expire_heap;
54
55   /**
56    * Entry for this value in the 'replication' heap.
57    */
58   struct GNUNET_CONTAINER_HeapNode *replication_heap;
59
60   /**
61    * Expiration time for this value.
62    */
63   struct GNUNET_TIME_Absolute expiration;
64
65   /**
66    * Offset of this value in the array of the 'struct ZeroAnonByType';
67    * only used if anonymity is zero.
68    */
69   unsigned int zero_anon_offset;
70
71   /**
72    * Number of bytes in 'data'.
73    */
74   uint32_t size;
75
76   /**
77    * Priority of the value.
78    */
79   uint32_t priority;
80
81   /**
82    * Anonymity level for the value.
83    */
84   uint32_t anonymity;
85
86   /**
87    * Replication level for the value.
88    */
89   uint32_t replication;
90
91   /**
92    * Type of 'data'.
93    */
94   enum GNUNET_BLOCK_Type type;
95
96 };
97
98
99 /**
100  * We organize 0-anonymity values in arrays "by type".
101  */
102 struct ZeroAnonByType
103 {
104
105   /**
106    * We keep these in a DLL.
107    */
108   struct ZeroAnonByType *next;
109
110   /**
111    * We keep these in a DLL.
112    */
113   struct ZeroAnonByType *prev;
114
115   /**
116    * Array of 0-anonymity items of the given type.
117    */
118   struct Value **array;
119
120   /**
121    * Allocated size of the array.
122    */
123   unsigned int array_size;
124
125   /**
126    * First unused offset in 'array'.
127    */
128   unsigned int array_pos;
129
130   /**
131    * Type of all of the values in 'array'.
132    */
133   enum GNUNET_BLOCK_Type type;
134 };
135
136
137 /**
138  * Context for all functions in this plugin.
139  */
140 struct Plugin
141 {
142   /**
143    * Our execution environment.
144    */
145   struct GNUNET_DATASTORE_PluginEnvironment *env;
146
147   /**
148    * Mapping from keys to 'struct Value's.
149    */
150   struct GNUNET_CONTAINER_MultiHashMap *keyvalue;
151
152   /**
153    * Heap organized by minimum expiration time.
154    */
155   struct GNUNET_CONTAINER_Heap *by_expiration;
156
157   /**
158    * Heap organized by maximum replication value.
159    */
160   struct GNUNET_CONTAINER_Heap *by_replication;
161
162   /**
163    * Head of list of arrays containing zero-anonymity values by type.
164    */
165   struct ZeroAnonByType *zero_head;
166
167   /**
168    * Tail of list of arrays containing zero-anonymity values by type.
169    */
170   struct ZeroAnonByType *zero_tail;
171
172   /**
173    * Size of all values we're storing.
174    */
175   unsigned long long size;
176
177 };
178
179
180 /**
181  * Get an estimate of how much space the database is
182  * currently using.
183  *
184  * @param cls our "struct Plugin*"
185  * @return number of bytes used on disk
186  */
187 static void
188 heap_plugin_estimate_size (void *cls, unsigned long long *estimate)
189 {
190   struct Plugin *plugin = cls;
191
192   if (NULL != estimate)
193     *estimate = plugin->size;
194 }
195
196
197 /**
198  * Closure for iterator for updating.
199  */
200 struct UpdateContext
201 {
202   /**
203    * Number of bytes in 'data'.
204    */
205   uint32_t size;
206
207   /**
208    * Pointer to the data.
209    */
210   const void *data;
211
212   /**
213    * Priority of the value.
214    */
215   uint32_t priority;
216
217   /**
218    * Replication level for the value.
219    */
220   uint32_t replication;
221
222   /**
223    * Expiration time for this value.
224    */
225   struct GNUNET_TIME_Absolute expiration;
226
227   /**
228    * True if the value was found and updated.
229    */
230   bool updated;
231 };
232
233
234 /**
235  * Update the matching value.
236  *
237  * @param cls the 'struct UpdateContext'
238  * @param key unused
239  * @param val the 'struct Value'
240  * @return GNUNET_YES (continue iteration), GNUNET_NO if value was found
241  */
242 static int
243 update_iterator (void *cls,
244                  const struct GNUNET_HashCode *key,
245                  void *val)
246 {
247   struct UpdateContext *uc = cls;
248   struct Value *value = val;
249
250   if (value->size != uc->size)
251     return GNUNET_YES;
252   if (0 != memcmp (value->data, uc->data, uc->size))
253     return GNUNET_YES;
254   uc->expiration = GNUNET_TIME_absolute_max (value->expiration,
255                                              uc->expiration);
256   if (value->expiration.abs_value_us != uc->expiration.abs_value_us)
257   {
258     value->expiration = uc->expiration;
259     GNUNET_CONTAINER_heap_update_cost (value->expire_heap,
260                                        value->expiration.abs_value_us);
261   }
262   /* Saturating adds, don't overflow */
263   if (value->priority > UINT32_MAX - uc->priority)
264     value->priority = UINT32_MAX;
265   else
266     value->priority += uc->priority;
267   if (value->replication > UINT32_MAX - uc->replication)
268     value->replication = UINT32_MAX;
269   else
270     value->replication += uc->replication;
271   uc->updated = true;
272   return GNUNET_NO;
273 }
274
275 /**
276  * Store an item in the datastore.
277  *
278  * @param cls closure
279  * @param key key for the item
280  * @param absent true if the key was not found in the bloom filter
281  * @param size number of bytes in data
282  * @param data content stored
283  * @param type type of the content
284  * @param priority priority of the content
285  * @param anonymity anonymity-level for the content
286  * @param replication replication-level for the content
287  * @param expiration expiration time for the content
288  * @param cont continuation called with success or failure status
289  * @param cont_cls continuation closure
290  */
291 static void
292 heap_plugin_put (void *cls,
293                  const struct GNUNET_HashCode *key,
294                  bool absent,
295                  uint32_t size,
296                  const void *data,
297                  enum GNUNET_BLOCK_Type type,
298                  uint32_t priority,
299                  uint32_t anonymity,
300                  uint32_t replication,
301                  struct GNUNET_TIME_Absolute expiration,
302                  PluginPutCont cont,
303                  void *cont_cls)
304 {
305   struct Plugin *plugin = cls;
306   struct Value *value;
307
308   if (!absent) {
309     struct UpdateContext uc;
310
311     uc.size = size;
312     uc.data = data;
313     uc.priority = priority;
314     uc.replication = replication;
315     uc.expiration = expiration;
316     uc.updated = false;
317     GNUNET_CONTAINER_multihashmap_get_multiple (plugin->keyvalue,
318                                                 key,
319                                                 &update_iterator,
320                                                 &uc);
321     if (uc.updated)
322     {
323       cont (cont_cls, key, size, GNUNET_NO, NULL);
324       return;
325     }
326   }
327   value = GNUNET_malloc (sizeof (struct Value) + size);
328   value->key = *key;
329   value->data = &value[1];
330   value->expire_heap = GNUNET_CONTAINER_heap_insert (plugin->by_expiration,
331                                                      value,
332                                                      expiration.abs_value_us);
333   value->replication_heap = GNUNET_CONTAINER_heap_insert (plugin->by_replication,
334                                                           value,
335                                                           replication);
336   value->expiration = expiration;
337   if (0 == anonymity)
338   {
339     struct ZeroAnonByType *zabt;
340
341     for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next)
342       if (zabt->type == type)
343         break;
344     if (NULL == zabt)
345     {
346       zabt = GNUNET_new (struct ZeroAnonByType);
347       zabt->type = type;
348       GNUNET_CONTAINER_DLL_insert (plugin->zero_head,
349                                    plugin->zero_tail,
350                                    zabt);
351     }
352     if (zabt->array_size == zabt->array_pos)
353     {
354       GNUNET_array_grow (zabt->array,
355                          zabt->array_size,
356                          zabt->array_size * 2 + 4);
357     }
358     value->zero_anon_offset = zabt->array_pos;
359     zabt->array[zabt->array_pos++] = value;
360   }
361   value->size = size;
362   value->priority = priority;
363   value->anonymity = anonymity;
364   value->replication = replication;
365   value->type = type;
366   GNUNET_memcpy (&value[1], data, size);
367   GNUNET_CONTAINER_multihashmap_put (plugin->keyvalue,
368                                      &value->key,
369                                      value,
370                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
371   plugin->size += size;
372   cont (cont_cls, key, size, GNUNET_OK, NULL);
373 }
374
375
376 /**
377  * Delete the given value, removing it from the plugin's data
378  * structures.
379  *
380  * @param plugin the plugin
381  * @param value value to delete
382  */
383 static void
384 delete_value (struct Plugin *plugin,
385               struct Value *value)
386 {
387   GNUNET_assert (GNUNET_YES ==
388                  GNUNET_CONTAINER_multihashmap_remove (plugin->keyvalue,
389                                                        &value->key,
390                                                        value));
391   GNUNET_assert (value == GNUNET_CONTAINER_heap_remove_node (value->expire_heap));
392   GNUNET_assert (value == GNUNET_CONTAINER_heap_remove_node (value->replication_heap));
393   if (0 == value->anonymity)
394   {
395     struct ZeroAnonByType *zabt;
396
397     for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next)
398       if (zabt->type == value->type)
399         break;
400     GNUNET_assert (NULL != zabt);
401     zabt->array[value->zero_anon_offset] = zabt->array[--zabt->array_pos];
402     zabt->array[value->zero_anon_offset]->zero_anon_offset = value->zero_anon_offset;
403     if (0 == zabt->array_pos)
404     {
405       GNUNET_array_grow (zabt->array,
406                          zabt->array_size,
407                          0);
408       GNUNET_CONTAINER_DLL_remove (plugin->zero_head,
409                                    plugin->zero_tail,
410                                    zabt);
411       GNUNET_free (zabt);
412     }
413   }
414   plugin->size -= value->size;
415   GNUNET_free (value);
416 }
417
418
419 /**
420  * Closure for iterator called during 'get_key'.
421  */
422 struct GetContext
423 {
424
425   /**
426    * Lowest uid to consider.
427    */
428   uint64_t next_uid;
429
430   /**
431    * Value with lowest uid >= next_uid found so far.
432    */
433   struct Value *value;
434
435   /**
436    * Requested type.
437    */
438   enum GNUNET_BLOCK_Type type;
439
440   /**
441    * If true, return a random value
442    */
443   bool random;
444
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 (plugin->by_replication,
572                                                             value,
573                                                             value->replication);
574   }
575   else
576   {
577     /* need a better way to pick a random item, replication level is always 0 */
578     value->replication_heap = GNUNET_CONTAINER_heap_insert (plugin->by_replication,
579                                                             value,
580                                                             value->replication);
581     value = GNUNET_CONTAINER_heap_walk_get_next (plugin->by_replication);
582   }
583   GNUNET_assert (GNUNET_OK ==
584                  proc (proc_cls,
585                        &value->key,
586                        value->size,
587                        &value[1],
588                        value->type,
589                        value->priority,
590                        value->anonymity,
591                        value->replication,
592                        value->expiration,
593                        (uint64_t) (intptr_t) value));
594 }
595
596
597 /**
598  * Get a random item for expiration.  Call 'proc' with all values ZERO
599  * or NULL if the datastore is empty.
600  *
601  * @param cls closure
602  * @param proc function to call the value (once only).
603  * @param proc_cls closure for proc
604  */
605 static void
606 heap_plugin_get_expiration (void *cls, PluginDatumProcessor proc,
607                             void *proc_cls)
608 {
609   struct Plugin *plugin = cls;
610   struct Value *value;
611
612   value = GNUNET_CONTAINER_heap_peek (plugin->by_expiration);
613   if (NULL == value)
614   {
615     proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
616     return;
617   }
618   if (GNUNET_NO ==
619       proc (proc_cls,
620             &value->key,
621             value->size,
622             &value[1],
623             value->type,
624             value->priority,
625             value->anonymity,
626             value->replication,
627             value->expiration,
628             (uint64_t) (intptr_t) value))
629     delete_value (plugin, value);
630 }
631
632
633 /**
634  * Call the given processor on an item with zero anonymity.
635  *
636  * @param cls our "struct Plugin*"
637  * @param next_uid return the result with lowest uid >= next_uid
638  * @param type entries of which type should be considered?
639  *        Must not be zero (ANY).
640  * @param proc function to call on each matching value;
641  *        will be called with NULL if no value matches
642  * @param proc_cls closure for proc
643  */
644 static void
645 heap_plugin_get_zero_anonymity (void *cls, uint64_t next_uid,
646                                 enum GNUNET_BLOCK_Type type,
647                                 PluginDatumProcessor proc, void *proc_cls)
648 {
649   struct Plugin *plugin = cls;
650   struct ZeroAnonByType *zabt;
651   struct Value *value = NULL;
652
653   for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next)
654   {
655     if ( (type != GNUNET_BLOCK_TYPE_ANY) &&
656          (type != zabt->type) )
657       continue;
658     for (int i = 0; i < zabt->array_pos; ++i)
659     {
660       if ( (uint64_t) (intptr_t) zabt->array[i] < next_uid)
661         continue;
662       if ( (NULL != value) &&
663            (zabt->array[i] > value) )
664         continue;
665       value = zabt->array[i];
666     }
667   }
668   if (NULL == value)
669   {
670     proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
671     return;
672   }
673   GNUNET_assert (GNUNET_OK ==
674                  proc (proc_cls,
675                        &value->key,
676                        value->size,
677                        &value[1],
678                        value->type,
679                        value->priority,
680                        value->anonymity,
681                        value->replication,
682                        value->expiration,
683                        (uint64_t) (intptr_t) value));
684 }
685
686
687 /**
688  * Drop database.
689  */
690 static void
691 heap_plugin_drop (void *cls)
692 {
693   /* nothing needs to be done */
694 }
695
696
697 /**
698  * Closure for the 'return_value' function.
699  */
700 struct GetAllContext
701 {
702   /**
703    * Function to call.
704    */
705   PluginKeyProcessor proc;
706
707   /**
708    * Closure for 'proc'.
709    */
710   void *proc_cls;
711 };
712
713
714 /**
715  * Callback invoked to call callback on each value.
716  *
717  * @param cls the plugin
718  * @param key unused
719  * @param val the value
720  * @return GNUNET_OK (continue to iterate)
721  */
722 static int
723 return_value (void *cls,
724               const struct GNUNET_HashCode *key,
725               void *val)
726 {
727   struct GetAllContext *gac = cls;
728
729   gac->proc (gac->proc_cls,
730              key,
731              1);
732   return GNUNET_OK;
733 }
734
735
736 /**
737  * Get all of the keys in the datastore.
738  *
739  * @param cls closure
740  * @param proc function to call on each key
741  * @param proc_cls closure for proc
742  */
743 static void
744 heap_get_keys (void *cls,
745                PluginKeyProcessor proc,
746                void *proc_cls)
747 {
748   struct Plugin *plugin = cls;
749   struct GetAllContext gac;
750
751   gac.proc = proc;
752   gac.proc_cls = proc_cls;
753   GNUNET_CONTAINER_multihashmap_iterate (plugin->keyvalue,
754                                          &return_value,
755                                          &gac);
756   proc (proc_cls, NULL, 0);
757 }
758
759
760 /**
761  * Closure for iterator called during 'remove_key'.
762  */
763 struct RemoveContext
764 {
765
766   /**
767    * Value found.
768    */
769   struct Value *value;
770
771   /**
772    * Size of data.
773    */
774   uint32_t size;
775
776   /**
777    * Data to remove.
778    */
779   const void *data;
780
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 (GNUNET_CONTAINER_HEAP_ORDER_MIN);
880   plugin->by_replication = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
881   api = GNUNET_new (struct GNUNET_DATASTORE_PluginFunctions);
882   api->cls = plugin;
883   api->estimate_size = &heap_plugin_estimate_size;
884   api->put = &heap_plugin_put;
885   api->get_key = &heap_plugin_get_key;
886   api->get_replication = &heap_plugin_get_replication;
887   api->get_expiration = &heap_plugin_get_expiration;
888   api->get_zero_anonymity = &heap_plugin_get_zero_anonymity;
889   api->drop = &heap_plugin_drop;
890   api->get_keys = &heap_get_keys;
891   api->remove_key = &heap_plugin_remove_key;
892   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "heap",
893                    _("Heap database running\n"));
894   return api;
895 }
896
897
898 /**
899  * Callback invoked to free all value.
900  *
901  * @param cls the plugin
902  * @param key unused
903  * @param val the value
904  * @return GNUNET_OK (continue to iterate)
905  */
906 static int
907 free_value (void *cls,
908             const struct GNUNET_HashCode *key,
909             void *val)
910 {
911   struct Plugin *plugin = cls;
912   struct Value *value = val;
913
914   delete_value (plugin, value);
915   return GNUNET_OK;
916 }
917
918
919 /**
920  * Exit point from the plugin.
921  * @param cls our "struct Plugin*"
922  * @return always NULL
923  */
924 void *
925 libgnunet_plugin_datastore_heap_done (void *cls)
926 {
927   struct GNUNET_DATASTORE_PluginFunctions *api = cls;
928   struct Plugin *plugin = api->cls;
929
930   GNUNET_CONTAINER_multihashmap_iterate (plugin->keyvalue,
931                                          &free_value,
932                                          plugin);
933   GNUNET_CONTAINER_multihashmap_destroy (plugin->keyvalue);
934   GNUNET_CONTAINER_heap_destroy (plugin->by_expiration);
935   GNUNET_CONTAINER_heap_destroy (plugin->by_replication);
936   GNUNET_free (plugin);
937   GNUNET_free (api);
938   return NULL;
939 }
940
941 /* end of plugin_datastore_heap.c */