gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [gnunet] branch master updated: [datastore] Create remove p


From: gnunet
Subject: [GNUnet-SVN] [gnunet] branch master updated: [datastore] Create remove plugin API call
Date: Mon, 17 Apr 2017 03:49:40 +0200

This is an automated email from the git hooks/post-receive script.

david-barksdale pushed a commit to branch master
in repository gnunet.

The following commit(s) were added to refs/heads/master by this push:
     new a58d36b8d [datastore] Create remove plugin API call
a58d36b8d is described below

commit a58d36b8da7afa42410bac54f57d5f3b6b6c4391
Author: David Barksdale <address@hidden>
AuthorDate: Sun Apr 16 20:46:21 2017 -0500

    [datastore] Create remove plugin API call
    
    The only use of vhash in the get_key call was for removing, split that out
    into its own function.  This simplifies the get_key call and removes the
    need for some indexes, speeding up insertion into the database.
---
 src/datastore/gnunet-service-datastore.c  |  80 +++++-------
 src/datastore/plugin_datastore_heap.c     | 202 ++++++++++++++++++++---------
 src/datastore/plugin_datastore_mysql.c    | 209 +++++++++++++++---------------
 src/datastore/plugin_datastore_postgres.c |  90 ++++++++++---
 src/datastore/plugin_datastore_sqlite.c   | 110 +++++++++++++---
 src/datastore/plugin_datastore_template.c |  39 ++++--
 src/datastore/test_plugin_datastore.c     |  40 +++++-
 src/include/gnunet_datastore_plugin.h     |  47 ++++++-
 8 files changed, 552 insertions(+), 265 deletions(-)

diff --git a/src/datastore/gnunet-service-datastore.c 
b/src/datastore/gnunet-service-datastore.c
index d965ad8e0..53ba858e4 100644
--- a/src/datastore/gnunet-service-datastore.c
+++ b/src/datastore/gnunet-service-datastore.c
@@ -880,7 +880,6 @@ handle_get (void *cls,
                         GNUNET_ntohll (msg->next_uid),
                         msg->random,
                         NULL,
-                        NULL,
                         ntohl (msg->type),
                         &transmit_item,
                         client);
@@ -932,7 +931,6 @@ handle_get_key (void *cls,
                         GNUNET_ntohll (msg->next_uid),
                         msg->random,
                         &msg->key,
-                        NULL,
                         ntohl (msg->type),
                         &transmit_item,
                         client);
@@ -1001,50 +999,46 @@ handle_get_zero_anonymity (void *cls,
 
 
 /**
- * Callback function that will cause the item that is passed
- * in to be deleted (by returning #GNUNET_NO).
+ * Remove continuation.
  *
  * @param cls closure
  * @param key key for the content
  * @param size number of bytes in data
- * @param data content stored
- * @param type type of the content
- * @param priority priority of the content
- * @param anonymity anonymity-level for the content
- * @param replication replication-level for the content
- * @param expiration expiration time for the content
- * @param uid unique identifier for the datum
- * @return #GNUNET_OK to keep the item
- *         #GNUNET_NO to delete the item
+ * @param status #GNUNET_OK if removed, #GNUNET_NO if not found,
+ *        or #GNUNET_SYSERROR if error
+ * @param msg error message on error
  */
-static int
-remove_callback (void *cls,
-                 const struct GNUNET_HashCode *key,
-                 uint32_t size,
-                 const void *data,
-                 enum GNUNET_BLOCK_Type type,
-                 uint32_t priority,
-                 uint32_t anonymity,
-                 uint32_t replication,
-                 struct GNUNET_TIME_Absolute expiration,
-                 uint64_t uid)
+static void
+remove_continuation (void *cls,
+                     const struct GNUNET_HashCode *key,
+                     uint32_t size,
+                     int status,
+                     const char *msg)
 {
   struct GNUNET_SERVICE_Client *client = cls;
 
-  if (NULL == key)
+  if (GNUNET_SYSERR == status)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "REMOVE request failed: %s.\n",
+                msg);
+    transmit_status (client,
+                     GNUNET_NO,
+                     msg);
+    return;
+  }
+  if (GNUNET_NO == status)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "No further matches for REMOVE request.\n");
+                "Content not found for REMOVE request.\n");
     transmit_status (client,
                      GNUNET_NO,
                      _("Content not found"));
-    return GNUNET_OK;           /* last item */
+    return;
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Item %llu matches REMOVE request for key `%s' and type %u.\n",
-              (unsigned long long) uid,
-              GNUNET_h2s (key),
-              type);
+              "Item matches REMOVE request for key `%s'.\n",
+              GNUNET_h2s (key));
   GNUNET_STATISTICS_update (stats,
                             gettext_noop ("# bytes removed (explicit 
request)"),
                             size,
@@ -1054,7 +1048,6 @@ remove_callback (void *cls,
   transmit_status (client,
                    GNUNET_OK,
                    NULL);
-  return GNUNET_NO;
 }
 
 
@@ -1090,26 +1083,19 @@ handle_remove (void *cls,
                const struct DataMessage *dm)
 {
   struct GNUNET_SERVICE_Client *client = cls;
-  struct GNUNET_HashCode vhash;
 
   GNUNET_STATISTICS_update (stats,
                             gettext_noop ("# REMOVE requests received"),
                             1, GNUNET_NO);
-  GNUNET_CRYPTO_hash (&dm[1],
-                      ntohl (dm->size),
-                      &vhash);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Processing REMOVE request for `%s' of type %u\n",
-              GNUNET_h2s (&dm->key),
-              (uint32_t) ntohl (dm->type));
-  plugin->api->get_key (plugin->api->cls,
-                        0,
-                        false,
-                        &dm->key,
-                        &vhash,
-                        (enum GNUNET_BLOCK_Type) ntohl (dm->type),
-                        &remove_callback,
-                        client);
+              "Processing REMOVE request for `%s'\n",
+              GNUNET_h2s (&dm->key));
+  plugin->api->remove_key (plugin->api->cls,
+                           &dm->key,
+                           ntohl (dm->size),
+                           &dm[1],
+                           &remove_continuation,
+                           client);
   GNUNET_SERVICE_client_continue (client);
 }
 
diff --git a/src/datastore/plugin_datastore_heap.c 
b/src/datastore/plugin_datastore_heap.c
index 6dbc15ebd..9950f7ab2 100644
--- a/src/datastore/plugin_datastore_heap.c
+++ b/src/datastore/plugin_datastore_heap.c
@@ -433,11 +433,6 @@ struct GetContext
   struct Value *value;
 
   /**
-   * Requested value hash.
-   */
-  const struct GNUNET_HashCode *vhash;
-
-  /**
    * Requested type.
    */
   enum GNUNET_BLOCK_Type type;
@@ -465,17 +460,10 @@ get_iterator (void *cls,
 {
   struct GetContext *gc = cls;
   struct Value *value = val;
-  struct GNUNET_HashCode vh;
 
   if ( (gc->type != GNUNET_BLOCK_TYPE_ANY) &&
        (gc->type != value->type) )
     return GNUNET_OK;
-  if (NULL != gc->vhash)
-  {
-    GNUNET_CRYPTO_hash (&value[1], value->size, &vh);
-    if (0 != memcmp (&vh, gc->vhash, sizeof (struct GNUNET_HashCode)))
-      return GNUNET_OK;
-  }
   if (gc->random)
   {
     gc->value = value;
@@ -498,23 +486,20 @@ get_iterator (void *cls,
  * @param next_uid return the result with lowest uid >= next_uid
  * @param random if true, return a random result instead of using next_uid
  * @param key maybe NULL (to match all entries)
- * @param vhash hash of the value, maybe NULL (to
- *        match all values that have the right key).
- *        Note that for DBlocks there is no difference
- *        betwen key and vhash, but for other blocks
- *        there may be!
  * @param type entries of which type are relevant?
  *     Use 0 for any type.
- * @param proc function to call on each matching value;
+ * @param proc function to call on the matching value;
  *        will be called with NULL if nothing matches
- * @param proc_cls closure for proc
+ * @param proc_cls closure for @a proc
  */
 static void
-heap_plugin_get_key (void *cls, uint64_t next_uid, bool random,
-                    const struct GNUNET_HashCode *key,
-                    const struct GNUNET_HashCode *vhash,
-                    enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc,
-                    void *proc_cls)
+heap_plugin_get_key (void *cls,
+                     uint64_t next_uid,
+                     bool random,
+                     const struct GNUNET_HashCode *key,
+                     enum GNUNET_BLOCK_Type type,
+                     PluginDatumProcessor proc,
+                     void *proc_cls)
 {
   struct Plugin *plugin = cls;
   struct GetContext gc;
@@ -522,7 +507,6 @@ heap_plugin_get_key (void *cls, uint64_t next_uid, bool 
random,
   gc.value = NULL;
   gc.next_uid = next_uid;
   gc.random = random;
-  gc.vhash = vhash;
   gc.type = type;
   if (NULL == key)
   {
@@ -542,20 +526,17 @@ heap_plugin_get_key (void *cls, uint64_t next_uid, bool 
random,
     proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
     return;
   }
-  if (GNUNET_NO ==
-      proc (proc_cls,
-            &gc.value->key,
-            gc.value->size,
-            &gc.value[1],
-            gc.value->type,
-            gc.value->priority,
-            gc.value->anonymity,
-            gc.value->replication,
-            gc.value->expiration,
-            (uint64_t) (intptr_t) gc.value))
-  {
-    delete_value (plugin, gc.value);
-  }
+  GNUNET_assert (GNUNET_OK ==
+                 proc (proc_cls,
+                       &gc.value->key,
+                       gc.value->size,
+                       &gc.value[1],
+                       gc.value->type,
+                       gc.value->priority,
+                       gc.value->anonymity,
+                       gc.value->replication,
+                       gc.value->expiration,
+                       (uint64_t) (intptr_t) gc.value));
 }
 
 
@@ -599,18 +580,17 @@ heap_plugin_get_replication (void *cls,
                                                            value->replication);
     value = GNUNET_CONTAINER_heap_walk_get_next (plugin->by_replication);
   }
-  if (GNUNET_NO ==
-      proc (proc_cls,
-            &value->key,
-            value->size,
-            &value[1],
-            value->type,
-            value->priority,
-            value->anonymity,
-            value->replication,
-            value->expiration,
-            (uint64_t) (intptr_t) value))
-    delete_value (plugin, value);
+  GNUNET_assert (GNUNET_OK ==
+                 proc (proc_cls,
+                       &value->key,
+                       value->size,
+                       &value[1],
+                       value->type,
+                       value->priority,
+                       value->anonymity,
+                       value->replication,
+                       value->expiration,
+                       (uint64_t) (intptr_t) value));
 }
 
 
@@ -690,18 +670,17 @@ heap_plugin_get_zero_anonymity (void *cls, uint64_t 
next_uid,
     proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
     return;
   }
-  if (GNUNET_NO ==
-      proc (proc_cls,
-            &value->key,
-            value->size,
-            &value[1],
-            value->type,
-            value->priority,
-            value->anonymity,
-            value->replication,
-            value->expiration,
-            (uint64_t) (intptr_t) value))
-    delete_value (plugin, value);
+  GNUNET_assert (GNUNET_OK ==
+                 proc (proc_cls,
+                       &value->key,
+                       value->size,
+                       &value[1],
+                       value->type,
+                       value->priority,
+                       value->anonymity,
+                       value->replication,
+                       value->expiration,
+                       (uint64_t) (intptr_t) value));
 }
 
 
@@ -779,6 +758,102 @@ heap_get_keys (void *cls,
 
 
 /**
+ * Closure for iterator called during 'remove_key'.
+ */
+struct RemoveContext
+{
+
+  /**
+   * Value found.
+   */
+  struct Value *value;
+
+  /**
+   * Size of data.
+   */
+  uint32_t size;
+
+  /**
+   * Data to remove.
+   */
+  const void *data;
+
+};
+
+
+/**
+ * Obtain the matching value with the lowest uid >= next_uid.
+ *
+ * @param cls the 'struct GetContext'
+ * @param key unused
+ * @param val the 'struct Value'
+ * @return GNUNET_YES (continue iteration), GNUNET_NO if result was found
+ */
+static int
+remove_iterator (void *cls,
+                 const struct GNUNET_HashCode *key,
+                 void *val)
+{
+  struct RemoveContext *rc = cls;
+  struct Value *value = val;
+
+  if (value->size != rc->size)
+    return GNUNET_YES;
+  if (0 != memcmp (value->data, rc->data, rc->size))
+    return GNUNET_YES;
+  rc->value = value;
+  return GNUNET_NO;
+}
+
+
+/**
+ * Remove a particular key in the datastore.
+ *
+ * @param cls closure
+ * @param key key for the content
+ * @param size number of bytes in data
+ * @param data content stored
+ * @param cont continuation called with success or failure status
+ * @param cont_cls continuation closure for @a cont
+ */
+static void
+heap_plugin_remove_key (void *cls,
+                        const struct GNUNET_HashCode *key,
+                        uint32_t size,
+                        const void *data,
+                        PluginRemoveCont cont,
+                        void *cont_cls)
+{
+  struct Plugin *plugin = cls;
+  struct RemoveContext rc;
+
+  rc.value = NULL;
+  rc.size = size;
+  rc.data = data;
+  GNUNET_CONTAINER_multihashmap_get_multiple (plugin->keyvalue,
+                                              key,
+                                              &remove_iterator,
+                                              &rc);
+  if (NULL == rc.value)
+  {
+    cont (cont_cls,
+          key,
+          size,
+          GNUNET_NO,
+          NULL);
+    return;
+  }
+  delete_value (plugin,
+                rc.value);
+  cont (cont_cls,
+        key,
+        size,
+        GNUNET_OK,
+        NULL);
+}
+
+
+/**
  * Entry point for the plugin.
  *
  * @param cls the "struct GNUNET_DATASTORE_PluginEnvironment*"
@@ -813,6 +888,7 @@ libgnunet_plugin_datastore_heap_init (void *cls)
   api->get_zero_anonymity = &heap_plugin_get_zero_anonymity;
   api->drop = &heap_plugin_drop;
   api->get_keys = &heap_get_keys;
+  api->remove_key = &heap_plugin_remove_key;
   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "heap",
                    _("Heap database running\n"));
   return api;
diff --git a/src/datastore/plugin_datastore_mysql.c 
b/src/datastore/plugin_datastore_mysql.c
index edc459272..708e35860 100644
--- a/src/datastore/plugin_datastore_mysql.c
+++ b/src/datastore/plugin_datastore_mysql.c
@@ -150,6 +150,12 @@ struct Plugin
 #define DELETE_ENTRY_BY_UID "DELETE FROM gn090 WHERE uid=?"
   struct GNUNET_MYSQL_StatementHandle *delete_entry_by_uid;
 
+#define DELETE_ENTRY_BY_HASH_VALUE "DELETE FROM gn090 "\
+  "WHERE hash = ? AND "\
+  "value = ? "\
+  "LIMIT 1"
+  struct GNUNET_MYSQL_StatementHandle *delete_entry_by_hash_value;
+
 #define RESULT_COLUMNS "repl, type, prio, anonLevel, expire, hash, value, uid"
 
 #define SELECT_ENTRY "SELECT " RESULT_COLUMNS " FROM gn090 "\
@@ -159,22 +165,13 @@ struct Plugin
   struct GNUNET_MYSQL_StatementHandle *select_entry;
 
 #define SELECT_ENTRY_BY_HASH "SELECT " RESULT_COLUMNS " FROM gn090 "\
-  "FORCE INDEX (idx_hash) "\
+  "FORCE INDEX (idx_hash_type_uid) "\
   "WHERE hash=? AND "\
   "uid >= ? AND "\
   "(rvalue >= ? OR 0 = ?) "\
   "ORDER BY uid LIMIT 1"
   struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash;
 
-#define SELECT_ENTRY_BY_HASH_AND_VHASH "SELECT " RESULT_COLUMNS " FROM gn090 "\
-  "FORCE INDEX (idx_hash_vhash) "\
-  "WHERE hash = ? AND "\
-  "vhash = ? AND "\
-  "uid >= ? AND "\
-  "(rvalue >= ? OR 0 = ?) "\
-  "ORDER BY uid LIMIT 1"
-  struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_and_vhash;
-
 #define SELECT_ENTRY_BY_HASH_AND_TYPE "SELECT " RESULT_COLUMNS " FROM gn090 "\
   "FORCE INDEX (idx_hash_type_uid) "\
   "WHERE hash = ? AND "\
@@ -184,17 +181,6 @@ struct Plugin
   "ORDER BY uid LIMIT 1"
   struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_and_type;
 
-#define SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT " RESULT_COLUMNS " "\
-  "FROM gn090 "\
-  "FORCE INDEX (idx_hash_vhash) "\
-  "WHERE hash = ? AND "\
-  "vhash = ? AND "\
-  "type = ? AND "\
-  "uid >= ? AND "\
-  "(rvalue >= ? OR 0 = ?) "\
-  "ORDER BY uid LIMIT 1"
-  struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_vhash_and_type;
-
 #define UPDATE_ENTRY "UPDATE gn090 SET "\
   "prio = prio + ?, "\
   "repl = repl + ?, "\
@@ -552,11 +538,6 @@ execute_select (struct Plugin *plugin,
  * @param next_uid return the result with lowest uid >= next_uid
  * @param random if true, return a random result instead of using next_uid
  * @param key key to match, never NULL
- * @param vhash hash of the value, maybe NULL (to
- *        match all values that have the right key).
- *        Note that for DBlocks there is no difference
- *        betwen key and vhash, but for other blocks
- *        there may be!
  * @param type entries of which type are relevant?
  *     Use 0 for any type.
  * @param proc function to call on the matching value,
@@ -568,7 +549,6 @@ mysql_plugin_get_key (void *cls,
                       uint64_t next_uid,
                       bool random,
                       const struct GNUNET_HashCode *key,
-                      const struct GNUNET_HashCode *vhash,
                       enum GNUNET_BLOCK_Type type,
                       PluginDatumProcessor proc,
                       void *proc_cls)
@@ -602,79 +582,37 @@ mysql_plugin_get_key (void *cls,
   }
   else if (type != GNUNET_BLOCK_TYPE_ANY)
   {
-    if (NULL != vhash)
-    {
-      struct GNUNET_MY_QueryParam params_select[] = {
-        GNUNET_MY_query_param_auto_from_type (key),
-        GNUNET_MY_query_param_auto_from_type (vhash),
-        GNUNET_MY_query_param_uint32 (&type),
-        GNUNET_MY_query_param_uint64 (&next_uid),
-        GNUNET_MY_query_param_uint64 (&rvalue),
-        GNUNET_MY_query_param_uint64 (&rvalue),
-        GNUNET_MY_query_param_end
-      };
-
-      execute_select (plugin,
-                      plugin->select_entry_by_hash_vhash_and_type,
-                      proc,
-                      proc_cls,
-                      params_select);
-    }
-    else
-    {
-      struct GNUNET_MY_QueryParam params_select[] = {
-        GNUNET_MY_query_param_auto_from_type (key),
-        GNUNET_MY_query_param_uint32 (&type),
-        GNUNET_MY_query_param_uint64 (&next_uid),
-        GNUNET_MY_query_param_uint64 (&rvalue),
-        GNUNET_MY_query_param_uint64 (&rvalue),
-        GNUNET_MY_query_param_end
-      };
-
-      execute_select (plugin,
-                      plugin->select_entry_by_hash_and_type,
-                      proc,
-                      proc_cls,
-                      params_select);
-    }
+    struct GNUNET_MY_QueryParam params_select[] = {
+      GNUNET_MY_query_param_auto_from_type (key),
+      GNUNET_MY_query_param_uint32 (&type),
+      GNUNET_MY_query_param_uint64 (&next_uid),
+      GNUNET_MY_query_param_uint64 (&rvalue),
+      GNUNET_MY_query_param_uint64 (&rvalue),
+      GNUNET_MY_query_param_end
+    };
+
+    execute_select (plugin,
+                    plugin->select_entry_by_hash_and_type,
+                    proc,
+                    proc_cls,
+                    params_select);
   }
   else
   {
-    if (NULL != vhash)
-    {
-      struct GNUNET_MY_QueryParam params_select[] = {
-        GNUNET_MY_query_param_auto_from_type (key),
-        GNUNET_MY_query_param_auto_from_type (vhash),
-        GNUNET_MY_query_param_uint64 (&next_uid),
-        GNUNET_MY_query_param_uint64 (&rvalue),
-        GNUNET_MY_query_param_uint64 (&rvalue),
-        GNUNET_MY_query_param_end
-      };
-
-      execute_select (plugin,
-                      plugin->select_entry_by_hash_and_vhash,
-                      proc,
-                      proc_cls,
-                      params_select);
-    }
-    else
-    {
-      struct GNUNET_MY_QueryParam params_select[] = {
-        GNUNET_MY_query_param_auto_from_type (key),
-        GNUNET_MY_query_param_uint64 (&next_uid),
-        GNUNET_MY_query_param_uint64 (&rvalue),
-        GNUNET_MY_query_param_uint64 (&rvalue),
-        GNUNET_MY_query_param_end
-      };
-
-      execute_select (plugin,
-                      plugin->select_entry_by_hash,
-                      proc,
-                      proc_cls,
-                      params_select);
-    }
-  }
+    struct GNUNET_MY_QueryParam params_select[] = {
+      GNUNET_MY_query_param_auto_from_type (key),
+      GNUNET_MY_query_param_uint64 (&next_uid),
+      GNUNET_MY_query_param_uint64 (&rvalue),
+      GNUNET_MY_query_param_uint64 (&rvalue),
+      GNUNET_MY_query_param_end
+    };
 
+    execute_select (plugin,
+                    plugin->select_entry_by_hash,
+                    proc,
+                    proc_cls,
+                    params_select);
+  }
 }
 
 
@@ -1098,6 +1036,69 @@ mysql_plugin_drop (void *cls)
 
 
 /**
+ * Remove a particular key in the datastore.
+ *
+ * @param cls closure
+ * @param key key for the content
+ * @param size number of bytes in data
+ * @param data content stored
+ * @param cont continuation called with success or failure status
+ * @param cont_cls continuation closure for @a cont
+ */
+static void
+mysql_plugin_remove_key (void *cls,
+                         const struct GNUNET_HashCode *key,
+                         uint32_t size,
+                         const void *data,
+                         PluginRemoveCont cont,
+                         void *cont_cls)
+{
+  struct Plugin *plugin = cls;
+  struct GNUNET_MY_QueryParam params_delete[] = {
+    GNUNET_MY_query_param_auto_from_type (key),
+    GNUNET_MY_query_param_fixed_size (data, size),
+    GNUNET_MY_query_param_end
+  };
+
+  if (GNUNET_OK !=
+      GNUNET_MY_exec_prepared (plugin->mc,
+                               plugin->delete_entry_by_hash_value,
+                               params_delete))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Removing key `%s' from gn090 table failed\n",
+                GNUNET_h2s (key));
+    cont (cont_cls,
+          key,
+          size,
+          GNUNET_SYSERR,
+          _("MySQL statement run failure"));
+    return;
+  }
+
+  MYSQL_STMT *stmt = GNUNET_MYSQL_statement_get_stmt 
(plugin->delete_entry_by_hash_value);
+  my_ulonglong rows = mysql_stmt_affected_rows (stmt);
+
+  if (0 == rows)
+  {
+    cont (cont_cls,
+          key,
+          size,
+          GNUNET_NO,
+          NULL);
+    return;
+  }
+  plugin->env->duc (plugin->env->cls,
+                    -size);
+  cont (cont_cls,
+        key,
+        size,
+        GNUNET_OK,
+        NULL);
+}
+
+
+/**
  * Entry point for the plugin.
  *
  * @param cls the `struct GNUNET_DATASTORE_PluginEnvironment *`
@@ -1132,24 +1133,20 @@ libgnunet_plugin_datastore_mysql_init (void *cls)
        " hash BINARY(64) NOT NULL DEFAULT '',"
        " vhash BINARY(64) NOT NULL DEFAULT '',"
        " value BLOB NOT NULL DEFAULT ''," " uid BIGINT NOT NULL 
AUTO_INCREMENT,"
-       " PRIMARY KEY (uid)," " INDEX idx_hash (hash(64)),"
-       " INDEX idx_hash_uid (hash(64),uid),"
-       " INDEX idx_hash_vhash (hash(64),vhash(64)),"
+       " PRIMARY KEY (uid),"
        " INDEX idx_hash_type_uid (hash(64),type,rvalue),"
-       " INDEX idx_prio (prio)," " INDEX idx_repl_rvalue (repl,rvalue),"
+       " INDEX idx_prio (prio),"
+       " INDEX idx_repl_rvalue (repl,rvalue),"
        " INDEX idx_expire (expire),"
        " INDEX idx_anonLevel_type_rvalue (anonLevel,type,rvalue)"
        ") ENGINE=InnoDB") || MRUNS ("SET AUTOCOMMIT = 1") ||
       PINIT (plugin->insert_entry, INSERT_ENTRY) ||
       PINIT (plugin->delete_entry_by_uid, DELETE_ENTRY_BY_UID) ||
+      PINIT (plugin->delete_entry_by_hash_value, DELETE_ENTRY_BY_HASH_VALUE) ||
       PINIT (plugin->select_entry, SELECT_ENTRY) ||
       PINIT (plugin->select_entry_by_hash, SELECT_ENTRY_BY_HASH) ||
-      PINIT (plugin->select_entry_by_hash_and_vhash,
-             SELECT_ENTRY_BY_HASH_AND_VHASH) ||
       PINIT (plugin->select_entry_by_hash_and_type,
              SELECT_ENTRY_BY_HASH_AND_TYPE) ||
-      PINIT (plugin->select_entry_by_hash_vhash_and_type,
-             SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE) ||
       PINIT (plugin->get_size, SELECT_SIZE) ||
       PINIT (plugin->update_entry, UPDATE_ENTRY) ||
       PINIT (plugin->dec_repl, DEC_REPL) ||
@@ -1158,7 +1155,8 @@ libgnunet_plugin_datastore_mysql_init (void *cls)
       PINIT (plugin->select_priority, SELECT_IT_PRIORITY) ||
       PINIT (plugin->max_repl, SELECT_MAX_REPL) ||
       PINIT (plugin->get_all_keys, GET_ALL_KEYS) ||
-      PINIT (plugin->select_replication, SELECT_IT_REPLICATION))
+      PINIT (plugin->select_replication, SELECT_IT_REPLICATION) ||
+      false)
   {
     GNUNET_MYSQL_context_destroy (plugin->mc);
     GNUNET_free (plugin);
@@ -1177,6 +1175,7 @@ libgnunet_plugin_datastore_mysql_init (void *cls)
   api->get_zero_anonymity = &mysql_plugin_get_zero_anonymity;
   api->get_keys = &mysql_plugin_get_keys;
   api->drop = &mysql_plugin_drop;
+  api->remove_key = &mysql_plugin_remove_key;
   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "mysql",
                    _("Mysql database running\n"));
   return api;
diff --git a/src/datastore/plugin_datastore_postgres.c 
b/src/datastore/plugin_datastore_postgres.c
index 349848ae6..b6aeb0be6 100644
--- a/src/datastore/plugin_datastore_postgres.c
+++ b/src/datastore/plugin_datastore_postgres.c
@@ -119,9 +119,6 @@ init_connection (struct Plugin *plugin)
                                "CREATE INDEX IF NOT EXISTS idx_hash ON gn090 
(hash)")) ||
         (GNUNET_OK !=
          GNUNET_POSTGRES_exec (plugin->dbh,
-                               "CREATE INDEX IF NOT EXISTS idx_hash_vhash ON 
gn090 (hash,vhash)")) ||
-        (GNUNET_OK !=
-         GNUNET_POSTGRES_exec (plugin->dbh,
                                "CREATE INDEX IF NOT EXISTS idx_prio ON gn090 
(prio)")) ||
         (GNUNET_OK !=
          GNUNET_POSTGRES_exec (plugin->dbh,
@@ -183,9 +180,8 @@ init_connection (struct Plugin *plugin)
                    "WHERE oid >= $1::bigint AND "
                    "(rvalue >= $2 OR 0 = $3::smallint) AND "
                    "(hash = $4 OR 0 = $5::smallint) AND "
-                   "(vhash = $6 OR 0 = $7::smallint) AND "
-                   "(type = $8 OR 0 = $9::smallint) "
-                   "ORDER BY oid ASC LIMIT 1", 9)) ||
+                   "(type = $6 OR 0 = $7::smallint) "
+                   "ORDER BY oid ASC LIMIT 1", 7)) ||
       (GNUNET_OK !=
        GNUNET_POSTGRES_prepare (plugin->dbh, "put",
                    "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, 
rvalue, hash, vhash, value) "
@@ -223,6 +219,10 @@ init_connection (struct Plugin *plugin)
       (GNUNET_OK !=
        GNUNET_POSTGRES_prepare (plugin->dbh, "delrow", "DELETE FROM gn090 " 
"WHERE oid=$1", 1)) ||
       (GNUNET_OK !=
+       GNUNET_POSTGRES_prepare (plugin->dbh, "remove", "DELETE FROM gn090 "
+         "WHERE hash = $1 AND "
+         "value = $2", 2)) ||
+      (GNUNET_OK !=
        GNUNET_POSTGRES_prepare (plugin->dbh, "get_keys", "SELECT hash FROM 
gn090", 0)))
   {
     PQfinish (plugin->dbh);
@@ -536,11 +536,6 @@ process_result (struct Plugin *plugin,
  * @param next_uid return the result with lowest uid >= next_uid
  * @param random if true, return a random result instead of using next_uid
  * @param key maybe NULL (to match all entries)
- * @param vhash hash of the value, maybe NULL (to
- *        match all values that have the right key).
- *        Note that for DBlocks there is no difference
- *        betwen key and vhash, but for other blocks
- *        there may be!
  * @param type entries of which type are relevant?
  *     Use 0 for any type.
  * @param proc function to call on the matching value;
@@ -552,7 +547,6 @@ postgres_plugin_get_key (void *cls,
                          uint64_t next_uid,
                          bool random,
                          const struct GNUNET_HashCode *key,
-                         const struct GNUNET_HashCode *vhash,
                          enum GNUNET_BLOCK_Type type,
                          PluginDatumProcessor proc,
                          void *proc_cls)
@@ -561,7 +555,6 @@ postgres_plugin_get_key (void *cls,
   uint32_t utype = type;
   uint16_t use_rvalue = random;
   uint16_t use_key = NULL != key;
-  uint16_t use_vhash = NULL != vhash;
   uint16_t use_type = GNUNET_BLOCK_TYPE_ANY != type;
   uint64_t rvalue;
   struct GNUNET_PQ_QueryParam params[] = {
@@ -570,8 +563,6 @@ postgres_plugin_get_key (void *cls,
     GNUNET_PQ_query_param_uint16 (&use_rvalue),
     GNUNET_PQ_query_param_auto_from_type (key),
     GNUNET_PQ_query_param_uint16 (&use_key),
-    GNUNET_PQ_query_param_auto_from_type (vhash),
-    GNUNET_PQ_query_param_uint16 (&use_vhash),
     GNUNET_PQ_query_param_uint32 (&utype),
     GNUNET_PQ_query_param_uint16 (&use_type),
     GNUNET_PQ_query_param_end
@@ -854,6 +845,74 @@ postgres_plugin_drop (void *cls)
 
 
 /**
+ * Remove a particular key in the datastore.
+ *
+ * @param cls closure
+ * @param key key for the content
+ * @param size number of bytes in data
+ * @param data content stored
+ * @param cont continuation called with success or failure status
+ * @param cont_cls continuation closure for @a cont
+ */
+static void
+postgres_plugin_remove_key (void *cls,
+                            const struct GNUNET_HashCode *key,
+                            uint32_t size,
+                            const void *data,
+                            PluginRemoveCont cont,
+                            void *cont_cls)
+{
+  struct Plugin *plugin = cls;
+  PGresult *ret;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (key),
+    GNUNET_PQ_query_param_fixed_size (data, size),
+    GNUNET_PQ_query_param_end
+  };
+  ret = GNUNET_PQ_exec_prepared (plugin->dbh,
+                                 "remove",
+                                 params);
+  if (GNUNET_OK !=
+      GNUNET_POSTGRES_check_result (plugin->dbh,
+                                    ret,
+                                    PGRES_COMMAND_OK,
+                                    "PQexecPrepared",
+                                    "remove"))
+  {
+    cont (cont_cls,
+          key,
+          size,
+          GNUNET_SYSERR,
+          _("Postgress exec failure"));
+    return;
+  }
+  /* What an awful API, this function really does return a string */
+  bool affected = 0 != strcmp ("0", PQcmdTuples (ret));
+  PQclear (ret);
+  if (!affected)
+  {
+    cont (cont_cls,
+          key,
+          size,
+          GNUNET_NO,
+          NULL);
+    return;
+  }
+  plugin->env->duc (plugin->env->cls,
+                    - (size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                   "datastore-postgres",
+                   "Deleted %u bytes from database\n",
+                   (unsigned int) size);
+  cont (cont_cls,
+        key,
+        size,
+        GNUNET_OK,
+        NULL);
+}
+
+
+/**
  * Entry point for the plugin.
  *
  * @param cls the `struct GNUNET_DATASTORE_PluginEnvironment*`
@@ -883,6 +942,7 @@ libgnunet_plugin_datastore_postgres_init (void *cls)
   api->get_zero_anonymity = &postgres_plugin_get_zero_anonymity;
   api->get_keys = &postgres_plugin_get_keys;
   api->drop = &postgres_plugin_drop;
+  api->remove_key = &postgres_plugin_remove_key;
   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
                    "datastore-postgres",
                    _("Postgres database running\n"));
diff --git a/src/datastore/plugin_datastore_sqlite.c 
b/src/datastore/plugin_datastore_sqlite.c
index 469dd7717..bcaf27d99 100644
--- a/src/datastore/plugin_datastore_sqlite.c
+++ b/src/datastore/plugin_datastore_sqlite.c
@@ -88,6 +88,11 @@ struct Plugin
   sqlite3 *dbh;
 
   /**
+   * Precompiled SQL for remove_key.
+   */
+  sqlite3_stmt *remove;
+
+  /**
    * Precompiled SQL for deletion.
    */
   sqlite3_stmt *delRow;
@@ -185,10 +190,6 @@ create_indices (sqlite3 * dbh)
                      NULL, NULL, NULL)) ||
       (SQLITE_OK !=
        sqlite3_exec (dbh,
-                     "CREATE INDEX IF NOT EXISTS idx_hash_vhash ON gn090 
(hash,vhash)",
-                     NULL, NULL, NULL)) ||
-      (SQLITE_OK !=
-       sqlite3_exec (dbh,
                      "CREATE INDEX IF NOT EXISTS idx_expire_repl ON gn090 
(expire ASC,repl DESC)",
                      NULL, NULL, NULL)) ||
       (SQLITE_OK !=
@@ -415,15 +416,21 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle 
*cfg,
                     "WHERE _ROWID_ >= ? AND "
                     "(rvalue >= ? OR 0 = ?) AND "
                     "(hash = ? OR 0 = ?) AND "
-                    "(vhash = ? OR 0 = ?) AND "
                     "(type = ? OR 0 = ?) "
                     "ORDER BY _ROWID_ ASC LIMIT 1",
                     &plugin->get)) ||
        (SQLITE_OK !=
         sq_prepare (plugin->dbh,
                     "DELETE FROM gn090 WHERE _ROWID_ = ?",
-                    &plugin->delRow))
-       )
+                    &plugin->delRow)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "DELETE FROM gn090 "
+                    "WHERE hash = ? AND "
+                    "value = ? "
+                    "LIMIT 1",
+                    &plugin->remove)) ||
+       false)
   {
     LOG_SQLITE (plugin,
                 GNUNET_ERROR_TYPE_ERROR,
@@ -448,6 +455,8 @@ database_shutdown (struct Plugin *plugin)
   sqlite3_stmt *stmt;
 #endif
 
+  if (NULL != plugin->remove)
+    sqlite3_finalize (plugin->remove);
   if (NULL != plugin->delRow)
     sqlite3_finalize (plugin->delRow);
   if (NULL != plugin->update)
@@ -845,15 +854,10 @@ sqlite_plugin_get_zero_anonymity (void *cls,
  * @param next_uid return the result with lowest uid >= next_uid
  * @param random if true, return a random result instead of using next_uid
  * @param key maybe NULL (to match all entries)
- * @param vhash hash of the value, maybe NULL (to
- *        match all values that have the right key).
- *        Note that for DBlocks there is no difference
- *        betwen key and vhash, but for other blocks
- *        there may be!
  * @param type entries of which type are relevant?
  *     Use 0 for any type.
- * @param proc function to call on each matching value;
- *        will be called once with a NULL value at the end
+ * @param proc function to call on the matching value;
+ *        will be called with NULL if nothing matches
  * @param proc_cls closure for @a proc
  */
 static void
@@ -861,7 +865,6 @@ sqlite_plugin_get_key (void *cls,
                        uint64_t next_uid,
                        bool random,
                        const struct GNUNET_HashCode *key,
-                       const struct GNUNET_HashCode *vhash,
                        enum GNUNET_BLOCK_Type type,
                        PluginDatumProcessor proc,
                        void *proc_cls)
@@ -872,15 +875,12 @@ sqlite_plugin_get_key (void *cls,
   uint32_t type32 = (uint32_t) type;
   uint16_t use_type = GNUNET_BLOCK_TYPE_ANY != type;
   uint16_t use_key = NULL != key;
-  uint16_t use_vhash = NULL != vhash;
   struct GNUNET_SQ_QueryParam params[] = {
     GNUNET_SQ_query_param_uint64 (&next_uid),
     GNUNET_SQ_query_param_uint64 (&rvalue),
     GNUNET_SQ_query_param_uint16 (&use_rvalue),
     GNUNET_SQ_query_param_auto_from_type (key),
     GNUNET_SQ_query_param_uint16 (&use_key),
-    GNUNET_SQ_query_param_auto_from_type (vhash),
-    GNUNET_SQ_query_param_uint16 (&use_vhash),
     GNUNET_SQ_query_param_uint32 (&type32),
     GNUNET_SQ_query_param_uint16 (&use_type),
     GNUNET_SQ_query_param_end
@@ -1186,6 +1186,79 @@ sqlite_plugin_drop (void *cls)
 
 
 /**
+ * Remove a particular key in the datastore.
+ *
+ * @param cls closure
+ * @param key key for the content
+ * @param size number of bytes in data
+ * @param data content stored
+ * @param cont continuation called with success or failure status
+ * @param cont_cls continuation closure for @a cont
+ */
+static void
+sqlite_plugin_remove_key (void *cls,
+                          const struct GNUNET_HashCode *key,
+                          uint32_t size,
+                          const void *data,
+                          PluginRemoveCont cont,
+                          void *cont_cls)
+{
+  struct Plugin *plugin = cls;
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_auto_from_type (key),
+    GNUNET_SQ_query_param_fixed_size (data, size),
+    GNUNET_SQ_query_param_end
+  };
+
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->remove,
+                      params))
+  {
+    cont (cont_cls,
+          key,
+          size,
+          GNUNET_SYSERR,
+          "bind failed");
+    return;
+  }
+  if (SQLITE_DONE != sqlite3_step (plugin->remove))
+  {
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                "sqlite3_step");
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->remove);
+    cont (cont_cls,
+          key,
+          size,
+          GNUNET_SYSERR,
+          "sqlite3_step failed");
+    return;
+  }
+  int changes = sqlite3_changes (plugin->dbh);
+  GNUNET_SQ_reset (plugin->dbh,
+                   plugin->remove);
+  if (0 == changes)
+  {
+    cont (cont_cls,
+          key,
+          size,
+          GNUNET_NO,
+          NULL);
+    return;
+  }
+  if (NULL != plugin->env->duc)
+    plugin->env->duc (plugin->env->cls,
+                      -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
+  cont (cont_cls,
+        key,
+        size,
+        GNUNET_OK,
+        NULL);
+}
+
+
+/**
  * Get an estimate of how much space the database is
  * currently using.
  *
@@ -1286,6 +1359,7 @@ libgnunet_plugin_datastore_sqlite_init (void *cls)
   api->get_zero_anonymity = &sqlite_plugin_get_zero_anonymity;
   api->get_keys = &sqlite_plugin_get_keys;
   api->drop = &sqlite_plugin_drop;
+  api->remove_key = &sqlite_plugin_remove_key;
   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
                    "sqlite",
                    _("Sqlite database running\n"));
diff --git a/src/datastore/plugin_datastore_template.c 
b/src/datastore/plugin_datastore_template.c
index 704d586bc..16bda45d4 100644
--- a/src/datastore/plugin_datastore_template.c
+++ b/src/datastore/plugin_datastore_template.c
@@ -99,11 +99,6 @@ template_plugin_put (void *cls,
  * @param next_uid return the result with lowest uid >= next_uid
  * @param random if true, return a random result instead of using next_uid
  * @param key maybe NULL (to match all entries)
- * @param vhash hash of the value, maybe NULL (to
- *        match all values that have the right key).
- *        Note that for DBlocks there is no difference
- *        betwen key and vhash, but for other blocks
- *        there may be!
  * @param type entries of which type are relevant?
  *     Use 0 for any type.
  * @param proc function to call on each matching value;
@@ -111,10 +106,12 @@ template_plugin_put (void *cls,
  * @param proc_cls closure for proc
  */
 static void
-template_plugin_get_key (void *cls, uint64_t next_uid, bool random,
-                         const struct GNUNET_HashCode * key,
-                         const struct GNUNET_HashCode * vhash,
-                         enum GNUNET_BLOCK_Type type, PluginDatumProcessor 
proc,
+template_plugin_get_key (void *cls,
+                         uint64_t next_uid,
+                         bool random,
+                         const struct GNUNET_HashCode *key,
+                         enum GNUNET_BLOCK_Type type,
+                         PluginDatumProcessor proc,
                          void *proc_cls)
 {
   GNUNET_break (0);
@@ -204,6 +201,29 @@ template_get_keys (void *cls,
 
 
 /**
+ * Remove a particular key in the datastore.
+ *
+ * @param cls closure
+ * @param key key for the content
+ * @param size number of bytes in data
+ * @param data content stored
+ * @param cont continuation called with success or failure status
+ * @param cont_cls continuation closure for @a cont
+ */
+static void
+template_plugin_remove_key (void *cls,
+                            const struct GNUNET_HashCode *key,
+                            uint32_t size,
+                            const void *data,
+                            PluginRemoveCont cont,
+                            void *cont_cls)
+{
+  GNUNET_break (0);
+  cont (cont_cls, key, size, GNUNET_SYSERR, "not implemented");
+}
+
+
+/**
  * Entry point for the plugin.
  *
  * @param cls the "struct GNUNET_DATASTORE_PluginEnvironment*"
@@ -228,6 +248,7 @@ libgnunet_plugin_datastore_template_init (void *cls)
   api->get_zero_anonymity = &template_plugin_get_zero_anonymity;
   api->drop = &template_plugin_drop;
   api->get_keys = &template_get_keys;
+  api->remove_key = &template_plugin_remove_key;
   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "template",
                    _("Template database running\n"));
   return api;
diff --git a/src/datastore/test_plugin_datastore.c 
b/src/datastore/test_plugin_datastore.c
index 0c34a5f66..d460daed7 100644
--- a/src/datastore/test_plugin_datastore.c
+++ b/src/datastore/test_plugin_datastore.c
@@ -52,6 +52,7 @@ enum RunPhase
   RP_ITER_ZERO,
   RP_REPL_GET,
   RP_EXPI_GET,
+  RP_REMOVE,
   RP_DROP
 };
 
@@ -153,7 +154,7 @@ do_put (struct CpsRunContext *crc)
   /* most content is 32k */
   size = 32 * 1024;
 
-  if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16) == 0)   /* but 
some of it is less! */
+  if (0 != i && GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16) == 
0)   /* but some of it is less! */
     size = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 32 * 1024);
   size = size - (size & 7);     /* always multiple of 8 */
 
@@ -220,6 +221,25 @@ iterate_one_shot (void *cls,
 }
 
 
+static void
+remove_continuation (void *cls,
+                     const struct GNUNET_HashCode *key,
+                     uint32_t size,
+                     int status,
+                     const char *msg)
+{
+  struct CpsRunContext *crc = cls;
+
+  GNUNET_assert (NULL != key);
+  GNUNET_assert (32768 == size);
+  GNUNET_assert (GNUNET_OK == status);
+  GNUNET_assert (NULL == msg);
+  crc->phase++;
+  GNUNET_SCHEDULER_add_now (&test,
+                            crc);
+}
+
+
 /**
  * Function called when the service shuts
  * down.  Unloads our datastore plugin.
@@ -303,7 +323,6 @@ test (void *cls)
                        0,
                        false,
                        &key,
-                       NULL,
                        GNUNET_BLOCK_TYPE_ANY,
                        &iterate_one_shot,
                        crc);
@@ -324,6 +343,23 @@ test (void *cls)
   case RP_EXPI_GET:
     crc->api->get_expiration (crc->api->cls, &iterate_one_shot, crc);
     break;
+  case RP_REMOVE:
+    {
+      struct GNUNET_HashCode key;
+      uint32_t size = 32768;
+      char value[size];
+
+      gen_key (0, &key);
+      memset (value, 0, size);
+      value[0] = crc->i;
+      crc->api->remove_key (crc->api->cls,
+                            &key,
+                            size,
+                            value,
+                            &remove_continuation,
+                            crc);
+      break;
+    }
   case RP_DROP:
     crc->api->drop (crc->api->cls);
     GNUNET_SCHEDULER_add_now (&cleaning_task, crc);
diff --git a/src/include/gnunet_datastore_plugin.h 
b/src/include/gnunet_datastore_plugin.h
index 28c8241b1..36a3fbec2 100644
--- a/src/include/gnunet_datastore_plugin.h
+++ b/src/include/gnunet_datastore_plugin.h
@@ -212,11 +212,6 @@ typedef void
  * @param next_uid return the result with lowest uid >= next_uid
  * @param random if true, return a random result instead of using next_uid
  * @param key maybe NULL (to match all entries)
- * @param vhash hash of the value, maybe NULL (to
- *        match all values that have the right key).
- *        Note that for DBlocks there is no difference
- *        betwen key and vhash, but for other blocks
- *        there may be!
  * @param type entries of which type are relevant?
  *     Use 0 for any type.
  * @param proc function to call on the matching value;
@@ -228,13 +223,49 @@ typedef void
                  uint64_t next_uid,
                  bool random,
                  const struct GNUNET_HashCode *key,
-                 const struct GNUNET_HashCode *vhash,
                  enum GNUNET_BLOCK_Type type,
                  PluginDatumProcessor proc,
                  void *proc_cls);
 
 
 /**
+ * Remove continuation.
+ *
+ * @param cls closure
+ * @param key key for the content removed
+ * @param size number of bytes removed
+ * @param status #GNUNET_OK if removed, #GNUNET_NO if not found,
+ *        or #GNUNET_SYSERROR if error
+ * @param msg error message on error
+ */
+typedef void
+(*PluginRemoveCont) (void *cls,
+                     const struct GNUNET_HashCode *key,
+                     uint32_t size,
+                     int status,
+                     const char *msg);
+
+
+/**
+ * Remove a particular key in the datastore.
+ *
+ * @param cls closure
+ * @param key key for the content
+ * @param size number of bytes in data
+ * @param data content stored
+ * @param cont continuation called with success or failure status
+ * @param cont_cls continuation closure for @a cont
+ */
+typedef void
+(*PluginRemoveKey) (void *cls,
+                    const struct GNUNET_HashCode *key,
+                    uint32_t size,
+                    const void *data,
+                    PluginRemoveCont cont,
+                    void *cont_cls);
+
+
+/**
  * Get a random item (additional constraints may apply depending on
  * the specific implementation).  Calls @a proc with all values ZERO or
  * NULL if no item applies, otherwise @a proc is called once and only
@@ -339,6 +370,10 @@ struct GNUNET_DATASTORE_PluginFunctions
    */
   PluginGetKeys get_keys;
 
+  /**
+   * Function to remove an item from the database.
+   */
+  PluginRemoveKey remove_key;
 };
 
 #endif

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]