add nick name for cached records
[oweals/gnunet.git] / src / datastore / gnunet-service-datastore.c
index c01de5891830ea6001b19d9ec207d23b189a8302..7c4c47e9019ad2feb8f4f0f0f198cbd8fdeea811 100644 (file)
@@ -4,7 +4,7 @@
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
  */
 #define MIN_EXPIRE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
 
-
-#define QUOTA_STAT_NAME gettext_noop ("# bytes used in file-sharing datastore")
+/**
+ * Name under which we store current space consumption.
+ */
+static char *quota_stat_name;
 
 /**
  * After how many payload-changing operations
@@ -149,6 +151,11 @@ static unsigned long long quota;
  */
 static int do_drop;
 
+/**
+ * Name of our plugin.
+ */
+static char *plugin_name;
+
 /**
  * How much space are we using for the cache?  (space available for
  * insertions that will be instantly reclaimed by discarding less
@@ -191,6 +198,13 @@ static GNUNET_SCHEDULER_TaskIdentifier expired_kill_task;
  */
 const struct GNUNET_CONFIGURATION_Handle *cfg;
 
+/**
+ * Minimum time that content should have to not be discarded instantly
+ * (time stamp of any content that we've been discarding recently to
+ * stay below the quota).  FOREVER if we had to expire content with
+ * non-zero priority.
+ */
+static struct GNUNET_TIME_Absolute min_expiration;
 
 /**
  * Handle for reporting statistics.
@@ -199,13 +213,14 @@ static struct GNUNET_STATISTICS_Handle *stats;
 
 
 /**
- * Synchronize our utilization statistics with the 
+ * Synchronize our utilization statistics with the
  * statistics service.
  */
 static void
 sync_stats ()
 {
-  GNUNET_STATISTICS_set (stats, QUOTA_STAT_NAME, payload, GNUNET_YES);
+  GNUNET_STATISTICS_set (stats, quota_stat_name, payload, GNUNET_YES);
+  GNUNET_STATISTICS_set (stats, "# utilization by current datastore", payload, GNUNET_NO);
   lastSync = 0;
 }
 
@@ -235,7 +250,7 @@ struct TransmitCallbackContext
   /**
    * Handle for the transmission request.
    */
-  struct GNUNET_CONNECTION_TransmitHandle *th;
+  struct GNUNET_SERVER_TransmitHandle *th;
 
   /**
    * Client that we are transmitting to.
@@ -301,45 +316,45 @@ delete_expired (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
  *         GNUNET_NO to delete the item and continue (if supported)
  */
 static int
-expired_processor (void *cls,
-                   const GNUNET_HashCode * key,
-                   uint32_t size,
-                   const void *data,
-                   enum GNUNET_BLOCK_Type type,
-                   uint32_t priority,
-                   uint32_t anonymity,
+expired_processor (void *cls, const struct GNUNET_HashCode * key, uint32_t size,
+                   const void *data, enum GNUNET_BLOCK_Type type,
+                   uint32_t priority, uint32_t anonymity,
                    struct GNUNET_TIME_Absolute expiration, uint64_t uid)
 {
   struct GNUNET_TIME_Absolute now;
 
   if (key == NULL)
   {
-    expired_kill_task
-        = GNUNET_SCHEDULER_add_delayed (MAX_EXPIRE_DELAY,
-                                        &delete_expired, NULL);
+    expired_kill_task =
+        GNUNET_SCHEDULER_add_delayed_with_priority (MAX_EXPIRE_DELAY,
+                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
+                                                   &delete_expired, NULL);
     return GNUNET_SYSERR;
   }
   now = GNUNET_TIME_absolute_get ();
-  if (expiration.abs_value > now.abs_value)
+  if (expiration.abs_value_us > now.abs_value_us)
   {
     /* finished processing */
-    expired_kill_task
-        = GNUNET_SCHEDULER_add_delayed (MAX_EXPIRE_DELAY,
-                                        &delete_expired, NULL);
+    expired_kill_task =
+        GNUNET_SCHEDULER_add_delayed_with_priority (MAX_EXPIRE_DELAY,
+                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
+                                                   &delete_expired, NULL);
     return GNUNET_SYSERR;
   }
-#if DEBUG_DATASTORE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Deleting content `%s' of type %u that expired %llu ms ago\n",
-              GNUNET_h2s (key),
-              type,
-              (unsigned long long) (now.abs_value - expiration.abs_value));
-#endif
-  GNUNET_STATISTICS_update (stats,
-                            gettext_noop ("# bytes expired"), size, GNUNET_YES);
+              "Deleting content `%s' of type %u that expired %s ago\n",
+              GNUNET_h2s (key), type,
+             GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_difference (expiration,
+                                                                                          now),
+                                                     GNUNET_YES));
+  min_expiration = now;
+  GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes expired"), size,
+                            GNUNET_YES);
   GNUNET_CONTAINER_bloomfilter_remove (filter, key);
-  expired_kill_task
-      = GNUNET_SCHEDULER_add_delayed (MIN_EXPIRE_DELAY, &delete_expired, NULL);
+  expired_kill_task =
+      GNUNET_SCHEDULER_add_delayed_with_priority (MIN_EXPIRE_DELAY,
+                                                 GNUNET_SCHEDULER_PRIORITY_IDLE,
+                                                 &delete_expired, NULL);
   return GNUNET_NO;
 }
 
@@ -381,29 +396,31 @@ delete_expired (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  *         GNUNET_NO to delete the item and continue (if supported)
  */
 static int
-quota_processor (void *cls,
-                 const GNUNET_HashCode * key,
-                 uint32_t size,
-                 const void *data,
-                 enum GNUNET_BLOCK_Type type,
-                 uint32_t priority,
-                 uint32_t anonymity,
+quota_processor (void *cls, const struct GNUNET_HashCode * key, uint32_t size,
+                 const void *data, enum GNUNET_BLOCK_Type type,
+                 uint32_t priority, uint32_t anonymity,
                  struct GNUNET_TIME_Absolute expiration, uint64_t uid)
 {
   unsigned long long *need = cls;
 
   if (NULL == key)
     return GNUNET_SYSERR;
-#if DEBUG_DATASTORE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Deleting %llu bytes of low-priority content `%s' of type %u (still trying to free another %llu bytes)\n",
+              "Deleting %llu bytes of low-priority (%u) content `%s' of type %u at %s prior to expiration (still trying to free another %llu bytes)\n",
               (unsigned long long) (size + GNUNET_DATASTORE_ENTRY_OVERHEAD),
-              GNUNET_h2s (key), type, *need);
-#endif
+             (unsigned int) priority,
+              GNUNET_h2s (key), type,
+             GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (expiration),
+                                                     GNUNET_YES),
+             *need);
   if (size + GNUNET_DATASTORE_ENTRY_OVERHEAD > *need)
     *need = 0;
   else
     *need -= size + GNUNET_DATASTORE_ENTRY_OVERHEAD;
+  if (priority > 0)
+    min_expiration = GNUNET_TIME_UNIT_FOREVER_ABS;
+  else
+    min_expiration = expiration;
   GNUNET_STATISTICS_update (stats,
                             gettext_noop ("# bytes purged (low-priority)"),
                             size, GNUNET_YES);
@@ -429,10 +446,8 @@ manage_space (unsigned long long need)
 {
   unsigned long long last;
 
-#if DEBUG_DATASTORE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Asked to free up %llu bytes of cache space\n", need);
-#endif
   last = 0;
   while ((need > 0) && (last != need))
   {
@@ -495,10 +510,8 @@ transmit (struct GNUNET_SERVER_Client *client, struct GNUNET_MessageHeader *msg)
 
   if (GNUNET_YES == cleaning_done)
   {
-#if DEBUG_DATASTORE
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "Shutdown in progress, aborting transmission.\n");
-#endif
+                _("Shutdown in progress, aborting transmission.\n"));
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     GNUNET_free (msg);
     return;
@@ -507,10 +520,10 @@ transmit (struct GNUNET_SERVER_Client *client, struct GNUNET_MessageHeader *msg)
   tcc->msg = msg;
   tcc->client = client;
   if (NULL ==
-      (tcc->th = GNUNET_SERVER_notify_transmit_ready (client,
-                                                      ntohs (msg->size),
-                                                      GNUNET_TIME_UNIT_FOREVER_REL,
-                                                      &transmit_callback, tcc)))
+      (tcc->th =
+       GNUNET_SERVER_notify_transmit_ready (client, ntohs (msg->size),
+                                            GNUNET_TIME_UNIT_FOREVER_REL,
+                                            &transmit_callback, tcc)))
   {
     GNUNET_break (0);
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
@@ -536,16 +549,15 @@ transmit_status (struct GNUNET_SERVER_Client *client, int code, const char *msg)
   struct StatusMessage *sm;
   size_t slen;
 
-#if DEBUG_DATASTORE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Transmitting `%s' message with value %d and message `%s'\n",
               "STATUS", code, msg != NULL ? msg : "(none)");
-#endif
   slen = (msg == NULL) ? 0 : strlen (msg) + 1;
   sm = GNUNET_malloc (sizeof (struct StatusMessage) + slen);
   sm->header.size = htons (sizeof (struct StatusMessage) + slen);
   sm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_STATUS);
   sm->status = htonl (code);
+  sm->min_expiration = GNUNET_TIME_absolute_hton (min_expiration);
   if (slen > 0)
     memcpy (&sm[1], msg, slen);
   transmit (client, &sm->header);
@@ -572,14 +584,10 @@ transmit_status (struct GNUNET_SERVER_Client *client, int code, const char *msg)
  *         GNUNET_NO to delete the item and continue (if supported)
  */
 static int
-transmit_item (void *cls,
-               const GNUNET_HashCode * key,
-               uint32_t size,
-               const void *data,
-               enum GNUNET_BLOCK_Type type,
-               uint32_t priority,
-               uint32_t anonymity,
-               struct GNUNET_TIME_Absolute expiration, uint64_t uid)
+transmit_item (void *cls, const struct GNUNET_HashCode * key, uint32_t size,
+               const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority,
+               uint32_t anonymity, struct GNUNET_TIME_Absolute expiration,
+               uint64_t uid)
 {
   struct GNUNET_SERVER_Client *client = cls;
   struct GNUNET_MessageHeader *end;
@@ -588,10 +596,8 @@ transmit_item (void *cls,
   if (key == NULL)
   {
     /* transmit 'DATA_END' */
-#if DEBUG_DATASTORE
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Transmitting `%s' message\n", "DATA_END");
-#endif
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' message\n",
+                "DATA_END");
     end = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader));
     end->size = htons (sizeof (struct GNUNET_MessageHeader));
     end->type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_DATA_END);
@@ -615,17 +621,14 @@ transmit_item (void *cls,
   dm->uid = GNUNET_htonll (uid);
   dm->key = *key;
   memcpy (&dm[1], data, size);
-#if DEBUG_DATASTORE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Transmitting `%s' message for `%s' of type %u with expiration %llu (now: %llu)\n",
-              "DATA",
-              GNUNET_h2s (key),
-              type,
-              (unsigned long long) expiration.abs_value,
-              (unsigned long long) GNUNET_TIME_absolute_get ().abs_value);
-#endif
-  GNUNET_STATISTICS_update (stats,
-                            gettext_noop ("# results found"), 1, GNUNET_NO);
+              "Transmitting `%s' message for `%s' of type %u with expiration %s (in: %s)\n",
+              "DATA", GNUNET_h2s (key), type,
+              GNUNET_STRINGS_absolute_time_to_string (expiration),
+              GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (expiration),
+                                                     GNUNET_YES));
+  GNUNET_STATISTICS_update (stats, gettext_noop ("# results found"), 1,
+                            GNUNET_NO);
   transmit (client, &dm->header);
   GNUNET_SERVER_client_drop (client);
   return GNUNET_OK;
@@ -640,8 +643,7 @@ transmit_item (void *cls,
  * @param message the actual message
  */
 static void
-handle_reserve (void *cls,
-                struct GNUNET_SERVER_Client *client,
+handle_reserve (void *cls, struct GNUNET_SERVER_Client *client,
                 const struct GNUNET_MessageHeader *message)
 {
   /**
@@ -656,9 +658,7 @@ handle_reserve (void *cls,
   uint64_t amount;
   uint32_t entries;
 
-#if DEBUG_DATASTORE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request\n", "RESERVE");
-#endif
   amount = GNUNET_ntohll (msg->amount);
   entries = ntohl (msg->entries);
   used = payload + reserved;
@@ -696,8 +696,8 @@ handle_reserve (void *cls,
     return;
   }
   reserved += req;
-  GNUNET_STATISTICS_set (stats,
-                         gettext_noop ("# reserved"), reserved, GNUNET_NO);
+  GNUNET_STATISTICS_set (stats, gettext_noop ("# reserved"), reserved,
+                         GNUNET_NO);
   e = GNUNET_malloc (sizeof (struct ReservationList));
   e->next = reservations;
   reservations = e;
@@ -719,8 +719,7 @@ handle_reserve (void *cls,
  * @param message the actual message
  */
 static void
-handle_release_reserve (void *cls,
-                        struct GNUNET_SERVER_Client *client,
+handle_release_reserve (void *cls, struct GNUNET_SERVER_Client *client,
                         const struct GNUNET_MessageHeader *message)
 {
   const struct ReleaseReserveMessage *msg =
@@ -731,10 +730,8 @@ handle_release_reserve (void *cls,
   int rid = ntohl (msg->rid);
   unsigned long long rem;
 
-#if DEBUG_DATASTORE
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Processing `%s' request\n", "RELEASE_RESERVE");
-#endif
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request\n",
+              "RELEASE_RESERVE");
   next = reservations;
   prev = NULL;
   while (NULL != (pos = next))
@@ -751,13 +748,11 @@ handle_release_reserve (void *cls,
           ((unsigned long long) GNUNET_DATASTORE_ENTRY_OVERHEAD) * pos->entries;
       GNUNET_assert (reserved >= rem);
       reserved -= rem;
-      GNUNET_STATISTICS_set (stats,
-                             gettext_noop ("# reserved"), reserved, GNUNET_NO);
-#if DEBUG_DATASTORE
+      GNUNET_STATISTICS_set (stats, gettext_noop ("# reserved"), reserved,
+                             GNUNET_NO);
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Returning %llu remaining reserved bytes to storage pool\n",
                   rem);
-#endif
       GNUNET_free (pos);
       transmit_status (client, GNUNET_OK, NULL);
       return;
@@ -820,6 +815,9 @@ struct PutContext
 
 /**
  * Actually put the data message.
+ *
+ * @param client sender of the message
+ * @param dm message with the data to store
  */
 static void
 execute_put (struct GNUNET_SERVER_Client *client, const struct DataMessage *dm)
@@ -830,26 +828,19 @@ execute_put (struct GNUNET_SERVER_Client *client, const struct DataMessage *dm)
 
   size = ntohl (dm->size);
   msg = NULL;
-  ret = plugin->api->put (plugin->api->cls,
-                          &dm->key,
-                          size,
-                          &dm[1],
-                          ntohl (dm->type),
-                          ntohl (dm->priority),
-                          ntohl (dm->anonymity),
-                          ntohl (dm->replication),
-                          GNUNET_TIME_absolute_ntoh (dm->expiration), &msg);
+  ret =
+      plugin->api->put (plugin->api->cls, &dm->key, size, &dm[1],
+                        ntohl (dm->type), ntohl (dm->priority),
+                        ntohl (dm->anonymity), ntohl (dm->replication),
+                        GNUNET_TIME_absolute_ntoh (dm->expiration), &msg);
   if (GNUNET_OK == ret)
   {
-    GNUNET_STATISTICS_update (stats,
-                              gettext_noop ("# bytes stored"),
-                              size, GNUNET_YES);
+    GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes stored"), size,
+                              GNUNET_YES);
     GNUNET_CONTAINER_bloomfilter_add (filter, &dm->key);
-#if DEBUG_DATASTORE
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Successfully stored %u bytes of type %u under key `%s'\n",
                 size, ntohl (dm->type), GNUNET_h2s (&dm->key));
-#endif
   }
   transmit_status (client, ret, msg);
   GNUNET_free_non_null (msg);
@@ -881,17 +872,13 @@ execute_put (struct GNUNET_SERVER_Client *client, const struct DataMessage *dm)
  *        maybe 0 if no unique identifier is available
  *
  * @return GNUNET_OK usually
- *         GNUNET_NO to delete the item 
+ *         GNUNET_NO to delete the item
  */
 static int
-check_present (void *cls,
-               const GNUNET_HashCode * key,
-               uint32_t size,
-               const void *data,
-               enum GNUNET_BLOCK_Type type,
-               uint32_t priority,
-               uint32_t anonymity,
-               struct GNUNET_TIME_Absolute expiration, uint64_t uid)
+check_present (void *cls, const struct GNUNET_HashCode * key, uint32_t size,
+               const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority,
+               uint32_t anonymity, struct GNUNET_TIME_Absolute expiration,
+               uint64_t uid)
 {
   struct PutContext *pc = cls;
   const struct DataMessage *dm;
@@ -905,19 +892,17 @@ check_present (void *cls,
     return GNUNET_OK;
   }
   if ((GNUNET_BLOCK_TYPE_FS_DBLOCK == type) ||
-      (GNUNET_BLOCK_TYPE_FS_IBLOCK == type) ||
-      ((size == ntohl (dm->size)) && (0 == memcmp (&dm[1], data, size))))
+      (GNUNET_BLOCK_TYPE_FS_IBLOCK == type) || ((size == ntohl (dm->size)) &&
+                                                (0 ==
+                                                 memcmp (&dm[1], data, size))))
   {
-#if DEBUG_MYSQL
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Result already present in datastore\n");
-#endif
     /* FIXME: change API to allow increasing 'replication' counter */
     if ((ntohl (dm->priority) > 0) ||
-        (GNUNET_TIME_absolute_ntoh (dm->expiration).abs_value >
-         expiration.abs_value))
-      plugin->api->update (plugin->api->cls,
-                           uid,
+        (GNUNET_TIME_absolute_ntoh (dm->expiration).abs_value_us >
+         expiration.abs_value_us))
+      plugin->api->update (plugin->api->cls, uid,
                            (int32_t) ntohl (dm->priority),
                            GNUNET_TIME_absolute_ntoh (dm->expiration), NULL);
     transmit_status (pc->client, GNUNET_NO, NULL);
@@ -942,15 +927,14 @@ check_present (void *cls,
  * @param message the actual message
  */
 static void
-handle_put (void *cls,
-            struct GNUNET_SERVER_Client *client,
+handle_put (void *cls, struct GNUNET_SERVER_Client *client,
             const struct GNUNET_MessageHeader *message)
 {
   const struct DataMessage *dm = check_data (message);
   int rid;
   struct ReservationList *pos;
   struct PutContext *pc;
-  GNUNET_HashCode vhash;
+  struct GNUNET_HashCode vhash;
   uint32_t size;
 
   if ((dm == NULL) || (ntohl (dm->type) == 0))
@@ -959,11 +943,9 @@ handle_put (void *cls,
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-#if DEBUG_DATASTORE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Processing `%s' request for `%s' of type %u\n",
-              "PUT", GNUNET_h2s (&dm->key), ntohl (dm->type));
-#endif
+              "Processing `%s' request for `%s' of type %u\n", "PUT",
+              GNUNET_h2s (&dm->key), ntohl (dm->type));
   rid = ntohl (dm->rid);
   size = ntohl (dm->size);
   if (rid > 0)
@@ -979,8 +961,8 @@ handle_put (void *cls,
       pos->entries--;
       pos->amount -= size;
       reserved -= (size + GNUNET_DATASTORE_ENTRY_OVERHEAD);
-      GNUNET_STATISTICS_set (stats,
-                             gettext_noop ("# reserved"), reserved, GNUNET_NO);
+      GNUNET_STATISTICS_set (stats, gettext_noop ("# reserved"), reserved,
+                             GNUNET_NO);
     }
   }
   if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (filter, &dm->key))
@@ -991,10 +973,8 @@ handle_put (void *cls,
     pc->client = client;
     GNUNET_SERVER_client_keep (client);
     memcpy (&pc[1], dm, size + sizeof (struct DataMessage));
-    plugin->api->get_key (plugin->api->cls,
-                          0,
-                          &dm->key,
-                          &vhash, ntohl (dm->type), &check_present, pc);
+    plugin->api->get_key (plugin->api->cls, 0, &dm->key, &vhash,
+                          ntohl (dm->type), &check_present, pc);
     return;
   }
   execute_put (client, dm);
@@ -1009,8 +989,7 @@ handle_put (void *cls,
  * @param message the actual message
  */
 static void
-handle_get (void *cls,
-            struct GNUNET_SERVER_Client *client,
+handle_get (void *cls, struct GNUNET_SERVER_Client *client,
             const struct GNUNET_MessageHeader *message)
 {
   const struct GetMessage *msg;
@@ -1018,31 +997,26 @@ handle_get (void *cls,
 
   size = ntohs (message->size);
   if ((size != sizeof (struct GetMessage)) &&
-      (size != sizeof (struct GetMessage) - sizeof (GNUNET_HashCode)))
+      (size != sizeof (struct GetMessage) - sizeof (struct GNUNET_HashCode)))
   {
     GNUNET_break (0);
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
   msg = (const struct GetMessage *) message;
-#if DEBUG_DATASTORE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Processing `%s' request for `%s' of type %u\n",
-              "GET", GNUNET_h2s (&msg->key), ntohl (msg->type));
-#endif
-  GNUNET_STATISTICS_update (stats,
-                            gettext_noop ("# GET requests received"),
-                            1, GNUNET_NO);
+              "Processing `%s' request for `%s' of type %u\n", "GET",
+              GNUNET_h2s (&msg->key), ntohl (msg->type));
+  GNUNET_STATISTICS_update (stats, gettext_noop ("# GET requests received"), 1,
+                            GNUNET_NO);
   GNUNET_SERVER_client_keep (client);
   if ((size == sizeof (struct GetMessage)) &&
       (GNUNET_YES != GNUNET_CONTAINER_bloomfilter_test (filter, &msg->key)))
   {
     /* don't bother database... */
-#if DEBUG_DATASTORE
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Empty result set for `%s' request for `%s' (bloomfilter).\n",
                 "GET", GNUNET_h2s (&msg->key));
-#endif
     GNUNET_STATISTICS_update (stats,
                               gettext_noop
                               ("# requests filtered by bloomfilter"), 1,
@@ -1051,8 +1025,7 @@ handle_get (void *cls,
                    0);
     return;
   }
-  plugin->api->get_key (plugin->api->cls,
-                        GNUNET_ntohll (msg->offset),
+  plugin->api->get_key (plugin->api->cls, GNUNET_ntohll (msg->offset),
                         ((size ==
                           sizeof (struct GetMessage)) ? &msg->key : NULL), NULL,
                         ntohl (msg->type), &transmit_item, client);
@@ -1067,29 +1040,23 @@ handle_get (void *cls,
  * @param message the actual message
  */
 static void
-handle_update (void *cls,
-               struct GNUNET_SERVER_Client *client,
+handle_update (void *cls, struct GNUNET_SERVER_Client *client,
                const struct GNUNET_MessageHeader *message)
 {
   const struct UpdateMessage *msg;
   int ret;
   char *emsg;
 
-  GNUNET_STATISTICS_update (stats,
-                            gettext_noop ("# UPDATE requests received"),
+  GNUNET_STATISTICS_update (stats, gettext_noop ("# UPDATE requests received"),
                             1, GNUNET_NO);
   msg = (const struct UpdateMessage *) message;
   emsg = NULL;
-#if DEBUG_DATASTORE
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Processing `%s' request for %llu\n",
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request for %llu\n",
               "UPDATE", (unsigned long long) GNUNET_ntohll (msg->uid));
-#endif
-  ret = plugin->api->update (plugin->api->cls,
-                             GNUNET_ntohll (msg->uid),
-                             (int32_t) ntohl (msg->priority),
-                             GNUNET_TIME_absolute_ntoh (msg->expiration),
-                             &emsg);
+  ret =
+      plugin->api->update (plugin->api->cls, GNUNET_ntohll (msg->uid),
+                           (int32_t) ntohl (msg->priority),
+                           GNUNET_TIME_absolute_ntoh (msg->expiration), &emsg);
   transmit_status (client, ret, emsg);
   GNUNET_free_non_null (emsg);
 }
@@ -1103,14 +1070,11 @@ handle_update (void *cls,
  * @param message the actual message
  */
 static void
-handle_get_replication (void *cls,
-                        struct GNUNET_SERVER_Client *client,
+handle_get_replication (void *cls, struct GNUNET_SERVER_Client *client,
                         const struct GNUNET_MessageHeader *message)
 {
-#if DEBUG_DATASTORE
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Processing `%s' request\n", "GET_REPLICATION");
-#endif
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request\n",
+              "GET_REPLICATION");
   GNUNET_STATISTICS_update (stats,
                             gettext_noop
                             ("# GET REPLICATION requests received"), 1,
@@ -1128,8 +1092,7 @@ handle_get_replication (void *cls,
  * @param message the actual message
  */
 static void
-handle_get_zero_anonymity (void *cls,
-                           struct GNUNET_SERVER_Client *client,
+handle_get_zero_anonymity (void *cls, struct GNUNET_SERVER_Client *client,
                            const struct GNUNET_MessageHeader *message)
 {
   const struct GetZeroAnonymityMessage *msg =
@@ -1143,18 +1106,16 @@ handle_get_zero_anonymity (void *cls,
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-#if DEBUG_DATASTORE
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Processing `%s' request\n", "GET_ZERO_ANONYMITY");
-#endif
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request\n",
+              "GET_ZERO_ANONYMITY");
   GNUNET_STATISTICS_update (stats,
                             gettext_noop
                             ("# GET ZERO ANONYMITY requests received"), 1,
                             GNUNET_NO);
   GNUNET_SERVER_client_keep (client);
   plugin->api->get_zero_anonymity (plugin->api->cls,
-                                   GNUNET_ntohll (msg->offset),
-                                   type, &transmit_item, client);
+                                   GNUNET_ntohll (msg->offset), type,
+                                   &transmit_item, client);
 }
 
 
@@ -1163,32 +1124,24 @@ handle_get_zero_anonymity (void *cls,
  * in to be deleted (by returning GNUNET_NO).
  */
 static int
-remove_callback (void *cls,
-                 const GNUNET_HashCode * key,
-                 uint32_t size,
-                 const void *data,
-                 enum GNUNET_BLOCK_Type type,
-                 uint32_t priority,
-                 uint32_t anonymity,
+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,
                  struct GNUNET_TIME_Absolute expiration, uint64_t uid)
 {
   struct GNUNET_SERVER_Client *client = cls;
 
   if (key == NULL)
   {
-#if DEBUG_DATASTORE
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "No further matches for `%s' request.\n", "REMOVE");
-#endif
     transmit_status (client, GNUNET_NO, _("Content not found"));
     GNUNET_SERVER_client_drop (client);
     return GNUNET_OK;           /* last item */
   }
-#if DEBUG_DATASTORE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Item %llu matches `%s' request for key `%s' and type %u.\n",
               (unsigned long long) uid, "REMOVE", GNUNET_h2s (key), type);
-#endif
   GNUNET_STATISTICS_update (stats,
                             gettext_noop ("# bytes removed (explicit request)"),
                             size, GNUNET_YES);
@@ -1207,12 +1160,11 @@ remove_callback (void *cls,
  * @param message the actual message
  */
 static void
-handle_remove (void *cls,
-               struct GNUNET_SERVER_Client *client,
+handle_remove (void *cls, struct GNUNET_SERVER_Client *client,
                const struct GNUNET_MessageHeader *message)
 {
   const struct DataMessage *dm = check_data (message);
-  GNUNET_HashCode vhash;
+  struct GNUNET_HashCode vhash;
 
   if (dm == NULL)
   {
@@ -1220,20 +1172,14 @@ handle_remove (void *cls,
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-#if DEBUG_DATASTORE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Processing `%s' request for `%s' of type %u\n",
-              "REMOVE", GNUNET_h2s (&dm->key), ntohl (dm->type));
-#endif
-  GNUNET_STATISTICS_update (stats,
-                            gettext_noop ("# REMOVE requests received"),
+              "Processing `%s' request for `%s' of type %u\n", "REMOVE",
+              GNUNET_h2s (&dm->key), ntohl (dm->type));
+  GNUNET_STATISTICS_update (stats, gettext_noop ("# REMOVE requests received"),
                             1, GNUNET_NO);
   GNUNET_SERVER_client_keep (client);
   GNUNET_CRYPTO_hash (&dm[1], ntohl (dm->size), &vhash);
-  plugin->api->get_key (plugin->api->cls,
-                        0,
-                        &dm->key,
-                        &vhash,
+  plugin->api->get_key (plugin->api->cls, 0, &dm->key, &vhash,
                         (enum GNUNET_BLOCK_Type) ntohl (dm->type),
                         &remove_callback, client);
 }
@@ -1247,13 +1193,10 @@ handle_remove (void *cls,
  * @param message the actual message
  */
 static void
-handle_drop (void *cls,
-             struct GNUNET_SERVER_Client *client,
+handle_drop (void *cls, struct GNUNET_SERVER_Client *client,
              const struct GNUNET_MessageHeader *message)
 {
-#if DEBUG_DATASTORE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request\n", "DROP");
-#endif
   do_drop = GNUNET_YES;
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
@@ -1264,7 +1207,7 @@ handle_drop (void *cls,
  * change in their disk utilization.
  *
  * @param cls closure (NULL)
- * @param delta change in disk utilization, 
+ * @param delta change in disk utilization,
  *        0 for "reset to empty"
  */
 static void
@@ -1298,18 +1241,15 @@ disk_utilization_change_cb (void *cls, int delta)
  * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
  */
 static int
-process_stat_in (void *cls,
-                 const char *subsystem,
-                 const char *name, uint64_t value, int is_persistent)
+process_stat_in (void *cls, const char *subsystem, const char *name,
+                 uint64_t value, int is_persistent)
 {
   GNUNET_assert (stats_worked == GNUNET_NO);
   stats_worked = GNUNET_YES;
   payload += value;
-#if DEBUG_SQLITE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Notification from statistics about existing payload (%llu), new payload is %llu\n",
-              abs_value, payload);
-#endif
+              value, payload);
   return GNUNET_OK;
 }
 
@@ -1333,31 +1273,21 @@ load_plugin ()
 {
   struct DatastorePlugin *ret;
   char *libname;
-  char *name;
 
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_string (cfg,
-                                             "DATASTORE", "DATABASE", &name))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                _("No `%s' specified for `%s' in configuration!\n"),
-                "DATABASE", "DATASTORE");
-    return NULL;
-  }
   ret = GNUNET_malloc (sizeof (struct DatastorePlugin));
   ret->env.cfg = cfg;
   ret->env.duc = &disk_utilization_change_cb;
   ret->env.cls = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              _("Loading `%s' datastore plugin\n"), name);
-  GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name);
-  ret->short_name = name;
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' datastore plugin\n"),
+              plugin_name);
+  GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", plugin_name);
+  ret->short_name = GNUNET_strdup (plugin_name);
   ret->lib_name = libname;
   ret->api = GNUNET_PLUGIN_load (libname, &ret->env);
   if (ret->api == NULL)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                _("Failed to load datastore plugin for `%s'\n"), name);
+                _("Failed to load datastore plugin for `%s'\n"), plugin_name);
     GNUNET_free (ret->short_name);
     GNUNET_free (libname);
     GNUNET_free (ret);
@@ -1376,14 +1306,14 @@ load_plugin ()
 static void
 unload_plugin (struct DatastorePlugin *plug)
 {
-#if DEBUG_DATASTORE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Datastore service is unloading plugin...\n");
-#endif
   GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
   GNUNET_free (plug->lib_name);
   GNUNET_free (plug->short_name);
   GNUNET_free (plug);
+  GNUNET_free (quota_stat_name);
+  quota_stat_name = NULL;
 }
 
 
@@ -1394,6 +1324,8 @@ unload_plugin (struct DatastorePlugin *plug)
 static void
 unload_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
+  if (lastSync > 0)
+    sync_stats ();
   if (GNUNET_YES == do_drop)
     plugin->api->drop (plugin->api->cls);
   unload_plugin (plugin);
@@ -1403,8 +1335,6 @@ unload_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     GNUNET_CONTAINER_bloomfilter_free (filter);
     filter = NULL;
   }
-  if (lastSync > 0)
-    sync_stats ();
   if (stat_get != NULL)
   {
     GNUNET_STATISTICS_get_cancel (stat_get);
@@ -1415,6 +1345,8 @@ unload_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
     stats = NULL;
   }
+  GNUNET_free_non_null (plugin_name);
+  plugin_name = NULL;
 }
 
 
@@ -1433,7 +1365,7 @@ cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     GNUNET_CONTAINER_DLL_remove (tcc_head, tcc_tail, tcc);
     if (tcc->th != NULL)
     {
-      GNUNET_CONNECTION_notify_transmit_ready_cancel (tcc->th);
+      GNUNET_SERVER_notify_transmit_ready_cancel (tcc->th);
       GNUNET_SERVER_client_drop (tcc->client);
     }
     GNUNET_free (tcc->msg);
@@ -1444,8 +1376,8 @@ cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     GNUNET_SCHEDULER_cancel (expired_kill_task);
     expired_kill_task = GNUNET_SCHEDULER_NO_TASK;
   }
-  GNUNET_SCHEDULER_add_continuation (&unload_task,
-                                     NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+  GNUNET_SCHEDULER_add_continuation (&unload_task, NULL,
+                                     GNUNET_SCHEDULER_REASON_PREREQ_DONE);
 }
 
 
@@ -1486,8 +1418,26 @@ cleanup_reservations (void *cls, struct GNUNET_SERVER_Client *client)
     }
     pos = next;
   }
-  GNUNET_STATISTICS_set (stats,
-                         gettext_noop ("# reserved"), reserved, GNUNET_NO);
+  GNUNET_STATISTICS_set (stats, gettext_noop ("# reserved"), reserved,
+                         GNUNET_NO);
+}
+
+
+/**
+ * Adds a given key to the bloomfilter 'count' times.
+ *
+ * @param cls the bloomfilter
+ * @param key key to add
+ * @param count number of times to add key
+ */
+static void
+add_key_to_bloomfilter (void *cls,
+                       const struct GNUNET_HashCode *key,
+                       unsigned int count)
+{
+  struct GNUNET_CONTAINER_BloomFilter *bf = cls;
+  while (0 < count--)
+    GNUNET_CONTAINER_bloomfilter_add (bf, key);
 }
 
 
@@ -1499,8 +1449,7 @@ cleanup_reservations (void *cls, struct GNUNET_SERVER_Client *client)
  * @param c configuration to use
  */
 static void
-run (void *cls,
-     struct GNUNET_SERVER_Handle *server,
+run (void *cls, struct GNUNET_SERVER_Handle *server,
      const struct GNUNET_CONFIGURATION_Handle *c)
 {
   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
@@ -1525,28 +1474,43 @@ run (void *cls,
     {NULL, NULL, 0, 0}
   };
   char *fn;
+  char *pfn;
   unsigned int bf_size;
+  int refresh_bf;
 
   cfg = c;
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (cfg, "DATASTORE", "QUOTA", &quota))
+      GNUNET_CONFIGURATION_get_value_string (cfg, "DATASTORE", "DATABASE",
+                                             &plugin_name))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                _("No `%s' specified for `%s' in configuration!\n"),
-                "QUOTA", "DATASTORE");
+                _("No `%s' specified for `%s' in configuration!\n"), "DATABASE",
+                "DATASTORE");
+    return;
+  }
+  GNUNET_asprintf (&quota_stat_name,
+                  _("# bytes used in file-sharing datastore `%s'"),
+                  plugin_name);
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_size (cfg, "DATASTORE", "QUOTA", &quota))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _("No `%s' specified for `%s' in configuration!\n"), "QUOTA",
+                "DATASTORE");
     return;
   }
   stats = GNUNET_STATISTICS_create ("datastore", cfg);
   GNUNET_STATISTICS_set (stats, gettext_noop ("# quota"), quota, GNUNET_NO);
   cache_size = quota / 8;       /* Or should we make this an option? */
-  GNUNET_STATISTICS_set (stats,
-                         gettext_noop ("# cache size"), cache_size, GNUNET_NO);
-  bf_size = quota / 32;         /* 8 bit per entry, 1 bit per 32 kb in DB */
+  GNUNET_STATISTICS_set (stats, gettext_noop ("# cache size"), cache_size,
+                         GNUNET_NO);
+  if (quota / (32 * 1024LL) > (1 << 31))
+    bf_size = (1 << 31);          /* absolute limit: ~2 GB, beyond that BF just won't help anyway */
+  else
+    bf_size = quota / (32 * 1024LL);         /* 8 bit per entry, 1 bit per 32 kb in DB */
   fn = NULL;
   if ((GNUNET_OK !=
-       GNUNET_CONFIGURATION_get_value_filename (cfg,
-                                                "DATASTORE",
-                                                "BLOOMFILTER",
+       GNUNET_CONFIGURATION_get_value_filename (cfg, "DATASTORE", "BLOOMFILTER",
                                                 &fn)) ||
       (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn)))
   {
@@ -1557,9 +1521,60 @@ run (void *cls,
     fn = NULL;
   }
   if (fn != NULL)
-    filter = GNUNET_CONTAINER_bloomfilter_load (fn, bf_size, 5);        /* approx. 3% false positives at max use */
+  {
+    GNUNET_asprintf (&pfn, "%s.%s", fn, plugin_name);
+    if (GNUNET_YES == GNUNET_DISK_file_test (pfn))
+    {
+      filter = GNUNET_CONTAINER_bloomfilter_load (pfn, bf_size, 5);        /* approx. 3% false positives at max use */
+      if (NULL == filter)
+      {
+       /* file exists but not valid, remove and try again, but refresh */
+       if (0 != UNLINK (pfn))
+       {
+         /* failed to remove, run without file */
+         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                     _("Failed to remove bogus bloomfilter file `%s'\n"),
+                     pfn);
+         GNUNET_free (pfn);
+         pfn = NULL;
+         filter = GNUNET_CONTAINER_bloomfilter_load (NULL, bf_size, 5);        /* approx. 3% false positives at max use */
+         refresh_bf = GNUNET_YES;
+       }
+       else
+       {
+         /* try again after remove */
+         filter = GNUNET_CONTAINER_bloomfilter_load (pfn, bf_size, 5);        /* approx. 3% false positives at max use */
+         refresh_bf = GNUNET_YES;
+         if (NULL == filter)
+         {
+           /* failed yet again, give up on using file */
+           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                       _("Failed to remove bogus bloomfilter file `%s'\n"),
+                       pfn);
+           GNUNET_free (pfn);
+           pfn = NULL;
+           filter = GNUNET_CONTAINER_bloomfilter_init (NULL, bf_size, 5);        /* approx. 3% false positives at max use */
+         }
+       }
+      }
+      else
+      {
+       /* normal case: have an existing valid bf file, no need to refresh */
+       refresh_bf = GNUNET_NO;
+      }
+    }
+    else
+    {
+      filter = GNUNET_CONTAINER_bloomfilter_load (pfn, bf_size, 5);        /* approx. 3% false positives at max use */
+      refresh_bf = GNUNET_YES;
+    }
+    GNUNET_free (pfn);
+  }
   else
+  {
     filter = GNUNET_CONTAINER_bloomfilter_init (NULL, bf_size, 5);      /* approx. 3% false positives at max use */
+    refresh_bf = GNUNET_YES;
+  }
   GNUNET_free_non_null (fn);
   if (filter == NULL)
   {
@@ -1584,19 +1599,30 @@ run (void *cls,
     }
     return;
   }
-  stat_get = GNUNET_STATISTICS_get (stats,
-                                    "datastore",
-                                    QUOTA_STAT_NAME,
-                                    GNUNET_TIME_UNIT_SECONDS,
-                                    &process_stat_done,
-                                    &process_stat_in, plugin);
+  stat_get =
+      GNUNET_STATISTICS_get (stats, "datastore", quota_stat_name,
+                             GNUNET_TIME_UNIT_SECONDS, &process_stat_done,
+                             &process_stat_in, plugin);
   GNUNET_SERVER_disconnect_notify (server, &cleanup_reservations, NULL);
   GNUNET_SERVER_add_handlers (server, handlers);
-  expired_kill_task
-      = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                            &delete_expired, NULL);
-  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
-                                &cleaning_task, NULL);
+  if (GNUNET_YES == refresh_bf)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+               _("Rebuilding bloomfilter.  Please be patient.\n"));
+    if (NULL != plugin->api->get_keys)
+      plugin->api->get_keys (plugin->api->cls, &add_key_to_bloomfilter, filter);
+    else
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("Plugin does not support get_keys function. Please fix!\n"));
+
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+               _("Bloomfilter construction complete.\n"));
+  }
+  expired_kill_task =
+      GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
+                                          &delete_expired, NULL);
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleaning_task,
+                                NULL);
 }
 
 
@@ -1612,11 +1638,10 @@ main (int argc, char *const *argv)
 {
   int ret;
 
-  ret = (GNUNET_OK ==
-         GNUNET_SERVICE_run (argc,
-                             argv,
-                             "datastore",
-                             GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
+  ret =
+      (GNUNET_OK ==
+       GNUNET_SERVICE_run (argc, argv, "datastore", GNUNET_SERVICE_OPTION_NONE,
+                           &run, NULL)) ? 0 : 1;
   return ret;
 }