From: Christian Grothoff Date: Sat, 25 Jul 2009 22:24:42 +0000 (+0000) Subject: towards datacache implementation X-Git-Tag: initial-import-from-subversion-38251~23628 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=c890b76cde9288a8d9f2faa3046fbb06341c8082;p=oweals%2Fgnunet.git towards datacache implementation --- diff --git a/TODO b/TODO index 07d082161..6c3bdeef2 100644 --- a/TODO +++ b/TODO @@ -58,7 +58,7 @@ that would cause them to be executed and check that they are working: Module features to implement: -* Dstore (needed for DHT) +* datacache (needed for DHT) - design plugin API - implement sqlite-based dstore plugin - implement dstore API diff --git a/configure.ac b/configure.ac index 30aeb32f6..9932e9092 100644 --- a/configure.ac +++ b/configure.ac @@ -745,6 +745,7 @@ po/Makefile.in src/Makefile src/arm/Makefile src/core/Makefile +src/datacache/Makefile src/datastore/Makefile src/fragmentation/Makefile src/hello/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index e4335db9d..42a668c75 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,6 +11,8 @@ SUBDIRS = \ include $(INTLEMU_SUBDIRS) \ util \ arm \ + datacache \ + datastore \ fragmentation \ hello \ peerinfo \ @@ -19,7 +21,6 @@ SUBDIRS = \ template \ transport \ core \ - datastore \ $(HOSTLIST_DIR) \ topology diff --git a/src/datacache/Makefile.am b/src/datacache/Makefile.am new file mode 100644 index 000000000..80b56bba1 --- /dev/null +++ b/src/datacache/Makefile.am @@ -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 diff --git a/src/datacache/datacache_api.c b/src/datacache/datacache_api.c new file mode 100644 index 000000000..1fe428b08 --- /dev/null +++ b/src/datacache/datacache_api.c @@ -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", "a)) + { + 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 */ diff --git a/src/datacache/plugin_datacache.h b/src/datacache/plugin_datacache.h new file mode 100644 index 000000000..e099cd31d --- /dev/null +++ b/src/datacache/plugin_datacache.h @@ -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 diff --git a/src/datacache/plugin_datacache_sqlite.c b/src/datacache/plugin_datacache_sqlite.c new file mode 100644 index 000000000..e386b55de --- /dev/null +++ b/src/datacache/plugin_datacache_sqlite.c @@ -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 + +#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, + "a); + 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 */ diff --git a/src/datacache/plugin_datacache_template.c b/src/datacache/plugin_datacache_template.c new file mode 100644 index 000000000..d1f162c17 --- /dev/null +++ b/src/datacache/plugin_datacache_template.c @@ -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 */ + diff --git a/src/datacache/test_datacache_api.c b/src/datacache/test_datacache_api.c new file mode 100644 index 000000000..00b63cda8 --- /dev/null +++ b/src/datacache/test_datacache_api.c @@ -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 */ diff --git a/src/datastore/Makefile.am b/src/datastore/Makefile.am index 07a14e534..1ca588926 100644 --- a/src/datastore/Makefile.am +++ b/src/datastore/Makefile.am @@ -16,7 +16,7 @@ lib_LTLIBRARIES = \ 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) diff --git a/src/datastore/plugin_datastore_template.c b/src/datastore/plugin_datastore_template.c index a364a0faa..4bfb452ed 100644 --- a/src/datastore/plugin_datastore_template.c +++ b/src/datastore/plugin_datastore_template.c @@ -47,6 +47,7 @@ struct Plugin */ static unsigned long long template_plugin_get_size (void *cls) { + GNUNET_break (0); return 0; } @@ -76,6 +77,7 @@ template_plugin_put (void *cls, struct GNUNET_TIME_Absolute expiration, char **msg) { + GNUNET_break (0); *msg = GNUNET_strdup ("not implemented"); return GNUNET_SYSERR; } @@ -94,9 +96,10 @@ template_plugin_put (void *cls, * 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 @@ template_plugin_get (void *cls, uint32_t type, PluginIterator iter, void *iter_cls) { + GNUNET_break (0); } @@ -155,6 +159,7 @@ template_plugin_update (void *cls, int delta, struct GNUNET_TIME_Absolute expire, char **msg) { + GNUNET_break (0); *msg = GNUNET_strdup ("not implemented"); return GNUNET_SYSERR; } @@ -176,6 +181,7 @@ template_plugin_iter_low_priority (void *cls, PluginIterator iter, void *iter_cls) { + GNUNET_break (0); } @@ -196,6 +202,7 @@ template_plugin_iter_zero_anonymity (void *cls, PluginIterator iter, void *iter_cls) { + GNUNET_break (0); } @@ -216,6 +223,7 @@ template_plugin_iter_ascending_expiration (void *cls, PluginIterator iter, void *iter_cls) { + GNUNET_break (0); } @@ -236,6 +244,7 @@ template_plugin_iter_migration_order (void *cls, PluginIterator iter, void *iter_cls) { + GNUNET_break (0); } @@ -256,6 +265,7 @@ template_plugin_iter_all_now (void *cls, PluginIterator iter, void *iter_cls) { + GNUNET_break (0); } @@ -265,6 +275,7 @@ template_plugin_iter_all_now (void *cls, static void template_plugin_drop (void *cls) { + GNUNET_break (0); } @@ -284,7 +295,7 @@ libgnunet_plugin_datastore_template_init (void *cls) 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; diff --git a/src/include/gnunet_datacache_lib.h b/src/include/gnunet_datacache_lib.h index 64d1d4883..1ee8eb8e2 100644 --- a/src/include/gnunet_datacache_lib.h +++ b/src/include/gnunet_datacache_lib.h @@ -51,12 +51,14 @@ struct GNUNET_DATACACHE_Handle; /** * 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 @@ typedef void (*GNUNET_DATACACHE_Iterator) (void *cls, /** - * 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 @@ typedef void (*GNUNET_DATACACHE_Iterator) (void *cls, * @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 @@ GNUNET_DATACACHE_put (const GNUNET_HashCode * key, /** * 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 @@ GNUNET_DATACACHE_put (const GNUNET_HashCode * key, * @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);