check_PROGRAMS = \
test_datastore_api \
+ test_datastore_api_management \
perf_datastore_api \
perf_plugin_datastore
$(top_builddir)/src/datastore/libgnunetdatastore.la \
$(top_builddir)/src/util/libgnunetutil.la
+test_datastore_api_management_SOURCES = \
+ test_datastore_api_management.c
+test_datastore_api_management_LDADD = \
+ $(top_builddir)/src/datastore/libgnunetdatastore.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
perf_datastore_api_SOURCES = \
perf_datastore_api.c
perf_datastore_api_LDADD = \
*/
/**
- * @file datastore/datastore.hc
+ * @file datastore/datastore.h
* @brief structs for communication between datastore service and API
* @author Christian Grothoff
*/
sm = (const struct StatusMessage*) msg;
status = ntohl(sm->status);
emsg = NULL;
- if (status == GNUNET_SYSERR)
+ if (ntohs(msg->size) > sizeof(struct StatusMessage))
{
emsg = (const char*) &sm[1];
- if ( (ntohs(msg->size) == sizeof(struct StatusMessage)) ||
- (emsg[ntohs(msg->size) - sizeof(struct StatusMessage) - 1] != '\0') )
+ if (emsg[ntohs(msg->size) - sizeof(struct StatusMessage) - 1] != '\0')
{
GNUNET_break (0);
emsg = _("Invalid error message received from datastore service");
}
}
+ if ( (status == GNUNET_SYSERR) &&
+ (emsg == NULL) )
+ {
+ GNUNET_break (0);
+ emsg = _("Invalid error message received from datastore service");
+ }
h->response_proc = NULL;
#if DEBUG_DATASTORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
rm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_RESERVE);
rm->header.size = htons(sizeof (struct ReserveMessage));
rm->entries = htonl(entries);
- rm->amount = htonl(amount);
+ rm->amount = GNUNET_htonll(amount);
transmit_for_status (h, cont, cont_cls, timeout);
}
#if DEBUG_DATASTORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Transmitting `%s' message with value %d and message %s\n",
+ "Transmitting `%s' message with value %d and message `%s'\n",
"STATUS",
code,
msg != NULL ? msg : "(none)");
unsigned long long used;
unsigned long long req;
uint64_t amount;
- uint64_t entries;
+ uint32_t entries;
#if DEBUG_DATASTORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Processing `%s' request\n",
"RESERVE");
#endif
- amount = ntohl(msg->amount);
- entries = GNUNET_ntohll(msg->entries);
+ amount = GNUNET_ntohll(msg->amount);
+ entries = ntohl(msg->entries);
used = plugin->api->get_size (plugin->api->cls) + reserved;
req = amount + ((unsigned long long) GNUNET_DATASTORE_ENTRY_OVERHEAD) * entries;
if (used + req > quota)
#include "plugin_datastore.h"
#include <sqlite3.h>
-#define DEBUG_SQLITE GNUNET_YES
+#define DEBUG_SQLITE GNUNET_NO
/**
* After how many payload-changing operations
* a failure of the command 'cmd' on file 'filename'
* with the message given by strerror(errno).
*/
-#define LOG_SQLITE(db, msg, level, cmd) do { GNUNET_log_from (level, "sqlite", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); if (msg != NULL) GNUNET_asprintf(msg, _("`%s' failed with error: %s\n"), cmd, sqlite3_errmsg(db->dbh)); } while(0)
+#define LOG_SQLITE(db, msg, level, cmd) do { GNUNET_log_from (level, "sqlite", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); if (msg != NULL) GNUNET_asprintf(msg, _("`%s' failed with error: %s"), cmd, sqlite3_errmsg(db->dbh)); } while(0)
#define SELECT_IT_LOW_PRIORITY_1 \
"SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (prio = ? AND hash > ?) "\
sqlite3_bind_int64 (plugin->updPrio, 2, expire.value);
sqlite3_bind_int64 (plugin->updPrio, 3, uid);
n = sqlite3_step (plugin->updPrio);
- if (n != SQLITE_OK)
+ if (n != SQLITE_DONE)
LOG_SQLITE (plugin, msg,
GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
"sqlite3_step");
if (n == SQLITE_BUSY)
return GNUNET_NO;
- return n == SQLITE_OK ? GNUNET_OK : GNUNET_SYSERR;
+ return n == SQLITE_DONE ? GNUNET_OK : GNUNET_SYSERR;
}
*/
/*
* @file datastore/test_datastore_api.c
- * @brief Test for the datastore implementation.
+ * @brief Test for the basic datastore API.
* @author Christian Grothoff
*
* TODO:
- * - test multiple values under same key
- * - test "update"
- * - test storage reservations
+ * - test reservation failure
*/
#include "platform.h"
{
struct GNUNET_TIME_Absolute av;
- av.value = now.value - i * 1000;
+ av.value = now.value + 200000 - i * 1000;
return av;
}
RP_GET,
RP_DEL,
RP_DO_DEL,
- RP_DELVALIDATE
+ RP_DELVALIDATE,
+ RP_RESERVE,
+ RP_PUT_MULTIPLE,
+ RP_PUT_MULTIPLE_NEXT,
+ RP_GET_MULTIPLE,
+ RP_GET_MULTIPLE_NEXT,
+ RP_GET_MULTIPLE_DONE,
+ RP_UPDATE,
+ RP_UPDATE_VALIDATE,
+ RP_UPDATE_DONE
};
{
GNUNET_HashCode key;
int i;
+ int rid;
int *iptr;
struct GNUNET_SCHEDULER_Handle *sched;
struct GNUNET_CONFIGURATION_Handle *cfg;
void *data;
size_t size;
enum RunPhase phase;
+ unsigned long long uid;
};
}
+static void
+get_reserved (void *cls,
+ int success,
+ const char *msg)
+{
+ struct CpsRunContext *crc = cls;
+ if (0 >= success)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%s\n", msg);
+ GNUNET_assert (0 < success);
+ crc->rid = success;
+ GNUNET_SCHEDULER_add_continuation (crc->sched,
+ GNUNET_NO,
+ &run_continuation,
+ crc,
+ GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+}
+
+
static void
check_value (void *cls,
const GNUNET_HashCode * key,
GNUNET_assert (key == NULL);
if (crc->i == 0)
{
- crc->phase = RP_DONE;
+ crc->phase = RP_RESERVE;
}
GNUNET_SCHEDULER_add_continuation (crc->sched,
GNUNET_NO,
}
+static void
+check_multiple (void *cls,
+ const GNUNET_HashCode * key,
+ uint32_t size,
+ const void *data,
+ uint32_t type,
+ uint32_t priority,
+ uint32_t anonymity,
+ struct GNUNET_TIME_Absolute
+ expiration, uint64_t uid)
+{
+ struct CpsRunContext *crc = cls;
+
+ if (key == NULL)
+ {
+ GNUNET_assert (crc->phase == RP_GET_MULTIPLE_DONE);
+ crc->phase = RP_UPDATE;
+ GNUNET_SCHEDULER_add_continuation (crc->sched,
+ GNUNET_NO,
+ &run_continuation,
+ crc,
+ GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+ return;
+ }
+ crc->phase++;
+ if (priority == get_priority (42))
+ crc->uid = uid;
+}
+
+
+static void
+check_update (void *cls,
+ const GNUNET_HashCode * key,
+ uint32_t size,
+ const void *data,
+ uint32_t type,
+ uint32_t priority,
+ uint32_t anonymity,
+ struct GNUNET_TIME_Absolute
+ expiration, uint64_t uid)
+{
+ struct CpsRunContext *crc = cls;
+
+ if (key == NULL)
+ {
+ GNUNET_assert (crc->phase == RP_UPDATE_DONE);
+ crc->phase = RP_DONE;
+ GNUNET_SCHEDULER_add_continuation (crc->sched,
+ GNUNET_NO,
+ &run_continuation,
+ crc,
+ GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+ return;
+ }
+ if ( (anonymity == get_anonymity (42)) &&
+ (size == get_size (42)) &&
+ (priority == get_priority (42) + 100) )
+ {
+ crc->phase = RP_UPDATE_DONE;
+ }
+ else
+ GNUNET_assert (size == get_size (43));
+}
+
+
static void
run_continuation (void *cls,
const struct GNUNET_SCHEDULER_TaskContext *tc)
{
struct CpsRunContext *crc = cls;
ok = (int) crc->phase;
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Test in phase %u\n", crc->phase);
+#endif
switch (crc->phase)
{
case RP_PUT:
crc,
TIMEOUT);
break;
- /* check reservations */
- /* check update */
- /* test multiple results */
+ case RP_RESERVE:
+ crc->phase = RP_PUT_MULTIPLE;
+ GNUNET_DATASTORE_reserve (datastore,
+ 128*1024,
+ 2,
+ &get_reserved,
+ crc,
+ TIMEOUT);
+ break;
+ case RP_PUT_MULTIPLE:
+ crc->phase = RP_PUT_MULTIPLE_NEXT;
+ GNUNET_DATASTORE_put (datastore,
+ crc->rid,
+ &crc->key,
+ get_size (42),
+ get_data (42),
+ get_type (42),
+ get_priority (42),
+ get_anonymity (42),
+ get_expiration (42),
+ TIMEOUT,
+ &check_success,
+ crc);
+ break;
+ case RP_PUT_MULTIPLE_NEXT:
+ crc->phase = RP_GET_MULTIPLE;
+ GNUNET_DATASTORE_put (datastore,
+ crc->rid,
+ &crc->key,
+ get_size (43),
+ get_data (43),
+ get_type (42),
+ get_priority (43),
+ get_anonymity (43),
+ get_expiration (43),
+ TIMEOUT,
+ &check_success,
+ crc);
+ break;
+ case RP_GET_MULTIPLE:
+ GNUNET_DATASTORE_get (datastore,
+ &crc->key,
+ get_type (42),
+ &check_multiple,
+ crc,
+ TIMEOUT);
+ break;
+ case RP_GET_MULTIPLE_NEXT:
+ case RP_GET_MULTIPLE_DONE:
+ GNUNET_assert (0);
+ break;
+ case RP_UPDATE:
+ GNUNET_assert (crc->uid > 0);
+ crc->phase = RP_UPDATE_VALIDATE;
+ GNUNET_DATASTORE_update (datastore,
+ crc->uid,
+ 100,
+ get_expiration (42),
+ &check_success,
+ crc,
+ TIMEOUT);
+ break;
+ case RP_UPDATE_VALIDATE:
+ GNUNET_DATASTORE_get (datastore,
+ &crc->key,
+ get_type (42),
+ &check_update,
+ crc,
+ TIMEOUT);
+ break;
+ case RP_UPDATE_DONE:
+ GNUNET_assert (0);
+ break;
case RP_DONE:
#if VERBOSE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
crc->sched = sched;
crc->cfg = cfg;
crc->phase = RP_PUT;
- now.value = 1000000;
+ now = GNUNET_TIME_absolute_get ();
datastore = GNUNET_DATASTORE_connect (cfg, sched);
GNUNET_SCHEDULER_add_continuation (crc->sched,
GNUNET_NO,
--- /dev/null
+/*
+ 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 datastore/test_datastore_api_management.c
+ * @brief Test for the space management functions of the datastore implementation.
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_datastore_service.h"
+
+#define VERBOSE GNUNET_NO
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
+
+/**
+ * Number of iterations to run; must be large enough
+ * so that the quota will be exceeded!
+ */
+#define ITERATIONS 5000
+
+static struct GNUNET_DATASTORE_Handle *datastore;
+
+static struct GNUNET_TIME_Absolute now;
+
+static int ok;
+
+
+static size_t
+get_size (int i)
+{
+ return 8 + 8 * (i % 256);
+}
+
+
+static const void *
+get_data (int i)
+{
+ static char buf[60000];
+ memset (buf, i, 8 + 8 * (i % 256));
+ return buf;
+}
+
+
+static int
+get_type(int i)
+{
+ return 1;
+}
+
+
+static int
+get_priority (int i)
+{
+ return i+1;
+}
+
+
+static int
+get_anonymity(int i)
+{
+ return i;
+}
+
+
+static struct GNUNET_TIME_Absolute
+get_expiration (int i)
+{
+ struct GNUNET_TIME_Absolute av;
+
+ av.value = now.value + i * 1000;
+ return av;
+}
+
+enum RunPhase
+ {
+ RP_DONE = 0,
+ RP_PUT,
+ RP_GET,
+ RP_GET_FAIL
+ };
+
+
+struct CpsRunContext
+{
+ GNUNET_HashCode key;
+ int i;
+ int found;
+ struct GNUNET_SCHEDULER_Handle *sched;
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ void *data;
+ size_t size;
+ enum RunPhase phase;
+};
+
+
+static void
+run_continuation (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+static void
+check_success (void *cls,
+ int success,
+ const char *msg)
+{
+ struct CpsRunContext *crc = cls;
+ if (GNUNET_OK != success)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%s\n", msg);
+ GNUNET_assert (GNUNET_OK == success);
+ GNUNET_free_non_null (crc->data);
+ crc->data = NULL;
+ GNUNET_SCHEDULER_add_continuation (crc->sched,
+ GNUNET_NO,
+ &run_continuation,
+ crc,
+ GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+}
+
+
+static void
+check_value (void *cls,
+ const GNUNET_HashCode * key,
+ uint32_t size,
+ const void *data,
+ uint32_t type,
+ uint32_t priority,
+ uint32_t anonymity,
+ struct GNUNET_TIME_Absolute
+ expiration, uint64_t uid)
+{
+ struct CpsRunContext *crc = cls;
+ int i;
+
+ if (key == NULL)
+ {
+ crc->i--;
+ if (crc->found == GNUNET_YES)
+ {
+ crc->phase = RP_GET;
+ crc->found = GNUNET_NO;
+ }
+ else
+ {
+ fprintf (stderr,
+ "First not found was %u\n", crc->i);
+ crc->phase = RP_GET_FAIL;
+ }
+ if (0 == crc->i)
+ crc->phase = RP_DONE;
+ GNUNET_SCHEDULER_add_continuation (crc->sched,
+ GNUNET_NO,
+ &run_continuation,
+ crc,
+ GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+ return;
+ }
+ i = crc->i;
+ crc->found = GNUNET_YES;
+ GNUNET_assert (size == get_size (i));
+ GNUNET_assert (0 == memcmp (data, get_data(i), size));
+ GNUNET_assert (type == get_type (i));
+ GNUNET_assert (priority == get_priority (i));
+ GNUNET_assert (anonymity == get_anonymity(i));
+ GNUNET_assert (expiration.value == get_expiration(i).value);
+}
+
+
+static void
+check_nothing (void *cls,
+ const GNUNET_HashCode * key,
+ uint32_t size,
+ const void *data,
+ uint32_t type,
+ uint32_t priority,
+ uint32_t anonymity,
+ struct GNUNET_TIME_Absolute
+ expiration, uint64_t uid)
+{
+ struct CpsRunContext *crc = cls;
+ GNUNET_assert (key == NULL);
+ if (crc->i == 0)
+ {
+ crc->phase = RP_DONE;
+ }
+ GNUNET_SCHEDULER_add_continuation (crc->sched,
+ GNUNET_NO,
+ &run_continuation,
+ crc,
+ GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+}
+
+
+static void
+run_continuation (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct CpsRunContext *crc = cls;
+ ok = (int) crc->phase;
+ switch (crc->phase)
+ {
+ case RP_PUT:
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Executing `%s' number %u\n",
+ "PUT",
+ crc->i);
+#endif
+ GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
+ GNUNET_DATASTORE_put (datastore,
+ 0,
+ &crc->key,
+ get_size (crc->i),
+ get_data (crc->i),
+ get_type (crc->i),
+ get_priority (crc->i),
+ get_anonymity (crc->i),
+ get_expiration (crc->i),
+ TIMEOUT,
+ &check_success,
+ crc);
+ crc->i++;
+ if (crc->i == ITERATIONS)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Sleeping to give datastore time to clean up\n");
+ sleep (5);
+ crc->phase = RP_GET;
+ crc->i--;
+ }
+ break;
+ case RP_GET:
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Executing `%s' number %u\n",
+ "GET",
+ crc->i);
+#endif
+ GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
+ GNUNET_DATASTORE_get (datastore,
+ &crc->key,
+ get_type (crc->i),
+ &check_value,
+ crc,
+ TIMEOUT);
+ break;
+ case RP_GET_FAIL:
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Executing `%s' number %u\n",
+ "GET",
+ crc->i);
+#endif
+ GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
+ GNUNET_DATASTORE_get (datastore,
+ &crc->key,
+ get_type (crc->i),
+ &check_nothing,
+ crc,
+ TIMEOUT);
+ break;
+ case RP_DONE:
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Finished, disconnecting\n");
+#endif
+ GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
+ GNUNET_free (crc);
+ ok = 0;
+ }
+}
+
+
+static void
+run (void *cls,
+ struct GNUNET_SCHEDULER_Handle *sched,
+ char *const *args,
+ const char *cfgfile, struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ struct CpsRunContext *crc;
+
+ crc = GNUNET_malloc(sizeof(struct CpsRunContext));
+ crc->sched = sched;
+ crc->cfg = cfg;
+ crc->phase = RP_PUT;
+ now = GNUNET_TIME_absolute_get ();
+ datastore = GNUNET_DATASTORE_connect (cfg, sched);
+ GNUNET_SCHEDULER_add_continuation (crc->sched,
+ GNUNET_NO,
+ &run_continuation,
+ crc,
+ GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+
+}
+
+
+
+static int
+check ()
+{
+ pid_t pid;
+ char *const argv[] = { "test-datastore-api-management",
+ "-c",
+ "test_datastore_api_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+ pid = GNUNET_OS_start_process ("gnunet-service-datastore",
+ "gnunet-service-datastore",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ "-c", "test_datastore_api_data.conf", NULL);
+ sleep (1);
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
+ argv, "test-datastore-api", "nohelp",
+ options, &run, NULL);
+ if (0 != PLIBC_KILL (pid, SIGTERM))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
+ ok = 1;
+ }
+ GNUNET_OS_process_wait(pid);
+ if (ok != 0)
+ fprintf (stderr, "Missed some testcases: %u\n", ok);
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-datastore");
+ GNUNET_log_setup ("test-datastore-api",
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+ ret = check ();
+
+ return ret;
+}
+
+
+
+/* end of test_datastore_api_management.c */