Browse Source

changing datacache API to separate put-paths from data (so that plugins can test for duplicates), removing support for MySQL

Christian Grothoff 11 years ago
parent
commit
4e1d85bac6

+ 15 - 33
src/datacache/Makefile.am

@@ -19,9 +19,6 @@ endif
 if HAVE_SQLITE
   SQLITE_PLUGIN = libgnunet_plugin_datacache_sqlite.la
 endif
-if HAVE_MYSQL
-  MYSQL_PLUGIN = libgnunet_plugin_datacache_mysql.la
-endif
 if HAVE_POSTGRES
   POSTGRES_PLUGIN = libgnunet_plugin_datacache_postgres.la
 endif
@@ -42,7 +39,6 @@ libgnunetdatacache_la_LDFLAGS = \
 
 plugin_LTLIBRARIES = \
   $(SQLITE_PLUGIN) \
-  $(MYSQL_PLUGIN) \
   $(POSTGRES_PLUGIN) \
   libgnunet_plugin_datacache_heap.la \
   libgnunet_plugin_datacache_template.la 
@@ -66,18 +62,6 @@ libgnunet_plugin_datacache_heap_la_LIBADD = \
 libgnunet_plugin_datacache_heap_la_LDFLAGS = \
  $(GN_PLUGIN_LDFLAGS)
 
-libgnunet_plugin_datacache_mysql_la_SOURCES = \
-  plugin_datacache_mysql.c
-libgnunet_plugin_datacache_mysql_la_LIBADD = \
-  $(top_builddir)/src/statistics/libgnunetstatistics.la \
-  $(top_builddir)/src/mysql/libgnunetmysql.la \
-  $(top_builddir)/src/util/libgnunetutil.la \
-  $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient
-libgnunet_plugin_datacache_mysql_la_CPPFLAGS = \
- $(MYSQL_CPPFLAGS)
-libgnunet_plugin_datacache_mysql_la_LDFLAGS = \
- $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient
-
 libgnunet_plugin_datacache_postgres_la_SOURCES = \
   plugin_datacache_postgres.c
 libgnunet_plugin_datacache_postgres_la_LIBADD = \
@@ -110,16 +94,14 @@ SQLITE_TESTS = \
  $(SQLITE_BENCHMARKS)
 endif
 
-if HAVE_MYSQL
 if HAVE_BENCHMARKS
- MYSQL_BENCHMARKS = \
-  perf_datacache_mysql
-endif
-MYSQL_TESTS = \
- test_datacache_mysql \
- test_datacache_quota_mysql \
- $(MYSQL_BENCHMARKS)
+ HEAP_BENCHMARKS = \
+  perf_datacache_heap
 endif
+HEAP_TESTS = \
+ test_datacache_heap \
+ test_datacache_quota_heap \
+ $(HEAP_BENCHMARKS)
 
 if HAVE_POSTGRES
 if HAVE_BENCHMARKS
@@ -134,7 +116,7 @@ endif
 
 check_PROGRAMS = \
  $(SQLITE_TESTS) \
- $(MYSQL_TESTS) \
+ $(HEAP_TESTS) \
  $(POSTGRES_TESTS) 
 
 if ENABLE_TEST_RUN
@@ -162,23 +144,23 @@ perf_datacache_sqlite_LDADD = \
  $(top_builddir)/src/datacache/libgnunetdatacache.la \
  $(top_builddir)/src/util/libgnunetutil.la  
 
-test_datacache_mysql_SOURCES = \
+test_datacache_heap_SOURCES = \
  test_datacache.c
-test_datacache_mysql_LDADD = \
+test_datacache_heap_LDADD = \
  $(top_builddir)/src/testing/libgnunettesting.la \
  $(top_builddir)/src/datacache/libgnunetdatacache.la \
  $(top_builddir)/src/util/libgnunetutil.la  
 
-test_datacache_quota_mysql_SOURCES = \
+test_datacache_quota_heap_SOURCES = \
  test_datacache_quota.c
-test_datacache_quota_mysql_LDADD = \
+test_datacache_quota_heap_LDADD = \
  $(top_builddir)/src/testing/libgnunettesting.la \
  $(top_builddir)/src/datacache/libgnunetdatacache.la \
  $(top_builddir)/src/util/libgnunetutil.la  
 
-perf_datacache_mysql_SOURCES = \
+perf_datacache_heap_SOURCES = \
  perf_datacache.c
-perf_datacache_mysql_LDADD = \
+perf_datacache_heap_LDADD = \
  $(top_builddir)/src/testing/libgnunettesting.la \
  $(top_builddir)/src/datacache/libgnunetdatacache.la \
  $(top_builddir)/src/util/libgnunetutil.la  
@@ -207,7 +189,7 @@ perf_datacache_postgres_LDADD = \
 EXTRA_DIST = \
  test_datacache_data_sqlite.conf \
  perf_datacache_data_sqlite.conf \
- test_datacache_data_mysql.conf \
- perf_datacache_data_mysql.conf \
+ test_datacache_data_heap.conf \
+ perf_datacache_data_heap.conf \
  test_datacache_data_postgres.conf \
  perf_datacache_data_postgres.conf

+ 18 - 6
src/datacache/datacache.c

@@ -233,22 +233,34 @@ GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h)
  * @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 'path_info'
+ * @param path_info a path through the network
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error, GNUNET_NO if duplicate
  */
 int
 GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h,
                       const struct GNUNET_HashCode * key, size_t size,
                       const char *data, enum GNUNET_BLOCK_Type type,
-                      struct GNUNET_TIME_Absolute discard_time)
+                      struct GNUNET_TIME_Absolute discard_time,
+		      unsigned int path_info_len,
+		      const struct GNUNET_PeerIdentity *path_info)
 {
-  uint32_t used;
+  ssize_t used;
 
-  used = h->api->put (h->api->cls, key, size, data, type, discard_time);
-  if (0 == used)
+  used = h->api->put (h->api->cls, key, 
+		      size, data, 
+		      type, discard_time,
+		      path_info_len, path_info);
+  if (-1 == used)
   {
-    /* error or duplicate */
+    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"), size,

+ 7 - 3
src/datacache/perf_datacache.c

@@ -44,9 +44,12 @@ static const char *plugin_name;
 
 
 static int
-checkIt (void *cls, struct GNUNET_TIME_Absolute exp,
+checkIt (void *cls, 
          const struct GNUNET_HashCode * key, size_t size, const char *data,
-         enum GNUNET_BLOCK_Type type)
+         enum GNUNET_BLOCK_Type type,
+	 struct GNUNET_TIME_Absolute exp,
+	 unsigned int path_len,
+	 const struct GNUNET_PeerIdentity *path)
 {
   if ((size == sizeof (struct GNUNET_HashCode)) && (0 == memcmp (data, cls, size)))
     found++;
@@ -84,7 +87,8 @@ run (void *cls, char *const *args, const char *cfgfile,
     GNUNET_CRYPTO_hash (&k, sizeof (struct GNUNET_HashCode), &n);
     ASSERT (GNUNET_OK ==
             GNUNET_DATACACHE_put (h, &k, sizeof (struct GNUNET_HashCode),
-                                  (const char *) &n, 1 + i % 16, exp));
+                                  (const char *) &n, 1 + i % 16, exp,
+				  0, NULL));
     k = n;
   }
   FPRINTF (stderr, "%s",  "\n");

+ 5 - 0
src/datacache/perf_datacache_data_heap.conf

@@ -0,0 +1,5 @@
+[perfcache]
+QUOTA = 500 KB
+DATABASE = heap
+
+

+ 0 - 13
src/datacache/perf_datacache_data_mysql.conf

@@ -1,13 +0,0 @@
-[perfcache]
-QUOTA = 500 KB
-DATABASE = mysql
-
-[datacache-mysql]
-DATABASE = gnunetcheck
-# CONFIG = ~/.my.cnf
-# USER =
-# PASSWORD =
-# HOST = 
-# PORT = 
-
-

+ 60 - 13
src/datacache/plugin_datacache_heap.c

@@ -32,6 +32,7 @@
 #define LOG_STRERROR_FILE(kind,op,fn) GNUNET_log_from_strerror_file (kind, "datacache-heap", op, fn)
 
 
+
 /**
  * Context for all functions in this plugin.
  */
@@ -75,11 +76,21 @@ struct Value
    */
   struct GNUNET_CONTAINER_HeapNode *hn;
 
+  /**
+   * Path information.
+   */
+  struct GNUNET_PeerIdentity *path_info;
+
   /**
    * Payload (actual payload follows this struct)
    */
   size_t size;
 
+  /**
+   * Number of entries in 'path_info'.
+   */
+  unsigned int path_info_len;
+
   /**
    * Type of the block.
    */
@@ -88,6 +99,9 @@ struct Value
 };
 
 
+#define OVERHEAD (sizeof (struct Value) + 64)
+
+
 /**
  * Closure for 'put_cb'.
  */
@@ -108,6 +122,11 @@ struct PutContext
    */
   struct GNUNET_CONTAINER_Heap *heap;
 
+  /**
+   * Path information.
+   */
+  const struct GNUNET_PeerIdentity *path_info;
+
   /**
    * Number of bytes in 'data'.
    */
@@ -118,6 +137,11 @@ struct PutContext
    */
   enum GNUNET_BLOCK_Type type;
 
+  /**
+   * Number of entries in 'path_info'.
+   */
+  unsigned int path_info_len;
+
   /**
    * Value to set to GNUNET_YES if an equivalent block was found.
    */
@@ -149,13 +173,20 @@ put_cb (void *cls,
     put_ctx->found = GNUNET_YES;    
     val->discard_time = GNUNET_TIME_absolute_max (val->discard_time,
 						  put_ctx->discard_time);
+    /* replace old path with new path */
+    GNUNET_array_grow (val->path_info,
+		       val->path_info_len,
+		       put_ctx->path_info_len);
+    memcpy (val->path_info, 
+	    put_ctx->path_info,
+	    put_ctx->path_info_len * sizeof (struct GNUNET_PeerIdentity));   
     GNUNET_CONTAINER_heap_update_cost (put_ctx->heap,
 				       val->hn,
 				       val->discard_time.abs_value);
     return GNUNET_NO;
   }
   if (val->type == put_ctx->type)
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
 		"Got another value for key %s and type %d (size %u vs %u)\n",
 		GNUNET_h2s (key),
 		val->type,
@@ -174,12 +205,16 @@ put_cb (void *cls,
  * @param data data to store
  * @param type type of the value
  * @param discard_time when to discard the value in any case
- * @return 0 on error, number of bytes used otherwise
+ * @param path_info_len number of entries in 'path_info'
+ * @param path_info a path through the network
+   * @return 0 if duplicate, -1 on error, number of bytes used otherwise
  */
-static size_t
+static ssize_t
 heap_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
-                   const char *data, enum GNUNET_BLOCK_Type type,
-                   struct GNUNET_TIME_Absolute discard_time)
+		 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)
 {
   struct Plugin *plugin = cls;
   struct Value *val;
@@ -189,6 +224,8 @@ heap_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
   put_ctx.heap = plugin->heap;
   put_ctx.data = data;
   put_ctx.size = size;
+  put_ctx.path_info = path_info;
+  put_ctx.path_info_len = path_info_len;
   put_ctx.discard_time = discard_time;
   put_ctx.type = type;
   GNUNET_CONTAINER_multihashmap_get_multiple (plugin->map,
@@ -203,6 +240,11 @@ heap_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
   val->type = type;
   val->discard_time = discard_time;
   val->size = size;
+  GNUNET_array_grow (val->path_info,
+		     val->path_info_len,
+		     path_info_len);
+  memcpy (val->path_info, path_info,
+	  path_info_len * sizeof (struct GNUNET_PeerIdentity));
   (void) GNUNET_CONTAINER_multihashmap_put (plugin->map,
 					    &val->key,
 					    val,
@@ -210,7 +252,7 @@ heap_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
   val->hn = GNUNET_CONTAINER_heap_insert (plugin->heap,
 					  val,
 					  val->discard_time.abs_value);
-  return size;
+  return size + OVERHEAD;
 }
 
 
@@ -263,13 +305,17 @@ get_cb (void *cls,
   if ( (get_ctx->type != val->type) &&
        (GNUNET_BLOCK_TYPE_ANY != get_ctx->type) )
     return GNUNET_OK;
-  ret = get_ctx->iter (get_ctx->iter_cls,
+  if (NULL != get_ctx->iter)
+    ret = get_ctx->iter (get_ctx->iter_cls,
+			 key,
+			 val->size,
+			 (const char *) &val[1],
+			 val->type,
 		       val->discard_time,
-		       key,
-		       val->size,
-		       (const char *) &val[1],
-		       val->type);
-		 
+			 val->path_info_len,
+			 val->path_info);
+  else
+    ret = GNUNET_YES;
   get_ctx->cnt++;
   return ret;
 }
@@ -328,7 +374,8 @@ heap_plugin_del (void *cls)
 						       val));
   plugin->env->delete_notify (plugin->env->cls,
 			      &val->key,
-			      val->size);
+			      val->size + OVERHEAD);
+  GNUNET_free_non_null (val->path_info);
   GNUNET_free (val);
   return GNUNET_OK;
 }

+ 0 - 474
src/datacache/plugin_datacache_mysql.c

@@ -1,474 +0,0 @@
-/*
-     This file is part of GNUnet
-     (C) 2006, 2009, 2010 Christian Grothoff (and other contributing authors)
-
-     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 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     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.
-*/
-
-/**
- * @file datacache/plugin_datacache_mysql.c
- * @brief mysql for an implementation of a database backend for the datacache
- * @author Christian Grothoff
- *
- * SETUP INSTRUCTIONS:
- *
- * 1) Access mysql as root,
- *    <pre>
- *
- *    $ mysql -u root -p
- *
- *    </pre>
- *    and do the following. [You should replace $USER with the username
- *    that will be running the gnunetd process].
- * @verbatim
-      CREATE DATABASE gnunet;
-      GRANT select,insert,update,delete,create,alter,drop,create temporary tables
-         ON gnunet.* TO $USER@localhost;
-      SET PASSWORD FOR $USER@localhost=PASSWORD('$the_password_you_like');
-      FLUSH PRIVILEGES;
-   @endverbatim
- * 2) In the $HOME directory of $USER, create a ".my.cnf" file
- *    with the following lines
- * @verbatim
-      [client]
-      user=$USER
-      password=$the_password_you_like
-   @endverbatim
- *
- * Thats it -- now you can configure your datastores in GNUnet to
- * use MySQL. Note that .my.cnf file is a security risk unless its on
- * a safe partition etc. The $HOME/.my.cnf can of course be a symbolic
- * link. Even greater security risk can be achieved by setting no
- * password for $USER.  Luckily $USER has only priviledges to mess
- * up GNUnet's tables, nothing else (unless you give him more,
- * of course).<p>
- *
- * 3) Still, perhaps you should briefly try if the DB connection
- *    works. First, login as $USER. Then use,
- * @verbatim
-      $ mysql -u $USER -p $the_password_you_like
-      mysql> use gnunet;
-   @endverbatim
- *
- *    If you get the message &quot;Database changed&quot; it probably works.
- *
- *    [If you get &quot;ERROR 2002: Can't connect to local MySQL server
- *     through socket '/tmp/mysql.sock' (2)&quot; it may be resolvable by
- *     &quot;ln -s /var/run/mysqld/mysqld.sock /tmp/mysql.sock&quot;
- *     so there may be some additional trouble depending on your mysql setup.]
- *
- * PROBLEMS?
- *
- * If you have problems related to the mysql module, your best
- * friend is probably the mysql manual. The first thing to check
- * is that mysql is basically operational, that you can connect
- * to it, create tables, issue queries etc.
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_datacache_plugin.h"
-#include "gnunet_mysql_lib.h"
-#include <mysql/mysql.h>
-
-
-/**
- * Estimate of the per-entry overhead (including indices).
- */
-#define OVERHEAD ((4*2+4*2+8*2+8*2+sizeof(struct GNUNET_HashCode)*5+8))
-
-/**
- * Die with an error message that indicates
- * a failure of the command 'cmd' with the message given
- * by strerror(errno).
- */
-#define DIE_MYSQL(cmd, dbh) do { GNUNET_log(GNUNET_ERROR_TYPE__ERROR, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); GNUNET_abort(); } while(0);
-
-/**
- * Log an error message at log-level 'level' that indicates
- * a failure of the command 'cmd' on file 'filename'
- * with the message given by strerror(errno).
- */
-#define LOG_MYSQL(level, cmd, dbh) do { GNUNET_log(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); } while(0);
-
-
-/**
- * Context for all functions in this plugin.
- */
-struct Plugin
-{
-  /**
-   * Our execution environment.
-   */
-  struct GNUNET_DATACACHE_PluginEnvironment *env;
-
-  /**
-   * Handle to the mysql database.
-   */
-  struct GNUNET_MYSQL_Context *mc;
-
-#define SELECT_VALUE_STMT "SELECT value,expire FROM gn080dstore FORCE INDEX (hashidx) WHERE hash=? AND type=? AND expire >= ? LIMIT 1 OFFSET ?"
-  struct GNUNET_MYSQL_StatementHandle *select_value;
-
-#define COUNT_VALUE_STMT "SELECT count(*) FROM gn080dstore FORCE INDEX (hashidx) WHERE hash=? AND type=? AND expire >= ?"
-  struct GNUNET_MYSQL_StatementHandle *count_value;
-
-#define SELECT_OLD_VALUE_STMT "SELECT hash, vhash, type, value FROM gn080dstore FORCE INDEX (expireidx) ORDER BY puttime ASC LIMIT 1"
-  struct GNUNET_MYSQL_StatementHandle *select_old_value;
-
-#define DELETE_VALUE_STMT "DELETE FROM gn080dstore WHERE hash = ? AND vhash = ? AND type = ? AND value = ?"
-  struct GNUNET_MYSQL_StatementHandle *delete_value;
-
-#define INSERT_VALUE_STMT "INSERT INTO gn080dstore (type, puttime, expire, hash, vhash, value) "\
-                          "VALUES (?, ?, ?, ?, ?, ?)"
-  struct GNUNET_MYSQL_StatementHandle *insert_value;
-
-#define UPDATE_VALUE_STMT "UPDATE gn080dstore FORCE INDEX (allidx) SET puttime=?, expire=? "\
-                          "WHERE hash=? AND vhash=? AND type=?"
-  struct GNUNET_MYSQL_StatementHandle *update_value;
-
-};
-
-
-/**
- * Create temporary table and prepare statements.
- *
- * @param plugin plugin context
- * @return GNUNET_OK on success
- */
-static int
-itable (struct Plugin *plugin)
-{
-#define MRUNS(a) (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, a) )
-  if (MRUNS
-      ("CREATE TEMPORARY TABLE gn080dstore ("
-       "  type INT(11) UNSIGNED NOT NULL DEFAULT 0,"
-       "  puttime BIGINT UNSIGNED NOT NULL DEFAULT 0,"
-       "  expire BIGINT UNSIGNED NOT NULL DEFAULT 0,"
-       "  hash BINARY(64) NOT NULL DEFAULT '',"
-       "  vhash BINARY(64) NOT NULL DEFAULT '',"
-       "  value BLOB NOT NULL DEFAULT '',"
-       "  INDEX hashidx (hash(64),type,expire),"
-       "  INDEX allidx (hash(64),vhash(64),type)," "  INDEX expireidx (puttime)"
-       ") ENGINE=InnoDB") || MRUNS ("SET AUTOCOMMIT = 1"))
-    return GNUNET_SYSERR;
-#undef MRUNS
-#define PINIT(a,b) (NULL == (a = GNUNET_MYSQL_statement_prepare (plugin->mc, b)))
-  if (PINIT (plugin->select_value, SELECT_VALUE_STMT) ||
-      PINIT (plugin->count_value, COUNT_VALUE_STMT) ||
-      PINIT (plugin->select_old_value, SELECT_OLD_VALUE_STMT) ||
-      PINIT (plugin->delete_value, DELETE_VALUE_STMT) ||
-      PINIT (plugin->insert_value, INSERT_VALUE_STMT) ||
-      PINIT (plugin->update_value, UPDATE_VALUE_STMT))
-    return GNUNET_SYSERR;
-#undef PINIT
-  return GNUNET_OK;
-}
-
-
-/**
- * Store an item in the datastore.
- *
- * @param cls closure (our "struct Plugin")
- * @param key key to store data under
- * @param size number of bytes in data
- * @param data data to store
- * @param type type of the value
- * @param discard_time when to discard the value in any case
- * @return 0 on error, number of bytes used otherwise
- */
-static size_t
-mysql_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
-                  const char *data, enum GNUNET_BLOCK_Type type,
-                  struct GNUNET_TIME_Absolute discard_time)
-{
-  struct Plugin *plugin = cls;
-  struct GNUNET_TIME_Absolute now;
-  unsigned long k_length;
-  unsigned long h_length;
-  unsigned long v_length;
-  unsigned long long v_now;
-  unsigned long long v_discard_time;
-  unsigned int v_type;
-  struct GNUNET_HashCode vhash;
-  int ret;
-
-  if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
-    return GNUNET_SYSERR;
-  GNUNET_CRYPTO_hash (data, size, &vhash);
-  now = GNUNET_TIME_absolute_get ();
-
-  /* first try UPDATE */
-  h_length = sizeof (struct GNUNET_HashCode);
-  k_length = sizeof (struct GNUNET_HashCode);
-  v_length = size;
-  v_type = type;
-  v_now = (unsigned long long) now.abs_value;
-  v_discard_time = (unsigned long long) discard_time.abs_value;
-  if (GNUNET_OK ==
-      GNUNET_MYSQL_statement_run_prepared (plugin->mc, plugin->update_value, NULL,
-                              MYSQL_TYPE_LONGLONG, &v_now, GNUNET_YES,
-                              MYSQL_TYPE_LONGLONG, &v_discard_time, GNUNET_YES,
-                              MYSQL_TYPE_BLOB, key, sizeof (struct GNUNET_HashCode),
-                              &k_length, MYSQL_TYPE_BLOB, &vhash,
-                              sizeof (struct GNUNET_HashCode), &h_length,
-                              MYSQL_TYPE_LONG, &v_type, GNUNET_YES, -1))
-    return GNUNET_OK;
-
-  /* now try INSERT */
-  h_length = sizeof (struct GNUNET_HashCode);
-  k_length = sizeof (struct GNUNET_HashCode);
-  v_length = size;
-  if (GNUNET_OK !=
-      (ret =
-       GNUNET_MYSQL_statement_run_prepared (plugin->mc, plugin->insert_value, NULL,
-                               MYSQL_TYPE_LONG, &type, GNUNET_YES,
-                               MYSQL_TYPE_LONGLONG, &v_now, GNUNET_YES,
-                               MYSQL_TYPE_LONGLONG, &v_discard_time, GNUNET_YES,
-                               MYSQL_TYPE_BLOB, key, sizeof (struct GNUNET_HashCode),
-                               &k_length, MYSQL_TYPE_BLOB, &vhash,
-                               sizeof (struct GNUNET_HashCode), &h_length,
-                               MYSQL_TYPE_BLOB, data, (unsigned long) size,
-                               &v_length, -1)))
-  {
-    if (ret == GNUNET_SYSERR)
-      itable (plugin);
-    return GNUNET_SYSERR;
-  }
-  return size + OVERHEAD;
-}
-
-
-static int
-return_ok (void *cls, unsigned int num_values, MYSQL_BIND * values)
-{
-  return GNUNET_OK;
-}
-
-
-/**
- * Iterate over the results for a particular key
- * in the datastore.
- *
- * @param cls closure (our "struct Plugin")
- * @param key
- * @param type entries of which type are relevant?
- * @param iter maybe NULL (to just count)
- * @param iter_cls closure for iter
- * @return the number of results found
- */
-static unsigned int
-mysql_plugin_get (void *cls, const struct GNUNET_HashCode * key,
-                  enum GNUNET_BLOCK_Type type, GNUNET_DATACACHE_Iterator iter,
-                  void *iter_cls)
-{
-  struct Plugin *plugin = cls;
-  MYSQL_BIND rbind[3];
-  unsigned long h_length;
-  unsigned long v_length;
-  unsigned long long v_expire;
-  struct GNUNET_TIME_Absolute now;
-  struct GNUNET_TIME_Absolute expire;
-  unsigned int cnt;
-  unsigned long long total;
-  unsigned long long v_now;
-  unsigned int off;
-  unsigned int v_type;
-  int ret;
-  char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
-
-  now = GNUNET_TIME_absolute_get ();
-  h_length = sizeof (struct GNUNET_HashCode);
-  v_length = sizeof (buffer);
-  total = -1;
-  memset (rbind, 0, sizeof (rbind));
-  rbind[0].buffer_type = MYSQL_TYPE_LONGLONG;
-  rbind[0].buffer = &total;
-  rbind[0].is_unsigned = GNUNET_YES;
-  v_type = type;
-  v_now = (unsigned long long) now.abs_value;
-  if ((GNUNET_OK !=
-       (ret =
-        GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->count_value, 1, rbind,
-                                       return_ok, NULL, MYSQL_TYPE_BLOB, key,
-                                       sizeof (struct GNUNET_HashCode), &h_length,
-                                       MYSQL_TYPE_LONG, &v_type, GNUNET_YES,
-                                       MYSQL_TYPE_LONGLONG, &v_now, GNUNET_YES,
-                                       -1))) || (-1 == total))
-  {
-    if (ret == GNUNET_SYSERR)
-      itable (plugin);
-    return GNUNET_SYSERR;
-  }
-  if ((iter == NULL) || (total == 0))
-    return (int) total;
-
-  off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total);
-  cnt = 0;
-  while (cnt < total)
-  {
-    memset (rbind, 0, sizeof (rbind));
-    rbind[0].buffer_type = MYSQL_TYPE_BLOB;
-    rbind[0].buffer_length = sizeof (buffer);
-    rbind[0].length = &v_length;
-    rbind[0].buffer = buffer;
-    rbind[1].buffer_type = MYSQL_TYPE_LONGLONG;
-    rbind[1].is_unsigned = 1;
-    rbind[1].buffer = &v_expire;
-    off = (off + 1) % total;
-    if (GNUNET_OK !=
-        (ret =
-         GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->select_value, 2, rbind,
-                                        return_ok, NULL, MYSQL_TYPE_BLOB, key,
-                                        sizeof (struct GNUNET_HashCode), &h_length,
-                                        MYSQL_TYPE_LONG, &v_type, GNUNET_YES,
-                                        MYSQL_TYPE_LONGLONG, &v_now, GNUNET_YES,
-                                        MYSQL_TYPE_LONG, &off, GNUNET_YES, -1)))
-    {
-      if (ret == GNUNET_SYSERR)
-        itable (plugin);
-      return GNUNET_SYSERR;
-    }
-    cnt++;
-    expire.abs_value = v_expire;
-    if (GNUNET_OK != iter (iter_cls, expire, key, v_length, buffer, type))
-      break;
-  }
-  return cnt;
-}
-
-
-/**
- * Delete the entry with the lowest expiration value
- * from the datacache right now.
- *
- * @param cls closure (our "struct Plugin")
- * @return GNUNET_OK on success, GNUNET_SYSERR on error
- */
-static int
-mysql_plugin_del (void *cls)
-{
-  struct Plugin *plugin = cls;
-
-  MYSQL_BIND rbind[5];
-  unsigned int v_type;
-  struct GNUNET_HashCode v_key;
-  struct GNUNET_HashCode vhash;
-  unsigned long k_length;
-  unsigned long h_length;
-  unsigned long v_length;
-  int ret;
-  char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
-
-  k_length = sizeof (struct GNUNET_HashCode);
-  h_length = sizeof (struct GNUNET_HashCode);
-  v_length = sizeof (buffer);
-  memset (rbind, 0, sizeof (rbind));
-  rbind[0].buffer_type = MYSQL_TYPE_BLOB;
-  rbind[0].buffer_length = sizeof (struct GNUNET_HashCode);
-  rbind[0].length = &k_length;
-  rbind[0].buffer = &v_key;
-  rbind[1].buffer_type = MYSQL_TYPE_BLOB;
-  rbind[1].buffer_length = sizeof (struct GNUNET_HashCode);
-  rbind[1].length = &h_length;
-  rbind[1].buffer = &vhash;
-  rbind[2].buffer_type = MYSQL_TYPE_LONG;
-  rbind[2].is_unsigned = 1;
-  rbind[2].buffer = &v_type;
-  rbind[3].buffer_type = MYSQL_TYPE_BLOB;
-  rbind[3].buffer_length = sizeof (buffer);
-  rbind[3].length = &v_length;
-  rbind[3].buffer = buffer;
-  if ((GNUNET_OK !=
-       (ret =
-        GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->select_old_value, 4,
-                                       rbind, return_ok, NULL, -1))) ||
-      (GNUNET_OK !=
-       (ret =
-        GNUNET_MYSQL_statement_run_prepared (plugin->mc, plugin->delete_value, NULL,
-                                MYSQL_TYPE_BLOB, &v_key,
-                                sizeof (struct GNUNET_HashCode), &k_length,
-                                MYSQL_TYPE_BLOB, &vhash,
-                                sizeof (struct GNUNET_HashCode), &h_length,
-                                MYSQL_TYPE_LONG, &v_type, GNUNET_YES,
-                                MYSQL_TYPE_BLOB, buffer,
-                                (unsigned long) sizeof (buffer), &v_length,
-                                -1))))
-  {
-    if (ret == GNUNET_SYSERR)
-      itable (plugin);
-    return GNUNET_SYSERR;
-  }
-  plugin->env->delete_notify (plugin->env->cls, &v_key, v_length + OVERHEAD);
-
-  return GNUNET_OK;
-}
-
-
-/**
- * Entry point for the plugin.
- *
- * @param cls closure (the "struct GNUNET_DATACACHE_PluginEnvironmnet")
- * @return the plugin's closure (our "struct Plugin")
- */
-void *
-libgnunet_plugin_datacache_mysql_init (void *cls)
-{
-  struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
-  struct GNUNET_DATACACHE_PluginFunctions *api;
-  struct Plugin *plugin;
-
-  plugin = GNUNET_malloc (sizeof (struct Plugin));
-  plugin->env = env;
-  plugin->mc = GNUNET_MYSQL_context_create (env->cfg, "datacache-mysql");
-  if ( (NULL == plugin->mc) ||
-       (GNUNET_OK != itable (plugin)) )
-  {
-    if (NULL != plugin->mc)
-      GNUNET_MYSQL_context_destroy (plugin->mc);
-    GNUNET_free (plugin);
-    return NULL;
-  }
-  api = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_PluginFunctions));
-  api->cls = plugin;
-  api->get = &mysql_plugin_get;
-  api->put = &mysql_plugin_put;
-  api->del = &mysql_plugin_del;
-  GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "mysql",
-                   _("MySQL datacache running\n"));
-  return api;
-}
-
-
-/**
- * Exit point from the plugin.
- *
- * @param cls closure (our "struct Plugin")
- * @return NULL
- */
-void *
-libgnunet_plugin_datacache_mysql_done (void *cls)
-{
-  struct GNUNET_DATACACHE_PluginFunctions *api = cls;
-  struct Plugin *plugin = api->cls;
-
-  GNUNET_MYSQL_context_destroy (plugin->mc);
-  GNUNET_free (plugin);
-  GNUNET_free (api);
-  return NULL;
-}
-
-
-/* end of plugin_datacache_mysql.c */

+ 47 - 22
src/datacache/plugin_datacache_postgres.c

@@ -75,13 +75,18 @@ init_connection (struct Plugin *plugin)
               "  type INTEGER NOT NULL DEFAULT 0,"
               "  discard_time BIGINT NOT NULL DEFAULT 0,"
               "  key BYTEA NOT NULL DEFAULT '',"
-              "  value BYTEA NOT NULL DEFAULT '')" "WITH OIDS");
-  if ((ret == NULL) || ((PQresultStatus (ret) != PGRES_COMMAND_OK) && (0 != strcmp ("42P07",    /* duplicate table */
-                                                                                    PQresultErrorField
-                                                                                    (ret,
-                                                                                     PG_DIAG_SQLSTATE)))))
+              "  value BYTEA NOT NULL DEFAULT '',"
+              "  path BYTEA DEFAULT '')"
+	      "WITH OIDS");
+  if ( (ret == NULL) || 
+       ((PQresultStatus (ret) != PGRES_COMMAND_OK) && 
+	(0 != strcmp ("42P07",    /* duplicate table */
+		      PQresultErrorField
+		      (ret,
+		       PG_DIAG_SQLSTATE)))))
   {
-    (void) GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "CREATE TABLE",
+    (void) GNUNET_POSTGRES_check_result (plugin->dbh, ret, 
+					 PGRES_COMMAND_OK, "CREATE TABLE",
 					 "gn090dc");
     PQfinish (plugin->dbh);
     plugin->dbh = NULL;
@@ -123,11 +128,11 @@ init_connection (struct Plugin *plugin)
   PQclear (ret);
   if ((GNUNET_OK !=
        GNUNET_POSTGRES_prepare (plugin->dbh, "getkt",
-                   "SELECT discard_time,type,value FROM gn090dc "
+                   "SELECT discard_time,type,value,path FROM gn090dc "
                    "WHERE key=$1 AND type=$2 ", 2)) ||
       (GNUNET_OK !=
        GNUNET_POSTGRES_prepare (plugin->dbh, "getk",
-                   "SELECT discard_time,type,value FROM gn090dc "
+                   "SELECT discard_time,type,value,path FROM gn090dc "
                    "WHERE key=$1", 1)) ||
       (GNUNET_OK !=
        GNUNET_POSTGRES_prepare (plugin->dbh, "getm",
@@ -137,8 +142,8 @@ init_connection (struct Plugin *plugin)
        GNUNET_POSTGRES_prepare (plugin->dbh, "delrow", "DELETE FROM gn090dc WHERE oid=$1", 1)) ||
       (GNUNET_OK !=
        GNUNET_POSTGRES_prepare (plugin->dbh, "put",
-                   "INSERT INTO gn090dc (type, discard_time, key, value) "
-                   "VALUES ($1, $2, $3, $4)", 4)))
+                   "INSERT INTO gn090dc (type, discard_time, key, value, path) "
+                   "VALUES ($1, $2, $3, $4, $5)", 5)))
   {
     PQfinish (plugin->dbh);
     plugin->dbh = NULL;
@@ -157,12 +162,16 @@ init_connection (struct Plugin *plugin)
  * @param data data to store
  * @param type type of the value
  * @param discard_time when to discard the value in any case
- * @return 0 on error, number of bytes used otherwise
+ * @param path_info_len number of entries in 'path_info'
+ * @param path_info a path through the network
+ * @return 0 if duplicate, -1 on error, number of bytes used otherwise
  */
-static size_t
+static ssize_t
 postgres_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
                      const char *data, enum GNUNET_BLOCK_Type type,
-                     struct GNUNET_TIME_Absolute discard_time)
+                     struct GNUNET_TIME_Absolute discard_time,
+		     unsigned int path_info_len,
+		     const struct GNUNET_PeerIdentity *path_info)
 {
   struct Plugin *plugin = cls;
   PGresult *ret;
@@ -173,22 +182,25 @@ postgres_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
     (const char *) &btype,
     (const char *) &bexpi,
     (const char *) key,
-    (const char *) data
+    (const char *) data,
+    (const char *) path_info
   };
   int paramLengths[] = {
     sizeof (btype),
     sizeof (bexpi),
     sizeof (struct GNUNET_HashCode),
-    size
+    size,
+    path_info_len * sizeof (struct GNUNET_PeerIdentity)
   };
-  const int paramFormats[] = { 1, 1, 1, 1 };
+  const int paramFormats[] = { 1, 1, 1, 1, 1 };
 
   ret =
-      PQexecPrepared (plugin->dbh, "put", 4, paramValues, paramLengths,
+      PQexecPrepared (plugin->dbh, "put", 5, paramValues, paramLengths,
                       paramFormats, 1);
   if (GNUNET_OK !=
-      GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "PQexecPrepared", "put"))
-    return GNUNET_SYSERR;
+      GNUNET_POSTGRES_check_result (plugin->dbh, ret, 
+				    PGRES_COMMAND_OK, "PQexecPrepared", "put"))
+    return -1;
   PQclear (ret);
   return size + OVERHEAD;
 }
@@ -226,6 +238,8 @@ postgres_plugin_get (void *cls, const struct GNUNET_HashCode * key,
   uint32_t size;
   unsigned int cnt;
   unsigned int i;
+  unsigned int path_len;
+  const struct GNUNET_PeerIdentity *path;
   PGresult *res;
 
   res =
@@ -254,7 +268,7 @@ postgres_plugin_get (void *cls, const struct GNUNET_HashCode * key,
     PQclear (res);
     return cnt;
   }
-  if ((3 != PQnfields (res)) || (sizeof (uint64_t) != PQfsize (res, 0)) ||
+  if ((4 != PQnfields (res)) || (sizeof (uint64_t) != PQfsize (res, 0)) ||
       (sizeof (uint32_t) != PQfsize (res, 1)))
   {
     GNUNET_break (0);
@@ -267,12 +281,23 @@ postgres_plugin_get (void *cls, const struct GNUNET_HashCode * key,
         GNUNET_ntohll (*(uint64_t *) PQgetvalue (res, i, 0));
     type = ntohl (*(uint32_t *) PQgetvalue (res, i, 1));
     size = PQgetlength (res, i, 2);
+    path_len = PQgetlength (res, i, 3);
+    if (0 != (path_len % sizeof (struct GNUNET_PeerIdentity)))
+    {
+      GNUNET_break (0);
+      path_len = 0;
+    }
+    path_len %= sizeof (struct GNUNET_PeerIdentity);
+    path = (const struct GNUNET_PeerIdentity *) PQgetvalue (res, i, 3);
     LOG (GNUNET_ERROR_TYPE_DEBUG, 
 	 "Found result of size %u bytes and type %u in database\n",
 	 (unsigned int) size, (unsigned int) type);
     if (GNUNET_SYSERR ==
-        iter (iter_cls, expiration_time, key, size, PQgetvalue (res, i, 2),
-              (enum GNUNET_BLOCK_Type) type))
+        iter (iter_cls, key, size, PQgetvalue (res, i, 2),
+              (enum GNUNET_BLOCK_Type) type,
+	      expiration_time,
+	      path_len,
+	      path))
     {
       LOG (GNUNET_ERROR_TYPE_DEBUG, 
 	   "Ending iteration (client error)\n");

+ 39 - 14
src/datacache/plugin_datacache_sqlite.c

@@ -95,12 +95,16 @@ sq_prepare (sqlite3 * dbh, const char *zSql,    /* SQL statement, UTF-8 encoded
  * @param data data to store
  * @param type type of the value
  * @param discard_time when to discard the value in any case
- * @return 0 on error, number of bytes used otherwise
+   * @return 0 if duplicate, -1 on error, number of bytes used otherwise
  */
-static size_t
-sqlite_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
-                   const char *data, enum GNUNET_BLOCK_Type type,
-                   struct GNUNET_TIME_Absolute discard_time)
+static ssize_t
+sqlite_plugin_put (void *cls,
+		   const struct GNUNET_HashCode *key,
+		   size_t 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)
 {
   struct Plugin *plugin = cls;
   sqlite3_stmt *stmt;
@@ -115,31 +119,38 @@ sqlite_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
     dval = INT64_MAX;
   if (sq_prepare
       (plugin->dbh,
-       "INSERT INTO ds090 (type, expire, key, value) VALUES (?, ?, ?, ?)",
+       "INSERT INTO ds090 (type, expire, key, value, path) VALUES (?, ?, ?, ?, ?)",
        &stmt) != SQLITE_OK)
   {
     LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sq_prepare");
-    return 0;
+    return -1;
   }
   if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, type)) ||
       (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, dval)) ||
       (SQLITE_OK !=
-       sqlite3_bind_blob (stmt, 3, key, sizeof (struct GNUNET_HashCode),
+       sqlite3_bind_blob (stmt, 3,
+			  key, sizeof (struct GNUNET_HashCode),
                           SQLITE_TRANSIENT)) ||
-      (SQLITE_OK != sqlite3_bind_blob (stmt, 4, data, size, SQLITE_TRANSIENT)))
+      (SQLITE_OK != sqlite3_bind_blob (stmt, 4,
+				       data, size, 
+				       SQLITE_TRANSIENT)) ||
+      (SQLITE_OK != sqlite3_bind_blob (stmt, 5, 
+				       path_info, 
+				       path_info_len * sizeof (struct GNUNET_PeerIdentity), 
+				       SQLITE_TRANSIENT)))
   {
     LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_bind_xxx");
     sqlite3_finalize (stmt);
-    return 0;
+    return -1;
   }
   if (SQLITE_DONE != sqlite3_step (stmt))
   {
     LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_step");
     sqlite3_finalize (stmt);
-    return 0;
+    return -1;
   }
   if (SQLITE_OK != sqlite3_finalize (stmt))
     LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
@@ -173,8 +184,10 @@ sqlite_plugin_get (void *cls, const struct GNUNET_HashCode * key,
   unsigned int cnt;
   unsigned int off;
   unsigned int total;
+  unsigned int psize;
   char scratch[256];
   int64_t ntime;
+  const struct GNUNET_PeerIdentity *path;
 
   now = GNUNET_TIME_absolute_get ();
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' for key `%4s'\n", "GET",
@@ -229,7 +242,7 @@ sqlite_plugin_get (void *cls, const struct GNUNET_HashCode * key,
   {
     off = (off + 1) % total;
     GNUNET_snprintf (scratch, sizeof (scratch),
-                     "SELECT value,expire FROM ds090 WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET %u",
+                     "SELECT value,expire,path FROM ds090 WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET %u",
                      off);
     if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK)
     {
@@ -253,6 +266,17 @@ sqlite_plugin_get (void *cls, const struct GNUNET_HashCode * key,
     size = sqlite3_column_bytes (stmt, 0);
     dat = sqlite3_column_blob (stmt, 0);
     exp.abs_value = sqlite3_column_int64 (stmt, 1);
+    psize = sqlite3_column_bytes (stmt, 2);
+    if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
+    {
+      GNUNET_break (0);
+      psize = 0;
+    }
+    psize /= sizeof (struct GNUNET_PeerIdentity);
+    if (0 != psize)
+      path = sqlite3_column_blob (stmt, 2);
+    else
+      path = NULL;
     ntime = (int64_t) exp.abs_value;
     if (ntime == INT64_MAX)
       exp = GNUNET_TIME_UNIT_FOREVER_ABS;
@@ -260,7 +284,7 @@ sqlite_plugin_get (void *cls, const struct GNUNET_HashCode * key,
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Found %u-byte result when processing `%s' for key `%4s'\n",
          (unsigned int) size, "GET", GNUNET_h2s (key));
-    if (GNUNET_OK != iter (iter_cls, exp, key, size, dat, type))
+    if (GNUNET_OK != iter (iter_cls, key, size, dat, type, exp, psize, path))
     {
       sqlite3_finalize (stmt);
       break;
@@ -408,7 +432,8 @@ libgnunet_plugin_datacache_sqlite_init (void *cls)
                 "CREATE TABLE ds090 (" "  type INTEGER NOT NULL DEFAULT 0,"
                 "  expire INTEGER NOT NULL DEFAULT 0,"
                 "  key BLOB NOT NULL DEFAULT '',"
-                "  value BLOB NOT NULL DEFAULT '')");
+                "  value BLOB NOT NULL DEFAULT '',"
+		"  path BLOB DEFAULT '')");
   SQLITE3_EXEC (dbh, "CREATE INDEX idx_hashidx ON ds090 (key,type,expire)");
   SQLITE3_EXEC (dbh, "CREATE INDEX idx_expire ON ds090 (expire)");
   plugin = GNUNET_malloc (sizeof (struct Plugin));

+ 8 - 4
src/datacache/plugin_datacache_template.c

@@ -49,15 +49,19 @@ struct Plugin
  * @param data data to store
  * @param type type of the value
  * @param discard_time when to discard the value in any case
- * @return 0 on error, number of bytes used otherwise
+ * @param path_info_len number of entries in 'path_info'
+ * @param path_info a path through the network
+ * @return 0 if duplicate, -1 on error, number of bytes used otherwise
  */
-static size_t
+static ssize_t
 template_plugin_put (void *cls, const struct GNUNET_HashCode * key, size_t size,
                      const char *data, enum GNUNET_BLOCK_Type type,
-                     struct GNUNET_TIME_Absolute discard_time)
+                     struct GNUNET_TIME_Absolute discard_time,
+		     unsigned int path_info_len,
+		     const struct GNUNET_PeerIdentity *path_info)
 {
   GNUNET_break (0);
-  return 0;
+  return -1;
 }
 
 

+ 11 - 5
src/datacache/test_datacache.c

@@ -38,9 +38,13 @@ static const char *plugin_name;
 
 
 static int
-checkIt (void *cls, struct GNUNET_TIME_Absolute exp,
-         const struct GNUNET_HashCode * key, size_t size, const char *data,
-         enum GNUNET_BLOCK_Type type)
+checkIt (void *cls, 
+         const struct GNUNET_HashCode *key, 
+	 size_t size, const char *data,
+         enum GNUNET_BLOCK_Type type,
+	 struct GNUNET_TIME_Absolute exp,
+	 unsigned int path_len,
+	 const struct GNUNET_PeerIdentity *path)
 {
   if (size != sizeof (struct GNUNET_HashCode))
   {
@@ -83,7 +87,8 @@ run (void *cls, char *const *args, const char *cfgfile,
     GNUNET_CRYPTO_hash (&k, sizeof (struct GNUNET_HashCode), &n);
     ASSERT (GNUNET_OK ==
             GNUNET_DATACACHE_put (h, &k, sizeof (struct GNUNET_HashCode),
-                                  (const char *) &n, 1 + i % 16, exp));
+                                  (const char *) &n, 1 + i % 16, exp, 
+				  0, NULL));
     k = n;
   }
   memset (&k, 0, sizeof (struct GNUNET_HashCode));
@@ -99,7 +104,8 @@ run (void *cls, char *const *args, const char *cfgfile,
   ASSERT (GNUNET_OK ==
           GNUNET_DATACACHE_put (h, &k, sizeof (struct GNUNET_HashCode),
                                 (const char *) &n, 792,
-                                GNUNET_TIME_UNIT_FOREVER_ABS));
+                                GNUNET_TIME_UNIT_FOREVER_ABS,
+				0, NULL));
   ASSERT (0 != GNUNET_DATACACHE_get (h, &k, 792, &checkIt, &n));
 
   GNUNET_DATACACHE_destroy (h);

+ 4 - 0
src/datacache/test_datacache_data_heap.conf

@@ -0,0 +1,4 @@
+[testcache]
+QUOTA = 1 MB
+DATABASE = heap
+

+ 0 - 13
src/datacache/test_datacache_data_mysql.conf

@@ -1,13 +0,0 @@
-[testcache]
-QUOTA = 1 MB
-DATABASE = mysql
-
-[datacache-mysql]
-DATABASE = gnunetcheck
-# CONFIG = ~/.my.cnf
-# USER =
-# PASSWORD =
-# HOST = 
-# PORT = 
-
-

+ 1 - 1
src/datacache/test_datacache_quota.c

@@ -73,7 +73,7 @@ run (void *cls, char *const *args, const char *cfgfile,
     {
       exp.abs_value++;
       buf[j] = i;
-      ASSERT (GNUNET_OK == GNUNET_DATACACHE_put (h, &k, j, buf, 1 + i, exp));
+      ASSERT (GNUNET_OK == GNUNET_DATACACHE_put (h, &k, j, buf, 1 + i, exp, 0, NULL));
       ASSERT (0 < GNUNET_DATACACHE_get (h, &k, 1 + i, NULL, NULL));
     }
     k = n;

+ 16 - 64
src/dht/gnunet-service-dht_datacache.c

@@ -38,28 +38,6 @@
 static struct GNUNET_DATACACHE_Handle *datacache;
 
 
-/**
- * Entry for inserting data into datacache from the DHT.
- */
-struct DHTPutEntry
-{
-  /**
-   * Size of data.
-   */
-  uint16_t data_size;
-
-  /**
-   * Length of recorded path.
-   */
-  uint16_t path_length;
-
-  /* PATH ENTRIES */
-
-  /* PUT DATA */
-
-};
-
-
 /**
  * Handle a datum we've received from another peer.  Cache if
  * possible.
@@ -80,14 +58,7 @@ GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration,
                           enum GNUNET_BLOCK_Type type, size_t data_size,
                           const void *data)
 {
-  size_t plen =
-      data_size + put_path_length * sizeof (struct GNUNET_PeerIdentity) +
-      sizeof (struct DHTPutEntry);
-  char buf[plen];
-  struct DHTPutEntry *pe;
-  struct GNUNET_PeerIdentity *pp;
-
-  if (datacache == NULL)
+  if (NULL == datacache)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                 _("%s request received, but have no datacache!\n"), "PUT");
@@ -102,14 +73,9 @@ GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration,
   GNUNET_STATISTICS_update (GDS_stats,
                             gettext_noop ("# ITEMS stored in datacache"), 1,
                             GNUNET_NO);
-  pe = (struct DHTPutEntry *) buf;
-  pe->data_size = htons (data_size);
-  pe->path_length = htons ((uint16_t) put_path_length);
-  pp = (struct GNUNET_PeerIdentity *) &pe[1];
-  memcpy (pp, put_path, put_path_length * sizeof (struct GNUNET_PeerIdentity));
-  memcpy (&pp[put_path_length], data, data_size);
-  (void) GNUNET_DATACACHE_put (datacache, key, plen, (const char *) pe, type,
-                               expiration);
+  (void) GNUNET_DATACACHE_put (datacache, key, 
+			       data_size, data, type,
+                               expiration, put_path_length, put_path);
 }
 
 
@@ -159,40 +125,26 @@ struct GetRequestContext
  * @param size the size of the data identified by key
  * @param data the actual data
  * @param type the type of the data
- *
+ * @param put_path_length number of peers in 'put_path'
+ * @param put_path path the reply took on put
  * @return GNUNET_OK to continue iteration, anything else
  * to stop iteration.
  */
 static int
-datacache_get_iterator (void *cls, struct GNUNET_TIME_Absolute exp,
+datacache_get_iterator (void *cls, 
                         const struct GNUNET_HashCode * key, size_t size,
-                        const char *data, enum GNUNET_BLOCK_Type type)
+                        const char *data, enum GNUNET_BLOCK_Type type,
+			struct GNUNET_TIME_Absolute exp,
+			unsigned int put_path_length,
+			const struct GNUNET_PeerIdentity *put_path)
 {
   struct GetRequestContext *ctx = cls;
-  const struct DHTPutEntry *pe;
-  const struct GNUNET_PeerIdentity *pp;
-  const char *rdata;
-  size_t rdata_size;
-  uint16_t put_path_length;
   enum GNUNET_BLOCK_EvaluationResult eval;
 
-  pe = (const struct DHTPutEntry *) data;
-  put_path_length = ntohs (pe->path_length);
-  rdata_size = ntohs (pe->data_size);
-
-  if (size !=
-      sizeof (struct DHTPutEntry) + rdata_size +
-      (put_path_length * sizeof (struct GNUNET_PeerIdentity)))
-  {
-    GNUNET_break (0);
-    return GNUNET_OK;
-  }
-  pp = (const struct GNUNET_PeerIdentity *) &pe[1];
-  rdata = (const char *) &pp[put_path_length];
   eval =
       GNUNET_BLOCK_evaluate (GDS_block_context, type, key, ctx->reply_bf,
                              ctx->reply_bf_mutator, ctx->xquery,
-                             ctx->xquery_size, rdata, rdata_size);
+                             ctx->xquery_size, data, size);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Found reply for query %s in datacache, evaluation result is %d\n",
               GNUNET_h2s (key), (int) eval);
@@ -206,11 +158,11 @@ datacache_get_iterator (void *cls, struct GNUNET_TIME_Absolute exp,
                               gettext_noop
                               ("# Good RESULTS found in datacache"), 1,
                               GNUNET_NO);
-    GDS_CLIENTS_handle_reply (exp, key, 0, NULL, put_path_length, pp, type,
-                              rdata_size, rdata);
+    GDS_CLIENTS_handle_reply (exp, key, 0, NULL, put_path_length, put_path, type,
+                              size, data);
     /* forward to other peers */
-    GDS_ROUTING_process (type, exp, key, put_path_length, pp, 0, NULL, rdata,
-                         rdata_size);
+    GDS_ROUTING_process (type, exp, key, put_path_length, put_path, 0, NULL, data,
+                         size);
     break;
   case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
     GNUNET_STATISTICS_update (GDS_stats,

+ 14 - 6
src/include/gnunet_datacache_lib.h

@@ -74,18 +74,22 @@ GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h);
  * An iterator over a set of items stored in the datacache.
  *
  * @param cls closure
- * @param exp when will the content expire?
  * @param key key for the content
  * @param size number of bytes in data
  * @param data content stored
  * @param type type of the content
+ * @param exp when will the content expire?
+ * @param path_info_len number of entries in 'path_info'
+ * @param path_info a path through the network
  * @return GNUNET_OK to continue iterating, GNUNET_SYSERR to abort
  */
 typedef int (*GNUNET_DATACACHE_Iterator) (void *cls,
-                                          struct GNUNET_TIME_Absolute exp,
-                                          const struct GNUNET_HashCode * key,
+                                          const struct GNUNET_HashCode *key,
                                           size_t size, const char *data,
-                                          enum GNUNET_BLOCK_Type type);
+                                          enum GNUNET_BLOCK_Type type,
+                                          struct GNUNET_TIME_Absolute exp,
+					  unsigned int path_info_len,
+					  const struct GNUNET_PeerIdentity *path_info);
 
 
 /**
@@ -97,13 +101,17 @@ typedef int (*GNUNET_DATACACHE_Iterator) (void *cls,
  * @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 'path_info'
+ * @param path_info a path through the network
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error, GNUNET_NO if duplicate
  */
 int
 GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h,
                       const struct GNUNET_HashCode * key, size_t size,
                       const char *data, enum GNUNET_BLOCK_Type type,
-                      struct GNUNET_TIME_Absolute discard_time);
+                      struct GNUNET_TIME_Absolute discard_time,
+		      unsigned int path_info_len,
+		      const struct GNUNET_PeerIdentity *path_info);
 
 
 /**

+ 8 - 4
src/include/gnunet_datacache_plugin.h

@@ -107,11 +107,15 @@ struct GNUNET_DATACACHE_PluginFunctions
    * @param data data to store
    * @param type type of the value
    * @param discard_time when to discard the value in any case
-   * @return 0 on error, number of bytes used otherwise
+   * @param path_info_len number of entries in 'path_info'
+   * @param path_info a path through the network
+   * @return 0 if duplicate, -1 on error, number of bytes used otherwise
    */
-       size_t (*put) (void *cls, const struct GNUNET_HashCode * key, size_t size,
-                      const char *data, enum GNUNET_BLOCK_Type type,
-                      struct GNUNET_TIME_Absolute discard_time);
+  ssize_t (*put) (void *cls, const struct GNUNET_HashCode * key, size_t 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);
 
 
   /**