gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r8782 - in gnunet: . src src/datacache src/datastore src/in


From: gnunet
Subject: [GNUnet-SVN] r8782 - in gnunet: . src src/datacache src/datastore src/include
Date: Sat, 25 Jul 2009 16:24:42 -0600

Author: grothoff
Date: 2009-07-25 16:24:42 -0600 (Sat, 25 Jul 2009)
New Revision: 8782

Added:
   gnunet/src/datacache/
   gnunet/src/datacache/Makefile.am
   gnunet/src/datacache/datacache_api.c
   gnunet/src/datacache/plugin_datacache.h
   gnunet/src/datacache/plugin_datacache_sqlite.c
   gnunet/src/datacache/plugin_datacache_template.c
   gnunet/src/datacache/test_datacache_api.c
Modified:
   gnunet/TODO
   gnunet/configure.ac
   gnunet/src/Makefile.am
   gnunet/src/datastore/Makefile.am
   gnunet/src/datastore/plugin_datastore_template.c
   gnunet/src/include/gnunet_datacache_lib.h
Log:
towards datacache implementation

Modified: gnunet/TODO
===================================================================
--- gnunet/TODO 2009-07-25 21:32:23 UTC (rev 8781)
+++ gnunet/TODO 2009-07-25 22:24:42 UTC (rev 8782)
@@ -58,7 +58,7 @@
 
 
 Module features to implement:
-* Dstore (needed for DHT)
+* datacache (needed for DHT)
   - design plugin API
   - implement sqlite-based dstore plugin
   - implement dstore API

Modified: gnunet/configure.ac
===================================================================
--- gnunet/configure.ac 2009-07-25 21:32:23 UTC (rev 8781)
+++ gnunet/configure.ac 2009-07-25 22:24:42 UTC (rev 8782)
@@ -745,6 +745,7 @@
 src/Makefile
 src/arm/Makefile
 src/core/Makefile
+src/datacache/Makefile
 src/datastore/Makefile
 src/fragmentation/Makefile
 src/hello/Makefile

Modified: gnunet/src/Makefile.am
===================================================================
--- gnunet/src/Makefile.am      2009-07-25 21:32:23 UTC (rev 8781)
+++ gnunet/src/Makefile.am      2009-07-25 22:24:42 UTC (rev 8782)
@@ -11,6 +11,8 @@
   include $(INTLEMU_SUBDIRS) \
   util \
   arm \
+  datacache \
+  datastore \
   fragmentation \
   hello \
   peerinfo \
@@ -19,7 +21,6 @@
   template \
   transport \
   core \
-  datastore \
   $(HOSTLIST_DIR) \
   topology 
 

Added: gnunet/src/datacache/Makefile.am
===================================================================
--- gnunet/src/datacache/Makefile.am                            (rev 0)
+++ gnunet/src/datacache/Makefile.am    2009-07-25 22:24:42 UTC (rev 8782)
@@ -0,0 +1,76 @@
+INCLUDES = -I$(top_srcdir)/src/include
+
+plugindir = $(libdir)/gnunet
+
+if MINGW
+  WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
+endif
+
+if USE_COVERAGE
+  AM_CFLAGS = --coverage -O0
+  XLIBS = -lgcov
+endif
+
+
+lib_LTLIBRARIES = \
+  libgnunetdatacache.la
+
+libgnunetdatacache_la_SOURCES = \
+  datacache_api.c plugin_datacache.h
+libgnunetdatacache_la_LIBADD = \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(GN_LIBINTL) 
+libgnunetdatacache_la_LDFLAGS = \
+  $(GN_LIB_LDFLAGS) $(WINFLAGS) \
+  -version-info 0:0:0
+
+
+plugin_LTLIBRARIES = \
+  libgnunet_plugin_datacache_sqlite.la \
+  libgnunet_plugin_datacache_template.la 
+
+
+libgnunet_plugin_datacache_sqlite_la_SOURCES = \
+  plugin_datacache_sqlite.c
+libgnunet_plugin_datacache_sqlite_la_LIBADD = \
+  $(top_builddir)/src/statistics/libgnunetstatistics.la \
+  $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3
+libgnunet_plugin_datacache_sqlite_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+
+libgnunet_plugin_datacache_template_la_SOURCES = \
+  plugin_datacache_template.c
+libgnunet_plugin_datacache_template_la_LIBADD = \
+  $(top_builddir)/src/util/libgnunetutil.la $(XLIBS)
+libgnunet_plugin_datacache_template_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+
+
+#check_PROGRAMS = \
+# test_datacache_api \
+# perf_datacache_api \
+# perf_plugin_datacache
+#
+#TESTS = $(check_PROGRAMS)
+#
+#test_datacache_api_SOURCES = \
+# test_datacache_api.c
+#test_datacache_api_LDADD = \
+# $(top_builddir)/src/datacache/libgnunetdatacache.la \
+# $(top_builddir)/src/util/libgnunetutil.la  
+#
+#perf_datacache_api_SOURCES = \
+# perf_datacache_api.c
+#perf_datacache_api_LDADD = \
+# $(top_builddir)/src/datacache/libgnunetdatacache.la \
+# $(top_builddir)/src/util/libgnunetutil.la  
+#
+#perf_plugin_datacache_SOURCES = \
+# perf_plugin_datacache.c
+#perf_plugin_datacache_LDADD = \
+# $(top_builddir)/src/util/libgnunetutil.la  
+#
+#
+#EXTRA_DIST = \
+# test_datacache_api_data.conf \
+# perf_plugin_datacache_data.conf

Added: gnunet/src/datacache/datacache_api.c
===================================================================
--- gnunet/src/datacache/datacache_api.c                                (rev 0)
+++ gnunet/src/datacache/datacache_api.c        2009-07-25 22:24:42 UTC (rev 
8782)
@@ -0,0 +1,261 @@
+/*
+     This file is part of GNUnet
+     (C) 2004, 2005, 2006, 2007, 2009 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 2, 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/datacache_api.c
+ * @brief datacache API implementation
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_datacache_lib.h"
+#include "plugin_datacache.h"
+
+/**
+ * Internal state of the datacache library.
+ */
+struct GNUNET_DATACACHE_Handle
+{
+
+  /**
+   * Our datastore plugin (NULL if not available).
+   */
+  struct DatastorePlugin *plugin;
+  
+  /**
+   * Bloomfilter to quickly tell if we don't have the content.
+   */
+  struct GNUNET_CONTAINER_BloomFilter *filter;
+
+  /**
+   * Our configuration.
+   */
+  struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  /**
+   * Configuration section to use.
+   */
+  char *section;
+
+  /**
+   * API of the transport as returned by the plugin's
+   * initialization function.
+   */
+  struct GNUNET_DATACACHE_PluginFunctions *api;
+
+  /**
+   * Short name for the plugin (i.e. "sqlite").
+   */
+  char *short_name;
+
+  /**
+   * Name of the library (i.e. "gnunet_plugin_datacache_sqlite").
+   */
+  char *lib_name;
+
+  /**
+   * Environment provided to our plugin.
+   */
+  struct GNUNET_DATASTORE_PluginEnvironment env;
+
+  /**
+   * How much space is in use right now?
+   */
+  unsigned long long utilization;
+
+};
+
+
+/**
+ * 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
+ */
+static void 
+env_delete_notify (void *cls,
+                  const GNUNET_HashCode *key,
+                  uint32_t size)
+{
+  struct GNUNET_DATACACHE_Handle * h = cls;
+  GNUNET_assert (h->utilization >= size);
+  h->utilization -= size;
+  GNUNET_CONTAINER_bloomfilter_remove (h->filter, key);
+}
+
+
+/**
+ * Create a data cache.
+ *
+ * @param sched scheduler to use
+ * @param cfg configuration to use
+ * @param section section in the configuration that contains our options
+ * @return handle to use to access the service
+ */
+struct GNUNET_DATACACHE_Handle *
+GNUNET_DATACACHE_create (struct GNUNET_SCHEDULER_Handle *sched,
+                        struct GNUNET_CONFIGURATION_Handle *cfg,
+                        const char *section)
+{
+  unsigned int bf_size;
+  struct GNUNET_DATACACHE_Handle *ret;
+  struct DatacachePlugin *ret;
+  char *libname;
+  char *name;
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (c,
+                                             section, "QUOTA", &quota))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("No `%s' specified for `%s' in configuration!\n"),
+                 "QUOTA",
+                 section);
+      return;
+    }
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_string (cfg,
+                                             section,
+                                            "DATABASE", &name))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("No `%s' specified for `%s' in configuration!\n"),
+                 "DATABASE",
+                 section);
+      return NULL;
+    }
+  bf_size = quota / 32; /* 8 bit per entry, 1 bit per 32 kb in DB */
+
+  ret = GNUNET_malloc (sizeof(struct GNUNET_DATACACHE_Handle));
+  /* FIXME: create a temporary file for the bloomfilter to better
+     support deletions! */
+  ret->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, bf_size, 5);  /* 
approx. 3% false positives at max use */  
+  ret->section = GNUNET_strdup (section);
+  ret->env.sched = s;
+  ret->env.cfg = cfg;
+  ret->env.delete_notify = &env_delete_notify;  
+  ret->env.section = ret->section;
+  ret->env.cls = ret;
+  ret->env.delete_notify = &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);
+  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;
+    }
+  return ret;
+}
+
+
+/**
+ * Destroy a data cache (and free associated resources).
+ *
+ * @param h handle to the datastore
+ */
+void GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h)
+{
+  GNUNET_CONTAINER_bloomfilter_free (h->filter);
+  if (h->api != NULL)
+    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_free (h);
+}
+
+
+/**
+ * Store an item in the datastore.
+ *
+ * @param h handle to the datacache
+ * @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 GNUNET_OK on success, GNUNET_SYSERR on error (full, etc.)
+ */
+int 
+GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h,
+                     const GNUNET_HashCode * key,
+                     uint32_t size,
+                     const char *data,
+                     unsigned int type,
+                     struct GNUNET_TIME_Absolute discard_time)
+{
+  uint32_t used;
+
+  used = h->api->put (h->api->cls,
+                     key,
+                     size,
+                     data,
+                     type,
+                     discard_time);
+  if (used == 0)
+    return GNUNET_SYSERR;
+  GNUNET_CONTAINER_bloomfilter_add (h->filter, key);
+  while (h->utilization + used > h->api.quota)
+    GNUNET_assert (GNUNET_OK == h->api->del (h->api->cls));
+  h->utilization += used;
+  return GNUNET_OK;
+}
+
+
+/**
+ * Iterate over the results for a particular key
+ * in the datacache.
+ *
+ * @param h handle to the datacache
+ * @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
+ * @return the number of results found
+ */
+unsigned int 
+GNUNET_DATACACHE_get (struct GNUNET_DATACACHE_Handle *h,
+                     const GNUNET_HashCode * key,
+                     unsigned int type, 
+                     GNUNET_DATACACHE_Iterator iter,
+                     void *iter_cls)
+{
+  if (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_test (h->filter,
+                                                     key))
+    return 0; /* can not be present */
+  return h->api->get (h->api->cls,
+                     key,
+                     type,
+                     iter,
+                     iter_cls);
+}
+
+
+
+/* end of datacache_api.c */

Added: gnunet/src/datacache/plugin_datacache.h
===================================================================
--- gnunet/src/datacache/plugin_datacache.h                             (rev 0)
+++ gnunet/src/datacache/plugin_datacache.h     2009-07-25 22:24:42 UTC (rev 
8782)
@@ -0,0 +1,159 @@
+/*
+     This file is part of GNUnet
+     (C) 2006, 2009 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 2, 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.h
+ * @brief API for database backends for the datacache
+ * @author Christian Grothoff
+ */
+#ifndef PLUGIN_DATACACHE_H
+#define PLUGIN_DATACACHE_H
+
+#include "gnunet_datacache_lib.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0                           /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+
+/**
+ * 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
+ */
+typedef void (*GNUNET_DATACACHE_DeleteNotifyCallback)(void *cls,
+                                                     const GNUNET_HashCode 
*key,
+                                                     uint32_t size);
+
+
+/**
+ * The datastore service will pass a pointer to a struct
+ * of this type as the first and only argument to the
+ * entry point of each datastore plugin.
+ */
+struct GNUNET_DATACACHE_PluginEnvironment
+{
+  
+  /**
+   * Scheduler to use.
+   */ 
+  struct GNUNET_SCHEDULER_Handle *sched;
+
+  /**
+   * Configuration to use.
+   */
+  struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  /**
+   * Configuration section to use.
+   */
+  const char *section;
+
+  /**
+   * Closure to use for callbacks.
+   */
+  void *cls;
+
+  /**
+   * Function to call whenever the plugin needs to
+   * discard content that it was asked to store.
+   */
+  GNUNET_DATACACHE_DeleteNotifyCallback delete_notify;
+
+  /**
+   * How much space are we allowed to use?
+   */
+  unsigned long long quota;
+
+};
+
+
+/**
+ * @brief struct returned by the initialization function of the plugin
+ */
+struct GNUNET_DATACACHE_PluginFunctions {
+
+  /**
+   * Closure to pass to all plugin functions.
+   */ 
+  void *cls;
+
+  /**
+   * Store an item in the datastore.
+   *
+   * @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
+   */
+  uint32_t (*put) (void *cls,
+                  const GNUNET_HashCode * key,
+                  uint32_t size,
+                  const char *data,
+                  uint32_t type,
+                  struct GNUNET_TIME_Absolute discard_time);
+
+
+  /**
+   * Iterate over the results for a particular key
+   * in the datastore.
+   *
+   * @param key
+   * @param type entries of which type are relevant?
+   * @param iter maybe NULL (to just count)
+   * @return the number of results found
+   */
+  unsigned int (*get) (void *cls,
+                      const GNUNET_HashCode * key,
+                      uint32_t type,
+                      GNUNET_DATACACHE_Iterator iter,
+                      void *iter_cls);
+
+
+  /**
+   * Delete the entry with the lowest expiration value
+   * from the datacache right now.
+   * 
+   * @return GNUNET_OK on success, GNUNET_SYSERR on error
+   */ 
+  int (*del) (void *cls);
+
+
+};
+
+
+#if 0                           /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* end of plugin_datacache.h */
+#endif

Added: gnunet/src/datacache/plugin_datacache_sqlite.c
===================================================================
--- gnunet/src/datacache/plugin_datacache_sqlite.c                              
(rev 0)
+++ gnunet/src/datacache/plugin_datacache_sqlite.c      2009-07-25 22:24:42 UTC 
(rev 8782)
@@ -0,0 +1,676 @@
+/*
+     This file is part of GNUnet.
+     (C) 2006, 2007, 2008 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 2, 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 applications/dstore_sqlite/dstore.c
+ * @brief SQLite based implementation of the dstore service
+ * @author Christian Grothoff
+ * @todo Indexes, statistics
+ *
+ * Database: SQLite
+ */
+
+#include "platform.h"
+#include "gnunet_util.h"
+#include "gnunet_dstore_service.h"
+#include "gnunet_stats_service.h"
+#include <sqlite3.h>
+
+#define DEBUG_DSTORE GNUNET_NO
+
+/**
+ * Maximum size for an individual item.
+ */
+#define MAX_CONTENT_SIZE 65536
+
+/**
+ * Bytes used
+ */
+static unsigned long long payload;
+
+/**
+ * Maximum bytes available
+ */
+static unsigned long long quota;
+
+/**
+ * Filename of this database
+ */
+static char *fn;
+static char *fn_utf8;
+
+static GNUNET_CoreAPIForPlugins *coreAPI;
+
+static struct GNUNET_Mutex *lock;
+
+/**
+ * Statistics service.
+ */
+static GNUNET_Stats_ServiceAPI *stats;
+
+static unsigned int stat_dstore_size;
+
+static unsigned int stat_dstore_quota;
+
+/**
+ * Estimate of the per-entry overhead (including indices).
+ */
+#define OVERHEAD ((4*2+4*2+8*2+8*2+sizeof(GNUNET_HashCode)*5+32))
+
+struct GNUNET_BloomFilter *bloom;
+
+static char *bloom_name;
+
+/**
+ * @brief Prepare a SQL statement
+ */
+static int
+sq_prepare (sqlite3 * dbh, const char *zSql,    /* SQL statement, UTF-8 
encoded */
+            sqlite3_stmt ** ppStmt)
+{                               /* OUT: Statement handle */
+  char *dummy;
+  return sqlite3_prepare (dbh,
+                          zSql,
+                          strlen (zSql), ppStmt, (const char **) &dummy);
+}
+
+#define SQLITE3_EXEC(db, cmd) do { emsg = NULL; if (SQLITE_OK != 
sqlite3_exec(db, cmd, NULL, NULL, &emsg)) { GNUNET_GE_LOG(coreAPI->ectx, 
GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK, _("`%s' failed at %s:%d 
with error: %s\n"), "sqlite3_exec", __FILE__, __LINE__, emsg); 
sqlite3_free(emsg); } } 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_SQLITE(db, level, cmd) do { GNUNET_GE_LOG(coreAPI->ectx, level, 
_("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, 
sqlite3_errmsg(db)); } while(0)
+
+static void
+db_init (sqlite3 * dbh)
+{
+  char *emsg;
+
+  SQLITE3_EXEC (dbh, "PRAGMA temp_store=MEMORY");
+  SQLITE3_EXEC (dbh, "PRAGMA synchronous=OFF");
+  SQLITE3_EXEC (dbh, "PRAGMA count_changes=OFF");
+  SQLITE3_EXEC (dbh, "PRAGMA page_size=4092");
+  SQLITE3_EXEC (dbh,
+                "CREATE TABLE ds080 ("
+                "  size INTEGER NOT NULL DEFAULT 0,"
+                "  type INTEGER NOT NULL DEFAULT 0,"
+                "  puttime INTEGER NOT NULL DEFAULT 0,"
+                "  expire INTEGER NOT NULL DEFAULT 0,"
+                "  key BLOB NOT NULL DEFAULT '',"
+                "  vhash BLOB NOT NULL DEFAULT '',"
+                "  value BLOB NOT NULL DEFAULT '')");
+  SQLITE3_EXEC (dbh, "CREATE INDEX idx_hashidx ON ds080 (key,type,expire)");
+  SQLITE3_EXEC (dbh,
+                "CREATE INDEX idx_allidx ON ds080 (key,vhash,type,size)");
+  SQLITE3_EXEC (dbh, "CREATE INDEX idx_puttime ON ds080 (puttime)");
+}
+
+static int
+db_reset ()
+{
+  int fd;
+  sqlite3 *dbh;
+  char *tmpl;
+  const char *tmpdir;
+
+  if (fn != NULL)
+    {
+      UNLINK (fn);
+      GNUNET_free (fn);
+      GNUNET_free (fn_utf8);
+    }
+  payload = 0;
+
+  tmpdir = getenv ("TMPDIR");
+  tmpdir = tmpdir ? tmpdir : "/tmp";
+
+#define TEMPLATE "/gnunet-dstoreXXXXXX"
+  tmpl = GNUNET_malloc (strlen (tmpdir) + sizeof (TEMPLATE) + 1);
+  strcpy (tmpl, tmpdir);
+  strcat (tmpl, TEMPLATE);
+#undef TEMPLATE
+
+#ifdef MINGW
+  fn = (char *) GNUNET_malloc (MAX_PATH + 1);
+  plibc_conv_to_win_path (tmpl, fn);
+  GNUNET_free (tmpl);
+#else
+  fn = tmpl;
+#endif
+  fd = mkstemp (fn);
+  if (fd == -1)
+    {
+      GNUNET_GE_BREAK (NULL, 0);
+      GNUNET_free (fn);
+      fn = NULL;
+      return GNUNET_SYSERR;
+    }
+  CLOSE (fd);
+  fn_utf8 = GNUNET_convert_string_to_utf8 (coreAPI->ectx, fn, strlen (fn),
+#ifdef ENABLE_NLS
+                                           nl_langinfo (CODESET)
+#else
+                                           "UTF-8"      /* good luck */
+#endif
+    );
+  if (SQLITE_OK != sqlite3_open (fn_utf8, &dbh))
+    {
+      GNUNET_free (fn);
+      GNUNET_free (fn_utf8);
+      fn = NULL;
+      return GNUNET_SYSERR;
+    }
+  db_init (dbh);
+  sqlite3_close (dbh);
+  return GNUNET_OK;
+}
+
+/**
+ * Check that we are within quota.
+ * @return GNUNET_OK if we are.
+ */
+static int
+checkQuota (sqlite3 * dbh)
+{
+  GNUNET_HashCode dkey;
+  GNUNET_HashCode vhash;
+  unsigned int dsize;
+  unsigned int dtype;
+  sqlite3_stmt *stmt;
+  sqlite3_stmt *dstmt;
+  int err;
+
+  if (payload * 10 <= quota * 9)
+    return GNUNET_OK;           /* we seem to be about 10% off */
+#if DEBUG_DSTORE
+  GNUNET_GE_LOG (coreAPI->ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER,
+                 "DStore above qutoa (have %llu, allowed %llu), will delete 
some data.\n",
+                 payload, quota);
+#endif
+  stmt = NULL;
+  dstmt = NULL;
+  if ((sq_prepare (dbh,
+                   "SELECT size, type, key, vhash FROM ds080 ORDER BY puttime 
ASC LIMIT 1",
+                   &stmt) != SQLITE_OK) ||
+      (sq_prepare (dbh,
+                   "DELETE FROM ds080 "
+                   "WHERE key=? AND vhash=? AND type=? AND size=?",
+                   &dstmt) != SQLITE_OK))
+    {
+      GNUNET_GE_LOG (coreAPI->ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
+                     _("`%s' failed at %s:%d with error: %s\n"),
+                     "sq_prepare", __FILE__, __LINE__, sqlite3_errmsg (dbh));
+      GNUNET_GE_BREAK (NULL, 0);
+      if (dstmt != NULL)
+        sqlite3_finalize (dstmt);
+      if (stmt != NULL)
+        sqlite3_finalize (stmt);
+      return GNUNET_SYSERR;
+    }
+  err = SQLITE_DONE;
+  while ((payload * 10 > quota * 9) &&  /* we seem to be about 10% off */
+         ((err = sqlite3_step (stmt)) == SQLITE_ROW))
+    {
+      dsize = sqlite3_column_int (stmt, 0);
+      dtype = sqlite3_column_int (stmt, 1);
+      GNUNET_GE_BREAK (NULL,
+                       sqlite3_column_bytes (stmt,
+                                             2) == sizeof (GNUNET_HashCode));
+      GNUNET_GE_BREAK (NULL,
+                       sqlite3_column_bytes (stmt,
+                                             3) == sizeof (GNUNET_HashCode));
+      memcpy (&dkey, sqlite3_column_blob (stmt, 2), sizeof (GNUNET_HashCode));
+      memcpy (&vhash, sqlite3_column_blob (stmt, 3),
+              sizeof (GNUNET_HashCode));
+      sqlite3_reset (stmt);
+      sqlite3_bind_blob (dstmt,
+                         1, &dkey, sizeof (GNUNET_HashCode),
+                         SQLITE_TRANSIENT);
+      sqlite3_bind_blob (dstmt,
+                         2, &vhash, sizeof (GNUNET_HashCode),
+                         SQLITE_TRANSIENT);
+      sqlite3_bind_int (dstmt, 3, dtype);
+      sqlite3_bind_int (dstmt, 4, dsize);
+      if ((err = sqlite3_step (dstmt)) != SQLITE_DONE)
+        {
+          GNUNET_GE_LOG (coreAPI->ectx,
+                         GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
+                         _("`%s' failed at %s:%d with error: %s\n"),
+                         "sqlite3_step", __FILE__, __LINE__,
+                         sqlite3_errmsg (dbh));
+          sqlite3_reset (dstmt);
+          GNUNET_GE_BREAK (NULL, 0);    /* should delete but cannot!? */
+          break;
+        }
+      if (sqlite3_total_changes (dbh) > 0)
+        {
+          if (bloom != NULL)
+            GNUNET_bloomfilter_remove (bloom, &dkey);
+          payload -= (dsize + OVERHEAD);
+        }
+#if DEBUG_DSTORE
+      GNUNET_GE_LOG (coreAPI->ectx,
+                     GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
+                     GNUNET_GE_DEVELOPER,
+                     "Deleting %u bytes decreases DStore payload to %llu out 
of %llu\n",
+                     dsize, payload, quota);
+#endif
+      sqlite3_reset (dstmt);
+    }
+  if (err != SQLITE_DONE)
+    {
+      GNUNET_GE_LOG (coreAPI->ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
+                     _("`%s' failed at %s:%d with error: %s\n"),
+                     "sqlite3_step", __FILE__, __LINE__,
+                     sqlite3_errmsg (dbh));
+    }
+  sqlite3_finalize (dstmt);
+  sqlite3_finalize (stmt);
+  if (payload * 10 > quota * 9)
+    {
+      /* we seem to be about 10% off */
+      GNUNET_GE_LOG (coreAPI->ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_DEVELOPER,
+                     "Failed to delete content to drop below quota (bug?).\n",
+                     payload, quota);
+      return GNUNET_SYSERR;
+    }
+  return GNUNET_OK;
+}
+
+/**
+ * Store an item in the datastore.
+ *
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ */
+static int
+d_put (const GNUNET_HashCode * key,
+       unsigned int type,
+       GNUNET_CronTime discard_time, unsigned int size, const char *data)
+{
+  GNUNET_HashCode vhash;
+  sqlite3 *dbh;
+  sqlite3_stmt *stmt;
+  int ret;
+  GNUNET_CronTime now;
+
+  if (size > MAX_CONTENT_SIZE)
+    return GNUNET_SYSERR;
+  GNUNET_hash (data, size, &vhash);
+  GNUNET_mutex_lock (lock);
+  if ((fn == NULL) || (SQLITE_OK != sqlite3_open (fn_utf8, &dbh)))
+    {
+      db_reset (dbh);
+      GNUNET_mutex_unlock (lock);
+      return GNUNET_SYSERR;
+    }
+  now = GNUNET_get_time ();
+#if DEBUG_DSTORE
+  GNUNET_GE_LOG (coreAPI->ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER,
+                 "dstore processes put `%.*s' with expiration %llu\n",
+                 size, data, discard_time);
+#endif
+
+  /* first try UPDATE */
+  if (sq_prepare (dbh,
+                  "UPDATE ds080 SET puttime=?, expire=? "
+                  "WHERE key=? AND vhash=? AND type=? AND size=?",
+                  &stmt) != SQLITE_OK)
+    {
+      GNUNET_GE_LOG (coreAPI->ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
+                     _("`%s' failed at %s:%d with error: %s\n"),
+                     "sq_prepare", __FILE__, __LINE__, sqlite3_errmsg (dbh));
+      sqlite3_close (dbh);
+      GNUNET_mutex_unlock (lock);
+      return GNUNET_SYSERR;
+    }
+  if ((SQLITE_OK !=
+       sqlite3_bind_int64 (stmt, 1, now)) ||
+      (SQLITE_OK !=
+       sqlite3_bind_int64 (stmt, 2, discard_time)) ||
+      (SQLITE_OK !=
+       sqlite3_bind_blob (stmt, 3, key, sizeof (GNUNET_HashCode),
+                          SQLITE_TRANSIENT)) ||
+      (SQLITE_OK !=
+       sqlite3_bind_blob (stmt, 4, &vhash, sizeof (GNUNET_HashCode),
+                          SQLITE_TRANSIENT)) ||
+      (SQLITE_OK != sqlite3_bind_int (stmt, 5, type)) ||
+      (SQLITE_OK != sqlite3_bind_int (stmt, 6, size)))
+    {
+      GNUNET_GE_LOG (coreAPI->ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
+                     _("`%s' failed at %s:%d with error: %s\n"),
+                     "sqlite3_bind_xxx", __FILE__, __LINE__,
+                     sqlite3_errmsg (dbh));
+      sqlite3_finalize (stmt);
+      sqlite3_close (dbh);
+      GNUNET_mutex_unlock (lock);
+      return GNUNET_SYSERR;
+    }
+  if (SQLITE_DONE != sqlite3_step (stmt))
+    {
+      GNUNET_GE_LOG (coreAPI->ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
+                     _("`%s' failed at %s:%d with error: %s\n"),
+                     "sqlite3_step", __FILE__, __LINE__,
+                     sqlite3_errmsg (dbh));
+      sqlite3_finalize (stmt);
+      sqlite3_close (dbh);
+      GNUNET_mutex_unlock (lock);
+      return GNUNET_SYSERR;
+    }
+  ret = sqlite3_changes (dbh);
+  sqlite3_finalize (stmt);
+  if (ret > 0)
+    {
+      sqlite3_close (dbh);
+      GNUNET_mutex_unlock (lock);
+      return GNUNET_OK;
+    }
+  if (GNUNET_OK != checkQuota (dbh))
+    {
+      sqlite3_close (dbh);
+      GNUNET_mutex_unlock (lock);
+      return GNUNET_SYSERR;
+    }
+  if (sq_prepare (dbh,
+                  "INSERT INTO ds080 "
+                  "(size, type, puttime, expire, key, vhash, value) "
+                  "VALUES (?, ?, ?, ?, ?, ?, ?)", &stmt) != SQLITE_OK)
+    {
+      GNUNET_GE_LOG (coreAPI->ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
+                     _("`%s' failed at %s:%d with error: %s\n"),
+                     "sq_prepare", __FILE__, __LINE__, sqlite3_errmsg (dbh));
+      sqlite3_close (dbh);
+      GNUNET_mutex_unlock (lock);
+      return GNUNET_SYSERR;
+    }
+  if ((SQLITE_OK == sqlite3_bind_int (stmt, 1, size)) &&
+      (SQLITE_OK == sqlite3_bind_int (stmt, 2, type)) &&
+      (SQLITE_OK == sqlite3_bind_int64 (stmt, 3, now)) &&
+      (SQLITE_OK == sqlite3_bind_int64 (stmt, 4, discard_time)) &&
+      (SQLITE_OK ==
+       sqlite3_bind_blob (stmt, 5, key, sizeof (GNUNET_HashCode),
+                          SQLITE_TRANSIENT)) &&
+      (SQLITE_OK ==
+       sqlite3_bind_blob (stmt, 6, &vhash, sizeof (GNUNET_HashCode),
+                          SQLITE_TRANSIENT))
+      && (SQLITE_OK ==
+          sqlite3_bind_blob (stmt, 7, data, size, SQLITE_TRANSIENT)))
+    {
+      if (SQLITE_DONE != sqlite3_step (stmt))
+        {
+          LOG_SQLITE (dbh,
+                      GNUNET_GE_ERROR | GNUNET_GE_DEVELOPER | GNUNET_GE_ADMIN
+                      | GNUNET_GE_BULK, "sqlite3_step");
+        }
+      else
+        {
+          payload += size + OVERHEAD;
+          if (bloom != NULL)
+            GNUNET_bloomfilter_add (bloom, key);
+        }
+      if (SQLITE_OK != sqlite3_finalize (stmt))
+        LOG_SQLITE (dbh,
+                    GNUNET_GE_ERROR | GNUNET_GE_DEVELOPER | GNUNET_GE_ADMIN |
+                    GNUNET_GE_BULK, "sqlite3_finalize");
+    }
+  else
+    {
+      LOG_SQLITE (dbh,
+                  GNUNET_GE_ERROR | GNUNET_GE_DEVELOPER | GNUNET_GE_ADMIN |
+                  GNUNET_GE_BULK, "sqlite3_bind_xxx");
+    }
+#if DEBUG_DSTORE
+  GNUNET_GE_LOG (coreAPI->ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER,
+                 "Storing %u bytes increases DStore payload to %llu out of 
%llu\n",
+                 size, payload, quota);
+#endif
+  checkQuota (dbh);
+  sqlite3_close (dbh);
+  GNUNET_mutex_unlock (lock);
+  if (stats != NULL)
+    stats->set (stat_dstore_size, payload);
+  return GNUNET_OK;
+}
+
+/**
+ * Iterate over the results for a particular key
+ * in the datastore.
+ *
+ * @param key
+ * @param type entries of which type are relevant?
+ * @param iter maybe NULL (to just count)
+ * @return the number of results, GNUNET_SYSERR if the
+ *   iter is non-NULL and aborted the iteration
+ */
+static int
+d_get (const GNUNET_HashCode * key,
+       unsigned int type, GNUNET_ResultProcessor handler, void *closure)
+{
+  sqlite3 *dbh;
+  sqlite3_stmt *stmt;
+  GNUNET_CronTime now;
+  unsigned int size;
+  const char *dat;
+  unsigned int cnt;
+  unsigned int off;
+  unsigned int total;
+  char scratch[256];
+
+  GNUNET_mutex_lock (lock);
+  if ((bloom != NULL) && (GNUNET_NO == GNUNET_bloomfilter_test (bloom, key)))
+    {
+      GNUNET_mutex_unlock (lock);
+      return 0;
+    }
+  if ((fn == NULL) || (SQLITE_OK != sqlite3_open (fn_utf8, &dbh)))
+    {
+      db_reset (dbh);
+      GNUNET_mutex_unlock (lock);
+      return GNUNET_SYSERR;
+    }
+  now = GNUNET_get_time ();
+#if DEBUG_DSTORE
+  GNUNET_GE_LOG (coreAPI->ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER,
+                 "dstore processes get at `%llu'\n", now);
+#endif
+  if (sq_prepare (dbh,
+                  "SELECT count(*) FROM ds080 WHERE key=? AND type=? AND 
expire >= ?",
+                  &stmt) != SQLITE_OK)
+    {
+      GNUNET_GE_LOG (coreAPI->ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
+                     _("`%s' failed at %s:%d with error: %s\n"),
+                     "sq_prepare", __FILE__, __LINE__, sqlite3_errmsg (dbh));
+      sqlite3_close (dbh);
+      db_reset (dbh);
+      GNUNET_mutex_unlock (lock);
+      return GNUNET_SYSERR;
+    }
+  sqlite3_bind_blob (stmt, 1, key, sizeof (GNUNET_HashCode),
+                     SQLITE_TRANSIENT);
+  sqlite3_bind_int (stmt, 2, type);
+  sqlite3_bind_int64 (stmt, 3, now);
+  if (SQLITE_ROW != sqlite3_step (stmt))
+    {
+      LOG_SQLITE (dbh,
+                  GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_USER |
+                  GNUNET_GE_BULK, "sqlite_step");
+      sqlite3_reset (stmt);
+      sqlite3_finalize (stmt);
+      db_reset (dbh);
+      GNUNET_mutex_unlock (lock);
+      return GNUNET_SYSERR;
+    }
+  total = sqlite3_column_int (stmt, 0);
+  sqlite3_reset (stmt);
+  sqlite3_finalize (stmt);
+  if ((total == 0) || (handler == NULL))
+    {
+      sqlite3_close (dbh);
+      GNUNET_mutex_unlock (lock);
+      return total;
+    }
+
+  cnt = 0;
+  off = GNUNET_random_u32 (GNUNET_RANDOM_QUALITY_WEAK, total);
+  while (cnt < total)
+    {
+      off = (off + 1) % total;
+      GNUNET_snprintf (scratch, 256,
+                       "SELECT size, value FROM ds080 WHERE key=? AND type=? 
AND expire >= ? LIMIT 1 OFFSET %u",
+                       off);
+      if (sq_prepare (dbh, scratch, &stmt) != SQLITE_OK)
+        {
+          GNUNET_GE_LOG (coreAPI->ectx,
+                         GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,
+                         _("`%s' failed at %s:%d with error: %s\n"),
+                         "sq_prepare", __FILE__, __LINE__,
+                         sqlite3_errmsg (dbh));
+          sqlite3_close (dbh);
+          GNUNET_mutex_unlock (lock);
+          return GNUNET_SYSERR;
+        }
+      sqlite3_bind_blob (stmt, 1, key, sizeof (GNUNET_HashCode),
+                         SQLITE_TRANSIENT);
+      sqlite3_bind_int (stmt, 2, type);
+      sqlite3_bind_int64 (stmt, 3, now);
+      if (sqlite3_step (stmt) != SQLITE_ROW)
+        break;
+      size = sqlite3_column_int (stmt, 0);
+      if (size != sqlite3_column_bytes (stmt, 1))
+        {
+          GNUNET_GE_BREAK (NULL, 0);
+          sqlite3_finalize (stmt);
+          continue;
+        }
+      dat = sqlite3_column_blob (stmt, 1);
+      cnt++;
+#if DEBUG_DSTORE
+      GNUNET_GE_LOG (coreAPI->ectx,
+                     GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
+                     GNUNET_GE_DEVELOPER,
+                     "dstore found result for get: `%.*s'\n", size, dat);
+#endif
+      if ((handler != NULL) &&
+          (GNUNET_OK != handler (key, type, size, dat, closure)))
+        {
+          sqlite3_finalize (stmt);
+          break;
+        }
+      sqlite3_finalize (stmt);
+    }
+  sqlite3_close (dbh);
+  GNUNET_mutex_unlock (lock);
+  return cnt;
+}
+
+GNUNET_Dstore_ServiceAPI *
+provide_module_dstore_sqlite (GNUNET_CoreAPIForPlugins * capi)
+{
+  static GNUNET_Dstore_ServiceAPI api;
+  int fd;
+
+#if DEBUG_SQLITE
+  GNUNET_GE_LOG (capi->ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                 "SQLite Dstore: initializing database\n");
+#endif
+  coreAPI = capi;
+  if (GNUNET_OK != db_reset ())
+    {
+      GNUNET_GE_BREAK (capi->ectx, 0);
+      return NULL;
+    }
+  lock = GNUNET_mutex_create (GNUNET_NO);
+
+
+  api.get = &d_get;
+  api.put = &d_put;
+  GNUNET_GC_get_configuration_value_number (coreAPI->cfg,
+                                            "DSTORE", "QUOTA", 1, 1024, 1,
+                                            &quota);
+  if (quota == 0)               /* error */
+    quota = 1;
+  quota *= 1024 * 1024;
+
+  bloom_name = GNUNET_strdup ("/tmp/dbloomXXXXXX");
+  fd = mkstemp (bloom_name);
+  if (fd != -1)
+    {
+      bloom = GNUNET_bloomfilter_load (coreAPI->ectx, bloom_name, quota / 
(OVERHEAD + 1024),    /* 8 bit per entry in DB, expect 1k entries */
+                                       5);
+      CLOSE (fd);
+    }
+  stats = capi->service_request ("stats");
+  if (stats != NULL)
+    {
+      stat_dstore_size = stats->create (gettext_noop ("# bytes in dstore"));
+      stat_dstore_quota =
+        stats->create (gettext_noop ("# max bytes allowed in dstore"));
+      stats->set (stat_dstore_quota, quota);
+    }
+  return &api;
+}
+
+/**
+ * Shutdown the module.
+ */
+void
+release_module_dstore_sqlite ()
+{
+  UNLINK (fn);
+  GNUNET_free (fn);
+  GNUNET_free (fn_utf8);
+  fn = NULL;
+  if (bloom != NULL)
+    {
+      GNUNET_bloomfilter_free (bloom);
+      bloom = NULL;
+    }
+  UNLINK (bloom_name);
+  GNUNET_free (bloom_name);
+  bloom_name = NULL;
+  if (stats != NULL)
+    {
+      coreAPI->service_release (stats);
+      stats = NULL;
+    }
+#if DEBUG_SQLITE
+  GNUNET_GE_LOG (coreAPI->ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                 "SQLite Dstore: database shutdown\n");
+#endif
+  GNUNET_mutex_destroy (lock);
+  coreAPI = NULL;
+}
+
+/* end of dstore.c */

Added: gnunet/src/datacache/plugin_datacache_template.c
===================================================================
--- gnunet/src/datacache/plugin_datacache_template.c                            
(rev 0)
+++ gnunet/src/datacache/plugin_datacache_template.c    2009-07-25 22:24:42 UTC 
(rev 8782)
@@ -0,0 +1,151 @@
+/*
+     This file is part of GNUnet
+     (C) 2006, 2009 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 2, 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_template.c
+ * @brief template for an implementation of a database backend for the 
datacache
+ * @author Christian Grothoff
+ */
+#ifndef PLUGIN_DATACACHE_H
+#define PLUGIN_DATACACHE_H
+
+#include "plugin_datacache.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0                           /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+
+
+/**
+ * Context for all functions in this plugin.
+ */
+struct Plugin 
+{
+  /**
+   * Our execution environment.
+   */
+  struct GNUNET_DATASTORE_PluginEnvironment *env;
+};
+
+
+/**
+ * Store an item in the datastore.
+ *
+ * @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 uint32_t 
+template_plugin_put (void *cls,
+                    const GNUNET_HashCode * key,
+                    uint32_t size,
+                    const char *data,
+                    uint32_t type,
+                    struct GNUNET_TIME_Absolute discard_time)
+{
+  GNUNET_break (0);
+  return 0;
+}
+
+
+/**
+ * Iterate over the results for a particular key
+ * in the datastore.
+ *
+ * @param key
+ * @param type entries of which type are relevant?
+ * @param iter maybe NULL (to just count)
+ * @return the number of results found
+ */
+static unsigned int 
+template_plugin_get (void *cls,
+                    const GNUNET_HashCode * key,
+                    uint32_t type,
+                    GNUNET_DATACACHE_Iterator iter,
+                    void *iter_cls)
+{
+  GNUNET_break (0);
+  return 0;
+}
+
+
+/**
+ * Delete the entry with the lowest expiration value
+ * from the datacache right now.
+ * 
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ */ 
+static int 
+template_plugin_del (void *cls)
+{
+  GNUNET_break (0);
+  return GNUNET_SYSERR;
+}
+
+
+/**
+ * Entry point for the plugin.
+ */
+void *
+libgnunet_plugin_datacache_template_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;
+  api = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_PluginFunctions));
+  api->cls = plugin;
+  api->get = &template_plugin_get;
+  api->put = &template_plugin_put;
+  api->del = &template_plugin_del;
+  GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
+                   "template", _("Template datacache running\n"));
+  return api;
+}
+
+
+/**
+ * Exit point from the plugin.
+ */
+void *
+libgnunet_plugin_datacache_template_done (void *cls)
+{
+  struct GNUNET_DATACACHE_PluginFunctions *api = cls;
+  struct Plugin *plugin = api->cls;
+
+  GNUNET_free (plugin);
+  GNUNET_free (api);
+  return NULL;
+}
+
+
+
+/* end of plugin_datacache_template.c */
+

Added: gnunet/src/datacache/test_datacache_api.c
===================================================================
--- gnunet/src/datacache/test_datacache_api.c                           (rev 0)
+++ gnunet/src/datacache/test_datacache_api.c   2009-07-25 22:24:42 UTC (rev 
8782)
@@ -0,0 +1,120 @@
+/*
+     This file is part of GNUnet.
+     (C) 2006 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 2, 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 applications/dstore/dstore_test.c
+ * @brief Test for the dstore implementations.
+ * @author Nils Durner
+ */
+
+#include "platform.h"
+#include "gnunet_util.h"
+#include "gnunet_protocols.h"
+#include "gnunet_dstore_service.h"
+#include "core.h"
+
+#define ASSERT(x) do { if (! (x)) { printf("Error at %s:%d\n", __FILE__, 
__LINE__); goto FAILURE;} } while (0)
+
+static int error;
+
+static int
+checkIt (const GNUNET_HashCode * key,
+         unsigned int type, unsigned int size, const char *data, void *cls)
+{
+  if (size != sizeof (GNUNET_HashCode))
+    {
+      printf ("ERROR: Invalid size\n");
+      error = 2;
+    }
+  if (0 != memcmp (data, cls, size))
+    {
+      printf ("ERROR: Invalid data\n");
+      error = 3;
+    }
+  return GNUNET_OK;
+}
+
+/**
+ * Add testcode here!
+ */
+static int
+test (GNUNET_Dstore_ServiceAPI * api)
+{
+  GNUNET_HashCode k;
+  GNUNET_HashCode n;
+  GNUNET_CronTime exp;
+  unsigned int i;
+
+  exp = GNUNET_get_time () + 5 * GNUNET_CRON_MINUTES;
+  memset (&k, 0, sizeof (GNUNET_HashCode));
+  for (i = 0; i < 100; i++)
+    {
+      GNUNET_hash (&k, sizeof (GNUNET_HashCode), &n);
+      ASSERT (GNUNET_OK == api->put (&k,
+                                     i % 2,
+                                     exp, sizeof (GNUNET_HashCode),
+                                     (const char *) &n));
+      k = n;
+    }
+  memset (&k, 0, sizeof (GNUNET_HashCode));
+  for (i = 0; i < 100; i++)
+    {
+      GNUNET_hash (&k, sizeof (GNUNET_HashCode), &n);
+      ASSERT (1 == api->get (&k, i % 2, &checkIt, &n));
+      k = n;
+    }
+  return GNUNET_OK;
+FAILURE:
+  return GNUNET_SYSERR;
+}
+
+#define TEST_DB "/tmp/GNUnet_dstore_test/"
+
+int
+main (int argc, char *argv[])
+{
+  GNUNET_Dstore_ServiceAPI *api;
+  int ok;
+  struct GNUNET_GC_Configuration *cfg;
+  struct GNUNET_CronManager *cron;
+
+  GNUNET_disable_entropy_gathering ();
+  cfg = GNUNET_GC_create ();
+  if (-1 == GNUNET_GC_parse_configuration (cfg, "check.conf"))
+    {
+      GNUNET_GC_free (cfg);
+      return -1;
+    }
+  cron = GNUNET_cron_create (NULL);
+  GNUNET_CORE_init (NULL, cfg, cron, NULL);
+  api = GNUNET_CORE_request_service ("dstore");
+  if (api != NULL)
+    {
+      ok = test (api);
+      GNUNET_CORE_release_service (api);
+    }
+  else
+    ok = GNUNET_SYSERR;
+  GNUNET_CORE_done ();
+  if (ok == GNUNET_SYSERR)
+    return 1;
+  return error;
+}
+
+/* end of dstore_test.c */

Modified: gnunet/src/datastore/Makefile.am
===================================================================
--- gnunet/src/datastore/Makefile.am    2009-07-25 21:32:23 UTC (rev 8781)
+++ gnunet/src/datastore/Makefile.am    2009-07-25 22:24:42 UTC (rev 8782)
@@ -16,7 +16,7 @@
   libgnunetdatastore.la
 
 libgnunetdatastore_la_SOURCES = \
-  datastore_api.c datastore.h
+  datastore_api.c datastore.h plugin_datastore.h
 libgnunetdatastore_la_LIBADD = \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(GN_LIBINTL) 

Modified: gnunet/src/datastore/plugin_datastore_template.c
===================================================================
--- gnunet/src/datastore/plugin_datastore_template.c    2009-07-25 21:32:23 UTC 
(rev 8781)
+++ gnunet/src/datastore/plugin_datastore_template.c    2009-07-25 22:24:42 UTC 
(rev 8782)
@@ -47,6 +47,7 @@
  */
 static unsigned long long template_plugin_get_size (void *cls)
 {
+  GNUNET_break (0);
   return 0;
 }
 
@@ -76,6 +77,7 @@
                     struct GNUNET_TIME_Absolute expiration,
                     char **msg)
 {
+  GNUNET_break (0);
   *msg = GNUNET_strdup ("not implemented");
   return GNUNET_SYSERR;
 }
@@ -94,9 +96,10 @@
  *         to signal the end of the iteration).
  */
 static void 
-template_next_request (void *next_cls,
+template_plugin_next_request (void *next_cls,
                       int end_it)
 {
+  GNUNET_break (0);
 }
 
 
@@ -124,6 +127,7 @@
                     uint32_t type,
                     PluginIterator iter, void *iter_cls)
 {
+  GNUNET_break (0);
 }
 
 
@@ -155,6 +159,7 @@
                        int delta, struct GNUNET_TIME_Absolute expire,
                        char **msg)
 {
+  GNUNET_break (0);
   *msg = GNUNET_strdup ("not implemented");
   return GNUNET_SYSERR;
 }
@@ -176,6 +181,7 @@
                                   PluginIterator iter,
                                   void *iter_cls)
 {
+  GNUNET_break (0);
 }
 
 
@@ -196,6 +202,7 @@
                        PluginIterator iter,
                        void *iter_cls)
 {
+  GNUNET_break (0);
 }
 
 
@@ -216,6 +223,7 @@
                        PluginIterator iter,
                        void *iter_cls)
 {
+  GNUNET_break (0);
 }
 
 
@@ -236,6 +244,7 @@
                        PluginIterator iter,
                        void *iter_cls)
 {
+  GNUNET_break (0);
 }
 
 
@@ -256,6 +265,7 @@
                        PluginIterator iter,
                        void *iter_cls)
 {
+  GNUNET_break (0);
 }
 
 
@@ -265,6 +275,7 @@
 static void 
 template_plugin_drop (void *cls)
 {
+  GNUNET_break (0);
 }
 
 
@@ -284,7 +295,7 @@
   api->cls = plugin;
   api->get_size = &template_plugin_get_size;
   api->put = &template_plugin_put;
-  api->next_request = &template_next_request;
+  api->next_request = &template_plugin_next_request;
   api->get = &template_plugin_get;
   api->update = &template_plugin_update;
   api->iter_low_priority = &template_plugin_iter_low_priority;

Modified: gnunet/src/include/gnunet_datacache_lib.h
===================================================================
--- gnunet/src/include/gnunet_datacache_lib.h   2009-07-25 21:32:23 UTC (rev 
8781)
+++ gnunet/src/include/gnunet_datacache_lib.h   2009-07-25 22:24:42 UTC (rev 
8782)
@@ -51,12 +51,14 @@
 /**
  * Create a data cache.
  *
+ * @param sched scheduler to use
  * @param cfg configuration to use
  * @param section section in the configuration that contains our options
  * @return handle to use to access the service
  */
 struct GNUNET_DATACACHE_Handle *
-GNUNET_DATACACHE_create (struct GNUNET_CONFIGURATION_Handle *cfg,
+GNUNET_DATACACHE_create (struct GNUNET_SCHEDULER_Handle *sched,
+                        struct GNUNET_CONFIGURATION_Handle *cfg,
                         const char *section);
 
 
@@ -85,8 +87,9 @@
 
 
 /**
- * Store an item in the datastore.
+ * Store an item in the datacache.
  *
+ * @param h handle to the datacache
  * @param key key to store data under
  * @param size number of bytes in data
  * @param data data to store
@@ -95,7 +98,8 @@
  * @return GNUNET_OK on success, GNUNET_SYSERR on error (full, etc.)
  */
 int 
-GNUNET_DATACACHE_put (const GNUNET_HashCode * key,
+GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h,
+                     const GNUNET_HashCode * key,
                      uint32_t size,
                      const char *data,
                      unsigned int type,
@@ -104,8 +108,9 @@
 
 /**
  * Iterate over the results for a particular key
- * in the datastore.
+ * in the datacache.
  *
+ * @param h handle to the datacache
  * @param key what to look up
  * @param type entries of which type are relevant?
  * @param iter maybe NULL (to just count)
@@ -113,7 +118,8 @@
  * @return the number of results found
  */
 unsigned int 
-GNUNET_DATACACHE_get (const GNUNET_HashCode * key,
+GNUNET_DATACACHE_get (struct GNUNET_DATACACHE_Handle *h,
+                     const GNUNET_HashCode * key,
                      unsigned int type, 
                      GNUNET_DATACACHE_Iterator iter,
                      void *iter_cls);





reply via email to

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