Merge branch 'credentials' of git+ssh://gnunet.org/gnunet into credentials
[oweals/gnunet.git] / src / datacache / datacache.c
index b937c63bb65931fd42efbcbc32f08bb84ec3edfa..a1869a8bd4bc851ca20fc1e8c8fb9fd2afbe6b15 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet
 /*
      This file is part of GNUnet
-     (C) 2004, 2005, 2006, 2007, 2009, 2010 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2015 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      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
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 */
-
 /**
  * @file datacache/datacache.c
  * @brief datacache API implementation
 /**
  * @file datacache/datacache.c
  * @brief datacache API implementation
 #include "gnunet_statistics_service.h"
 #include "gnunet_datacache_plugin.h"
 
 #include "gnunet_statistics_service.h"
 #include "gnunet_datacache_plugin.h"
 
+
+#define LOG(kind,...) GNUNET_log_from (kind, "datacache", __VA_ARGS__)
+
+#define LOG_STRERROR_FILE(kind,op,fn) GNUNET_log_from_strerror_file (kind, "datacache", op, fn)
+
 /**
  * Internal state of the datacache library.
  */
 /**
  * Internal state of the datacache library.
  */
@@ -70,7 +74,7 @@ struct GNUNET_DATACACHE_Handle
    * Name of the library (i.e. "gnunet_plugin_datacache_sqlite").
    */
   char *lib_name;
    * Name of the library (i.e. "gnunet_plugin_datacache_sqlite").
    */
   char *lib_name;
-  
+
   /**
    * Name for the bloom filter file.
    */
   /**
    * Name for the bloom filter file.
    */
@@ -92,24 +96,33 @@ struct GNUNET_DATACACHE_Handle
 /**
  * Function called by plugins to notify the datacache
  * about content deletions.
 /**
  * Function called by plugins to notify the datacache
  * about content deletions.
- * 
+ *
  * @param cls closure
  * @param key key of the content that was deleted
  * @param size number of bytes that were made available
  */
  * @param cls closure
  * @param key key of the content that was deleted
  * @param size number of bytes that were made available
  */
-static void 
+static void
 env_delete_notify (void *cls,
 env_delete_notify (void *cls,
-                  const GNUNET_HashCode *key,
-                  size_t size)
+                   const struct GNUNET_HashCode *key,
+                   size_t size)
 {
 {
-  struct GNUNET_DATACACHE_Handle * h = cls;
+  struct GNUNET_DATACACHE_Handle *h = cls;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Content under key `%s' discarded\n",
+       GNUNET_h2s (key));
   GNUNET_assert (h->utilization >= size);
   h->utilization -= size;
   GNUNET_assert (h->utilization >= size);
   h->utilization -= size;
-  GNUNET_CONTAINER_bloomfilter_remove (h->filter, key);
+  GNUNET_CONTAINER_bloomfilter_remove (h->filter,
+                                       key);
+  GNUNET_STATISTICS_update (h->stats,
+                            gettext_noop ("# bytes stored"),
+                            - (long long) size,
+                            GNUNET_NO);
   GNUNET_STATISTICS_update (h->stats,
   GNUNET_STATISTICS_update (h->stats,
-                           gettext_noop ("# bytes stored"),
-                           -size,
-                           GNUNET_NO);
+                            gettext_noop ("# items stored"),
+                            -1,
+                            GNUNET_NO);
 }
 
 
 }
 
 
@@ -122,7 +135,7 @@ env_delete_notify (void *cls,
  */
 struct GNUNET_DATACACHE_Handle *
 GNUNET_DATACACHE_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
  */
 struct GNUNET_DATACACHE_Handle *
 GNUNET_DATACACHE_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                        const char *section)
+                         const char *section)
 {
   unsigned int bf_size;
   unsigned long long quota;
 {
   unsigned int bf_size;
   unsigned long long quota;
@@ -131,62 +144,77 @@ GNUNET_DATACACHE_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
   char *name;
 
   if (GNUNET_OK !=
   char *name;
 
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (cfg,
-                                             section, "QUOTA", &quota))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("No `%s' specified for `%s' in configuration!\n"),
-                 "QUOTA",
-                 section);
-      return NULL;
-    }
+      GNUNET_CONFIGURATION_get_value_size (cfg,
+                                           section,
+                                           "QUOTA",
+                                           &quota))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               section,
+                               "QUOTA");
+    return NULL;
+  }
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_string (cfg,
                                              section,
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_string (cfg,
                                              section,
-                                            "DATABASE", &name))
+                                             "DATABASE",
+                                             &name))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               section,
+                               "DATABASE");
+    return NULL;
+  }
+  bf_size = quota / 32;         /* 8 bit per entry, 1 bit per 32 kb in DB */
+
+  ret = GNUNET_new (struct GNUNET_DATACACHE_Handle);
+
+  if (GNUNET_YES !=
+      GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "DISABLE_BF"))
+  {
+    if (GNUNET_YES !=
+       GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "DISABLE_BF_RC"))
     {
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("No `%s' specified for `%s' in configuration!\n"),
-                 "DATABASE",
-                 section);
-      return NULL;
+      ret->bloom_name = GNUNET_DISK_mktemp ("gnunet-datacachebloom");
     }
     }
-  bf_size = quota / 32; /* 8 bit per entry, 1 bit per 32 kb in DB */
-
-  ret = GNUNET_malloc (sizeof(struct GNUNET_DATACACHE_Handle));
-  ret->bloom_name = GNUNET_DISK_mktemp ("gnunet-datacachebloom");
-  if (NULL != ret->bloom_name)
+    if (NULL != ret->bloom_name)
     {
     {
-      ret->filter = GNUNET_CONTAINER_bloomfilter_load (ret->bloom_name, 
-                                                      quota / 1024,    /* 8 bit per entry in DB, expect 1k entries */
+      ret->filter = GNUNET_CONTAINER_bloomfilter_load (ret->bloom_name,
+                                                       quota / 1024,     /* 8 bit per entry in DB, expect 1k entries */
                                                       5);
     }
                                                       5);
     }
-  else
+    if (NULL == ret->filter)
     {
     {
-      ret->filter = GNUNET_CONTAINER_bloomfilter_init (NULL, bf_size, 5);  /* approx. 3% false positives at max use */  
+       ret->filter = GNUNET_CONTAINER_bloomfilter_init (NULL,
+                                                         bf_size,
+                                                         5); /* approx. 3% false positives at max use */
     }
     }
-  ret->stats = GNUNET_STATISTICS_create ("datacache",
-                                        cfg);
+  }
+  ret->stats = GNUNET_STATISTICS_create ("datacache", cfg);
   ret->section = GNUNET_strdup (section);
   ret->env.cfg = cfg;
   ret->section = GNUNET_strdup (section);
   ret->env.cfg = cfg;
-  ret->env.delete_notify = &env_delete_notify;  
+  ret->env.delete_notify = &env_delete_notify;
   ret->env.section = ret->section;
   ret->env.cls = ret;
   ret->env.delete_notify = &env_delete_notify;
   ret->env.quota = quota;
   ret->env.section = ret->section;
   ret->env.cls = ret;
   ret->env.delete_notify = &env_delete_notify;
   ret->env.quota = quota;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              _("Loading `%s' datacache plugin\n"), name);
-  GNUNET_asprintf (&libname, "libgnunet_plugin_datacache_%s", name);
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       _("Loading `%s' datacache plugin\n"),
+       name);
+  GNUNET_asprintf (&libname,
+                   "libgnunet_plugin_datacache_%s",
+                   name);
   ret->short_name = name;
   ret->lib_name = libname;
   ret->api = GNUNET_PLUGIN_load (libname, &ret->env);
   if (ret->api == NULL)
   ret->short_name = 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 datacache plugin for `%s'\n"), name);
-      GNUNET_DATACACHE_destroy (ret);
-      return NULL;
-    }
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _("Failed to load datacache plugin for `%s'\n"),
+         name);
+    GNUNET_DATACACHE_destroy (ret);
+    return NULL;
+  }
   return ret;
 }
 
   return ret;
 }
 
@@ -196,25 +224,26 @@ GNUNET_DATACACHE_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
  *
  * @param h handle to the datastore
  */
  *
  * @param h handle to the datastore
  */
-void GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h)
+void
+GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h)
 {
 {
-  if (h->filter != NULL)
+  if (NULL != h->filter)
     GNUNET_CONTAINER_bloomfilter_free (h->filter);
     GNUNET_CONTAINER_bloomfilter_free (h->filter);
-  if (h->api != NULL)
+  if (NULL != h->api)
     GNUNET_break (NULL == GNUNET_PLUGIN_unload (h->lib_name, h->api));
   GNUNET_free (h->lib_name);
   GNUNET_free (h->short_name);
   GNUNET_free (h->section);
     GNUNET_break (NULL == GNUNET_PLUGIN_unload (h->lib_name, h->api));
   GNUNET_free (h->lib_name);
   GNUNET_free (h->short_name);
   GNUNET_free (h->section);
-  if (h->bloom_name != NULL)
-    {
-      if (0 != UNLINK (h->bloom_name))
-       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
-                                 "unlink",
-                                 h->bloom_name);
-      GNUNET_free (h->bloom_name);
-    }
-  GNUNET_STATISTICS_destroy (h->stats,
-                            GNUNET_NO);
+  if (NULL != h->bloom_name)
+  {
+    if (0 != UNLINK (h->bloom_name))
+      GNUNET_log_from_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                                     "datacache",
+                                     "unlink",
+                                     h->bloom_name);
+    GNUNET_free (h->bloom_name);
+  }
+  GNUNET_STATISTICS_destroy (h->stats, GNUNET_NO);
   GNUNET_free (h);
 }
 
   GNUNET_free (h);
 }
 
@@ -224,38 +253,53 @@ void GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h)
  *
  * @param h handle to the datacache
  * @param key key to store data under
  *
  * @param h handle to the datacache
  * @param key key to store data under
- * @param size number of bytes in data
+ * @param data_size number of bytes in @a data
  * @param data data to store
  * @param type type of the value
  * @param discard_time when to discard the value in any case
  * @param data data to store
  * @param type type of the value
  * @param discard_time when to discard the value in any case
- * @return GNUNET_OK on success, GNUNET_SYSERR on error (full, etc.)
+ * @param path_info_len number of entries in @a path_info
+ * @param path_info a path through the network
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error, #GNUNET_NO if duplicate
  */
  */
-int 
+int
 GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h,
 GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h,
-                     const GNUNET_HashCode * key,
-                     size_t size,
-                     const char *data,
-                     enum GNUNET_BLOCK_Type type,
-                     struct GNUNET_TIME_Absolute discard_time)
+                      const struct GNUNET_HashCode *key,
+                      size_t data_size,
+                      const char *data,
+                      enum GNUNET_BLOCK_Type type,
+                      struct GNUNET_TIME_Absolute discard_time,
+                     unsigned int path_info_len,
+                     const struct GNUNET_PeerIdentity *path_info)
 {
 {
-  uint32_t used;
-
-  used = h->api->put (h->api->cls,
-                     key,
-                     size,
-                     data,
-                     type,
-                     discard_time);
-  if (used == 0)
-    {
-      GNUNET_break (0);
-      return GNUNET_SYSERR;
-    }
+  ssize_t used;
+
+  used = h->api->put (h->api->cls, key,
+                     data_size, data,
+                     type, discard_time,
+                     path_info_len, path_info);
+  if (-1 == used)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (0 == used)
+  {
+    /* duplicate */
+    return GNUNET_NO;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Stored data under key `%s' in cache\n",
+       GNUNET_h2s (key));
+  GNUNET_STATISTICS_update (h->stats,
+                            gettext_noop ("# bytes stored"),
+                            data_size,
+                            GNUNET_NO);
   GNUNET_STATISTICS_update (h->stats,
   GNUNET_STATISTICS_update (h->stats,
-                           gettext_noop ("# bytes stored"),
-                           size,
-                           GNUNET_NO);
-  GNUNET_CONTAINER_bloomfilter_add (h->filter, key);
+                            gettext_noop ("# items stored"),
+                            1,
+                            GNUNET_NO);
+  if (NULL != h->filter)
+    GNUNET_CONTAINER_bloomfilter_add (h->filter, key);
   while (h->utilization + used > h->env.quota)
     GNUNET_assert (GNUNET_OK == h->api->del (h->api->cls));
   h->utilization += used;
   while (h->utilization + used > h->env.quota)
     GNUNET_assert (GNUNET_OK == h->api->del (h->api->cls));
   h->utilization += used;
@@ -271,36 +315,99 @@ GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h,
  * @param key what to look up
  * @param type entries of which type are relevant?
  * @param iter maybe NULL (to just count)
  * @param key what to look up
  * @param type entries of which type are relevant?
  * @param iter maybe NULL (to just count)
- * @param iter_cls closure for iter
+ * @param iter_cls closure for @a iter
  * @return the number of results found
  */
  * @return the number of results found
  */
-unsigned int 
+unsigned int
 GNUNET_DATACACHE_get (struct GNUNET_DATACACHE_Handle *h,
 GNUNET_DATACACHE_get (struct GNUNET_DATACACHE_Handle *h,
-                     const GNUNET_HashCode * key,
-                     enum GNUNET_BLOCK_Type type, 
-                     GNUNET_DATACACHE_Iterator iter,
-                     void *iter_cls)
+                      const struct GNUNET_HashCode *key,
+                      enum GNUNET_BLOCK_Type type,
+                      GNUNET_DATACACHE_Iterator iter,
+                      void *iter_cls)
 {
   GNUNET_STATISTICS_update (h->stats,
 {
   GNUNET_STATISTICS_update (h->stats,
-                           gettext_noop ("# requests received"),
-                           1,
-                           GNUNET_NO);
-  if (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_test (h->filter,
-                                                     key))
-    {
-      GNUNET_STATISTICS_update (h->stats,
-                               gettext_noop ("# requests filtered by bloom filter"),
-                               1,
-                               GNUNET_NO);
-      return 0; /* can not be present */
-    } 
+                            gettext_noop ("# requests received"),
+                            1,
+                            GNUNET_NO);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Processing request for key `%s'\n",
+       GNUNET_h2s (key));
+  if ( (NULL != h->filter) &&
+       (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_test (h->filter, key)) )
+  {
+    GNUNET_STATISTICS_update (h->stats,
+                              gettext_noop ("# requests filtered by bloom filter"),
+                              1,
+                              GNUNET_NO);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Bloomfilter filters request for key `%s'\n",
+         GNUNET_h2s (key));
+    return 0;                   /* can not be present */
+  }
   return h->api->get (h->api->cls,
   return h->api->get (h->api->cls,
-                     key,
-                     type,
-                     iter,
-                     iter_cls);
+                      key, type,
+                      iter, iter_cls);
+}
+
+
+/**
+ * Obtain a random element from the datacache.
+ *
+ * @param h handle to the datacache
+ * @param iter maybe NULL (to just count)
+ * @param iter_cls closure for @a iter
+ * @return the number of results found (zero or 1)
+ */
+unsigned int
+GNUNET_DATACACHE_get_random (struct GNUNET_DATACACHE_Handle *h,
+                             GNUNET_DATACACHE_Iterator iter,
+                             void *iter_cls)
+{
+  GNUNET_STATISTICS_update (h->stats,
+                            gettext_noop ("# requests for random value received"),
+                            1,
+                            GNUNET_NO);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Processing request for random value\n");
+  return h->api->get_random (h->api->cls,
+                             iter,
+                             iter_cls);
 }
 
 
 }
 
 
+/**
+ * Iterate over the results that are "close" to a particular key in
+ * the datacache.  "close" is defined as numerically larger than @a
+ * key (when interpreted as a circular address space), with small
+ * distance.
+ *
+ * @param h handle to the datacache
+ * @param key area of the keyspace to look into
+ * @param num_results number of results that should be returned to @a iter
+ * @param iter maybe NULL (to just count)
+ * @param iter_cls closure for @a iter
+ * @return the number of results found
+ */
+unsigned int
+GNUNET_DATACACHE_get_closest (struct GNUNET_DATACACHE_Handle *h,
+                              const struct GNUNET_HashCode *key,
+                              unsigned int num_results,
+                              GNUNET_DATACACHE_Iterator iter,
+                              void *iter_cls)
+{
+  GNUNET_STATISTICS_update (h->stats,
+                            gettext_noop ("# proximity search requests received"),
+                            1,
+                            GNUNET_NO);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Processing proximity search at `%s'\n",
+       GNUNET_h2s (key));
+  return h->api->get_closest (h->api->cls,
+                              key,
+                              num_results,
+                              iter,
+                              iter_cls);
+}
+
 
 
-/* end of datacache_api.c */
+/* end of datacache.c */