gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r5144 - in GNUnet: . src/applications src/applications/sqst


From: gnunet
Subject: [GNUnet-SVN] r5144 - in GNUnet: . src/applications src/applications/sqstore_mysql src/applications/sqstore_mysql_embedded
Date: Mon, 25 Jun 2007 20:33:56 -0600 (MDT)

Author: grothoff
Date: 2007-06-25 20:33:42 -0600 (Mon, 25 Jun 2007)
New Revision: 5144

Added:
   GNUnet/src/applications/sqstore_mysql_embedded/
   GNUnet/src/applications/sqstore_mysql_embedded/Makefile.am
   GNUnet/src/applications/sqstore_mysql_embedded/check.conf
   GNUnet/src/applications/sqstore_mysql_embedded/mysql.c
   GNUnet/src/applications/sqstore_mysql_embedded/mysqltest.c
   GNUnet/src/applications/sqstore_mysql_embedded/mysqltest2.c
   GNUnet/src/applications/sqstore_mysql_embedded/mysqltest3.c
Modified:
   GNUnet/README.debian
   GNUnet/configure.ac
   GNUnet/src/applications/sqstore_mysql/mysqltest2.c
Log:
sqlite

Modified: GNUnet/README.debian
===================================================================
--- GNUnet/README.debian        2007-06-25 07:55:56 UTC (rev 5143)
+++ GNUnet/README.debian        2007-06-26 02:33:42 UTC (rev 5144)
@@ -23,7 +23,7 @@
 guile-1.8-dev (etch or higher!)
 libextractor-dev (etch or higher!)
 libcurl3-gnutls-dev or libcurl4-gnutls-dev
-libsqlite3-dev (recommended)
+libsqlite3-dev 
 libmysqlclient15-dev (optional)
 libncursesw5-dev (optional)
 dialog (optional)

Modified: GNUnet/configure.ac
===================================================================
--- GNUnet/configure.ac 2007-06-25 07:55:56 UTC (rev 5143)
+++ GNUnet/configure.ac 2007-06-26 02:33:42 UTC (rev 5144)
@@ -640,6 +640,7 @@
 src/applications/rpc/Makefile
 src/applications/session/Makefile
 src/applications/sqstore_mysql/Makefile
+src/applications/sqstore_mysql_embedded/Makefile
 src/applications/sqstore_sqlite/Makefile
 src/applications/state/Makefile
 src/applications/stats/Makefile
@@ -705,6 +706,12 @@
 
 AC_MSG_NOTICE([NOTICE: Database support is set to MySQL: $mysql, SQLite: 
$sqlite])
 
+# sqlite
+if test "x$sqlite" = "x0"
+then
+  AC_MSG_NOTICE([WARNING: sqlite not found, this will cause problems with 
file-sharing.]
+fi
+
 # guile
 if test "x$guile" = "x0"
 then

Modified: GNUnet/src/applications/sqstore_mysql/mysqltest2.c
===================================================================
--- GNUnet/src/applications/sqstore_mysql/mysqltest2.c  2007-06-25 07:55:56 UTC 
(rev 5143)
+++ GNUnet/src/applications/sqstore_mysql/mysqltest2.c  2007-06-26 02:33:42 UTC 
(rev 5144)
@@ -277,4 +277,4 @@
   return 0;
 }
 
-/* end of sqlitetest2.c */
+/* end of mysqltest2.c */

Added: GNUnet/src/applications/sqstore_mysql_embedded/Makefile.am
===================================================================
--- GNUnet/src/applications/sqstore_mysql_embedded/Makefile.am                  
        (rev 0)
+++ GNUnet/src/applications/sqstore_mysql_embedded/Makefile.am  2007-06-26 
02:33:42 UTC (rev 5144)
@@ -0,0 +1,54 @@
+INCLUDES = -I$(top_srcdir)/src/include
+
+plugindir = $(libdir)/GNUnet
+
+LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la 
+
+plugin_LTLIBRARIES = \
+  libgnunetmodule_sqstore_mysql.la
+
+check_PROGRAMS = \
+  mysqltest \
+  mysqltest2 \
+  mysqltest3
+
+TESTS = $(check_PROGRAMS)
+
+if HAVE_ZLIB
+ ZLIB_LNK = -lz
+endif
+
+AM_CPPFLAGS = $(CPPFLAGS) $(MYSQL_CPPFLAGS)
+
+libgnunetmodule_sqstore_mysql_la_SOURCES = \
+  mysql.c 
+libgnunetmodule_sqstore_mysql_la_LDFLAGS = \
+  -export-dynamic -avoid-version -module \
+  $(MYSQL_LDFLAGS)
+libgnunetmodule_sqstore_mysql_la_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ -lmysqld $(ZLIB_LNK)
+
+EXTRA_DIST = check.conf
+
+mysqltest_SOURCES = \
+ mysqltest.c 
+mysqltest_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/util/config_impl/libgnunetutil_config.la  \
+ $(top_builddir)/src/server/libgnunetcore.la
+
+mysqltest2_SOURCES = \
+ mysqltest2.c 
+mysqltest2_LDADD = \
+ $(top_builddir)/src/server/libgnunetcore.la  \
+ $(top_builddir)/src/util/config_impl/libgnunetutil_config.la  \
+ $(top_builddir)/src/util/libgnunetutil.la  
+
+mysqltest3_SOURCES = \
+ mysqltest3.c 
+mysqltest3_LDADD = \
+ $(top_builddir)/src/server/libgnunetcore.la  \
+ $(top_builddir)/src/util/config_impl/libgnunetutil_config.la  \
+ $(top_builddir)/src/util/libgnunetutil.la  

Added: GNUnet/src/applications/sqstore_mysql_embedded/check.conf
===================================================================
--- GNUnet/src/applications/sqstore_mysql_embedded/check.conf                   
        (rev 0)
+++ GNUnet/src/applications/sqstore_mysql_embedded/check.conf   2007-06-26 
02:33:42 UTC (rev 5144)
@@ -0,0 +1,42 @@
+[PATHS]
+GNUNETD_HOME = "/tmp/gnunet-mysql-sqstore-test"
+
+[GNUNETD]
+HELLOEXPIRES = 1440
+LOGLEVEL = "ERROR"
+PIDFILE = "$GNUNETD_HOME/gnunet.pid"
+HOSTS = "$GNUNETD_HOME/data/hosts/"
+HTTP-PROXY = ""
+HTTP-PROXY-PORT = 1080
+APPLICATIONS = "fs getoption stats traffic"
+PROCESS-PRIORITY = "NORMAL"
+
+[MODULES]
+sqstore = "sqstore_mysql"
+topology = "topology_default"
+
+[NETWORK]
+PORT = 32087
+INTERFACE = ""
+IP = ""
+HELLOEXCHANGE = YES
+TRUSTED = "127.0.0.0/8;"
+
+[LOAD]
+BASICLIMITING = YES
+INTERFACES = "eth0"
+MAXNETDOWNBPSTOTAL = 50000
+MAXNETUPBPSTOTAL = 50000
+MAXCPULOAD = 50
+
+[FS]
+QUOTA = 1024
+ACTIVEMIGRATION = YES
+DIR = "$GNUNETD_HOME/data/fs/"
+INDEX-DIRECTORY = "$GNUNETD_HOME/data/shared/"
+INDEX-QUOTA = 8192
+POOL = 32
+
+[MYSQL]
+DATABASE = "gnunetcheck"
+CONFIG = ~/.my.cnf

Added: GNUnet/src/applications/sqstore_mysql_embedded/mysql.c
===================================================================
--- GNUnet/src/applications/sqstore_mysql_embedded/mysql.c                      
        (rev 0)
+++ GNUnet/src/applications/sqstore_mysql_embedded/mysql.c      2007-06-26 
02:33:42 UTC (rev 5144)
@@ -0,0 +1,1525 @@
+/*
+     This file is part of GNUnet.
+     (C) 2001, 2002, 2003, 2004, 2005, 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/sqstore_mysql/mysql.c
+ * @author Igor Wronsky and Christian Grothoff
+ *
+ * Database: MySQL
+ *
+ * NOTE: This db module does NOT work with mysql prior to 4.1 since
+ * it uses prepared statements.
+ *
+ * HIGHLIGHTS
+ *
+ * Pros
+ * + On up-to-date hardware where mysql can be used comfortably, this
+ *   module will have better performance than the other db choices
+ *   (according to our tests).
+ * + Its often possible to recover the mysql database from internal
+ *   inconsistencies. The other db choices do not support repair!
+ * Cons
+ * - Memory usage (Comment: "I have 1G and it never caused me trouble")
+ * - Manual setup
+ *
+ * MANUAL SETUP INSTRUCTIONS
+ *
+ * 1) in /etc/gnunet.conf, set
+ *    <pre>
+ *
+ *     sqstore = "sqstore_mysql"
+ *
+ *    </pre>
+ * 2) Then access mysql as root,
+ *    <pre>
+ *
+ *    $ mysql -u root -p
+ *
+ *    </pre>
+ *    and do the following. [You should replace $USER with the username
+ *    that will be running the gnunetd process].
+ *    <pre>
+ *
+      CREATE DATABASE gnunet;
+      GRANT select,insert,update,delete,create,alter,drop
+         ON gnunet.* TO address@hidden;
+      SET PASSWORD FOR address@hidden('$the_password_you_like');
+      FLUSH PRIVILEGES;
+ *
+ *    </pre>
+ * 3) In the $HOME directory of $USER, create a ".my.cnf" file
+ *    with the following lines
+ *    <pre>
+
+      [client]
+      user=$USER
+      password=$the_password_you_like
+
+ *    </pre>
+ *
+ * Thats it. Note that .my.cnf file is a security risk unless its on
+ * a safe partition etc. The $HOME/.my.cnf can of course be a symbolic
+ * link. Even greater security risk can be achieved by setting no
+ * password for $USER.  Luckily $USER has only priviledges to mess
+ * up GNUnet's tables, nothing else (unless you give him more,
+ * of course).<p>
+ *
+ * 4) Still, perhaps you should briefly try if the DB connection
+ *    works. First, login as $USER. Then use,
+ *
+ *    <pre>
+ *    $ mysql -u $USER -p $the_password_you_like
+ *    mysql> use gnunet;
+ *    </pre>
+ *
+ *    If you get the message &quot;Database changed&quot; it probably works.
+ *
+ *    [If you get &quot;ERROR 2002: Can't connect to local MySQL server
+ *     through socket '/tmp/mysql.sock' (2)&quot; it may be resolvable by
+ *     &quot;ln -s /var/run/mysqld/mysqld.sock /tmp/mysql.sock&quot;
+ *     so there may be some additional trouble depending on your mysql setup.]
+ *
+ * REPAIRING TABLES
+ *
+ * - Its probably healthy to check your tables for inconsistencies
+ *   every now and then.
+ * - If you get odd SEGVs on gnunetd startup, it might be that the mysql
+ *   databases have been corrupted.
+ * - The tables can be verified/fixed in two ways;
+ *   1) by shutting down mysqld (mandatory!) and running
+ *   # myisamchk -r *.MYI
+ *   in /var/lib/mysql/gnunet/ (or wherever the tables are stored).
+ *   Another repair command is "mysqlcheck". The usable command
+ *   may depend on your mysql build/version. Or,
+ *   2) by executing
+ *   mysql> REPAIR TABLE gn070;
+ *
+ * PROBLEMS?
+ *
+ * If you have problems related to the mysql module, your best
+ * friend is probably the mysql manual. The first thing to check
+ * is that mysql is basically operational, that you can connect
+ * to it, create tables, issue queries etc.
+ *
+ */
+
+#include "platform.h"
+#include "gnunet_util.h"
+#include "gnunet_protocols.h"
+#include "gnunet_sqstore_service.h"
+#include "gnunet_stats_service.h"
+#include "gnunet_state_service.h"
+#include <mysql/mysql.h>
+
+#define DEBUG_MYSQL NO
+#define DEBUG_TIME_MYSQL NO
+
+/**
+ * Die with an error message that indicates
+ * a failure of the command 'cmd' with the message given
+ * by strerror(errno).
+ */
+#define DIE_MYSQL(cmd, dbh) do { GE_LOG(ectx, GE_FATAL | GE_ADMIN | 
GE_IMMEDIATE, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, 
__LINE__, mysql_error((dbh)->dbf)); abort(); } while(0);
+
+/**
+ * Log an error message at log-level 'level' that indicates
+ * a failure of the command 'cmd' on file 'filename'
+ * with the message given by strerror(errno).
+ */
+#define LOG_MYSQL(level, cmd, dbh) do { GE_LOG(ectx, level, _("`%s' failed at 
%s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); } 
while(0);
+
+static Stats_ServiceAPI * stats;
+
+static CoreAPIForApplication * coreAPI;
+
+static unsigned int stat_size;
+
+/**
+ * Size of the mysql database on disk.
+ */
+static unsigned long long content_size;
+
+/**
+ * Lock for updating content_size
+ */
+static struct MUTEX * lock;
+
+static struct GE_Context * ectx;
+
+/**
+ * @brief mysql wrapper
+ */
+typedef struct {
+  MYSQL * dbf;
+
+  char * cnffile;
+
+  int prepare;
+
+  MYSQL_STMT * insert;
+
+  MYSQL_BIND bind[7];
+
+  MYSQL_STMT * select;
+
+  MYSQL_STMT * selectc;
+
+  MYSQL_STMT * selects;
+
+  MYSQL_STMT * selectsc;
+
+  MYSQL_BIND sbind[2];
+
+  MYSQL_STMT * deleteh;
+
+  MYSQL_STMT * deleteg;
+
+  MYSQL_BIND dbind[7];
+
+  MYSQL_STMT * update;
+
+  MYSQL_BIND ubind[5];
+
+  struct MUTEX * DATABASE_Lock_;
+
+} mysqlHandle;
+
+#define SELECT_SIZE "SELECT sum(size) FROM gn070"
+
+#define INSERT_SAMPLE "INSERT INTO gn070 
(size,type,prio,anonLevel,expire,hash,value) VALUES (?,?,?,?,?,?,?)"
+
+#define SELECT_SAMPLE "SELECT * FROM gn070 WHERE hash=? ORDER BY expire DESC"
+
+#define SELECT_SAMPLE_COUNT "SELECT count(*) FROM gn070 WHERE hash=?"
+
+#define SELECT_TYPE_SAMPLE "SELECT * FROM gn070 WHERE hash=? AND type=?"
+
+#define SELECT_TYPE_SAMPLE_COUNT "SELECT count(*) FROM gn070 WHERE hash=? AND 
type=?"
+
+/**
+ * Select to prepare for key-based deletion.
+ */
+#define SELECT_HASH_SAMPLE "SELECT * FROM gn070 WHERE hash=? ORDER BY prio ASC 
LIMIT 1"
+
+#define DELETE_GENERIC_SAMPLE "DELETE FROM gn070 WHERE hash=? AND size=? AND 
type=? AND prio=? AND anonLevel=? AND expire=? AND value=? ORDER BY prio ASC 
LIMIT 1"
+
+#define UPDATE_SAMPLE "UPDATE gn070 SET 
prio=prio+?,expire=IF(expire>=?,expire,?) WHERE hash=? AND value=?"
+
+static mysqlHandle * dbh;
+
+/**
+ * Given a full (SELECT *) sql_row from gn070 table in database
+ * order, assemble it into a Datastore_Datum representation.
+ *
+ */
+static Datastore_Datum * assembleDatum(MYSQL_RES * res,
+                                      MYSQL_ROW sql_row,
+                                      mysqlHandle * dbhI) {
+  Datastore_Datum * datum;
+  int contentSize;
+  unsigned long * lens;
+  unsigned int type;
+  unsigned int prio;
+  unsigned int level;
+  unsigned long long exp;
+
+  contentSize = atol(sql_row[0]) - sizeof(Datastore_Value);
+  if (contentSize < 0)
+    return NULL; /* error */
+
+  lens = mysql_fetch_lengths(res);
+  if ( (lens[5] != sizeof(HashCode512)) ||
+       (lens[6] != contentSize) ||
+       (sscanf(sql_row[1], "%u", &type) != 1) ||
+       (sscanf(sql_row[2], "%u", &prio) != 1) ||
+       (sscanf(sql_row[3], "%u", &level) != 1) ||
+       (SSCANF(sql_row[4], "%llu", &exp) != 1) ) {
+    mysql_free_result(res);
+    if ( (lens[5] != sizeof(HashCode512)) ||
+        (lens[6] != contentSize) ) {
+      char scratch[512];
+
+      GE_LOG(ectx,
+            GE_WARNING | GE_BULK | GE_USER,
+            _("Invalid data in %s.  Trying to fix (by deletion).\n"),
+            _("mysql datastore"));
+      SNPRINTF(scratch,
+              512,
+              "DELETE FROM gn070 WHERE NOT ((LENGTH(hash)=%u) AND (size=%u + 
LENGTH(value)))",
+              sizeof(HashCode512),
+              sizeof(Datastore_Value));
+      if (0 != mysql_query(dbhI->dbf, scratch))
+       LOG_MYSQL(GE_ERROR | GE_ADMIN | GE_BULK, "mysql_query", dbhI);
+    } else {
+      GE_BREAK(ectx, 0); /* should really never happen */
+    }
+    return NULL;
+  }
+  datum = MALLOC(sizeof(Datastore_Datum) + contentSize);
+  datum->value.size = htonl(contentSize + sizeof(Datastore_Value));
+  datum->value.type = htonl(type);
+  datum->value.prio = htonl(prio);
+  datum->value.anonymityLevel = htonl(level);
+  datum->value.expirationTime = htonll(exp);
+  memcpy(&datum->key,
+        sql_row[5],
+        sizeof(HashCode512));
+  memcpy(&datum[1],
+         sql_row[6],
+        contentSize);
+  return datum;
+}
+
+/**
+ * Initiate the database connection.
+ * Uses dbhI->cnffile for the configuration,
+ * so that must be set already.
+ * @return OK on success
+ */
+static int iopen(mysqlHandle * dbhI,
+                int prepare) {
+  char * dbname;
+
+  if (dbhI->cnffile == NULL)
+    return SYSERR;
+  dbhI->dbf = mysql_init(NULL);
+  if (dbhI->dbf == NULL)
+    return SYSERR;
+  mysql_options(dbhI->dbf,
+               MYSQL_READ_DEFAULT_FILE,
+               dbh->cnffile);
+  mysql_options(dbhI->dbf,
+               MYSQL_READ_DEFAULT_GROUP,
+               "client");
+  dbname = NULL;
+  GC_get_configuration_value_string(coreAPI->cfg,
+                                   "MYSQL",
+                                   "DATABASE",
+                                   "gnunet",
+                                   &dbname);
+  GE_ASSERT(ectx, dbname != NULL);
+  mysql_real_connect(dbhI->dbf,
+                    NULL,
+                    NULL,
+                    NULL,
+                    dbname,
+                    0,
+                    NULL,
+                    0);
+  FREE(dbname);
+  if (mysql_error(dbhI->dbf)[0]) {
+    LOG_MYSQL(GE_ERROR | GE_ADMIN | GE_BULK,
+             "mysql_real_connect",
+             dbhI);
+    dbhI->dbf = NULL;
+    return SYSERR;
+  }
+  if (prepare) {
+    mysql_query(dbhI->dbf,
+               "CREATE TABLE IF NOT EXISTS gn070 ("
+               " size INT(11) NOT NULL DEFAULT 0,"
+               " type INT(11) NOT NULL DEFAULT 0,"
+               " prio INT(11) NOT NULL DEFAULT 0,"
+               " anonLevel INT(11) NOT NULL DEFAULT 0,"
+               " expire BIGINT NOT NULL DEFAULT 0,"
+               " hash TINYBLOB NOT NULL DEFAULT '',"
+               " value BLOB NOT NULL DEFAULT '',"
+               " INDEX (hash(64)),"
+               " INDEX (prio),"
+               " INDEX (expire)"
+               ") TYPE=InnoDB");
+    if (mysql_error(dbhI->dbf)[0]) {
+      LOG_MYSQL(GE_ERROR | GE_ADMIN | GE_BULK,
+               "mysql_query",
+               dbhI);
+      mysql_close(dbhI->dbf);
+      dbhI->dbf = NULL;
+      return SYSERR;
+    }
+    mysql_query(dbhI->dbf,
+               "SET AUTOCOMMIT = 1");
+    if (mysql_error(dbhI->dbf)[0]) {
+      LOG_MYSQL(GE_ERROR | GE_ADMIN | GE_BULK,
+               "mysql_query",
+               dbhI);
+      mysql_close(dbhI->dbf);
+      dbhI->dbf = NULL;
+      return SYSERR;
+    }
+    dbhI->insert = mysql_stmt_init(dbhI->dbf);
+    dbhI->select = mysql_stmt_init(dbhI->dbf);
+    dbhI->selectc = mysql_stmt_init(dbhI->dbf);
+    dbhI->selects = mysql_stmt_init(dbhI->dbf);
+    dbhI->selectsc = mysql_stmt_init(dbhI->dbf);
+    dbhI->update = mysql_stmt_init(dbhI->dbf);
+    dbhI->deleteh = mysql_stmt_init(dbhI->dbf);
+    dbhI->deleteg = mysql_stmt_init(dbhI->dbf);
+    if ( (dbhI->insert == NULL) ||
+        (dbhI->update == NULL) ||
+        (dbhI->select == NULL) ||
+        (dbhI->selectc == NULL) ||
+        (dbhI->selects == NULL) ||
+        (dbhI->selectsc == NULL) ||
+        (dbhI->deleteh == NULL) ||
+        (dbhI->deleteg == NULL) ) {
+      GE_BREAK(ectx, 0);
+      if (dbhI->insert != NULL)
+       mysql_stmt_close(dbhI->insert);
+      if (dbhI->update != NULL)
+       mysql_stmt_close(dbhI->update);
+      if (dbhI->select != NULL)
+       mysql_stmt_close(dbhI->select);
+      if (dbhI->selectc != NULL)
+       mysql_stmt_close(dbhI->selectc);
+      if (dbhI->selects != NULL)
+       mysql_stmt_close(dbhI->selects);
+      if (dbhI->selectsc != NULL)
+       mysql_stmt_close(dbhI->selectsc);
+      mysql_close(dbhI->dbf);
+      dbhI->dbf = NULL;
+      return SYSERR;
+    }
+    if (mysql_stmt_prepare(dbhI->insert,
+                          INSERT_SAMPLE,
+                          strlen(INSERT_SAMPLE)) ||
+       mysql_stmt_prepare(dbhI->select,
+                          SELECT_SAMPLE,
+                          strlen(SELECT_SAMPLE)) ||
+       mysql_stmt_prepare(dbhI->selectc,
+                          SELECT_SAMPLE_COUNT,
+                          strlen(SELECT_SAMPLE_COUNT)) ||
+       mysql_stmt_prepare(dbhI->selects,
+                          SELECT_TYPE_SAMPLE,
+                          strlen(SELECT_TYPE_SAMPLE)) ||
+       mysql_stmt_prepare(dbhI->selectsc,
+                          SELECT_TYPE_SAMPLE_COUNT,
+                          strlen(SELECT_TYPE_SAMPLE_COUNT)) ||
+       mysql_stmt_prepare(dbhI->update,
+                          UPDATE_SAMPLE,
+                          strlen(UPDATE_SAMPLE)) ||
+       mysql_stmt_prepare(dbhI->deleteh,
+                          SELECT_HASH_SAMPLE,
+                          strlen(SELECT_HASH_SAMPLE)) ||
+       mysql_stmt_prepare(dbhI->deleteg,
+                          DELETE_GENERIC_SAMPLE,
+                          strlen(DELETE_GENERIC_SAMPLE)) ) {
+      GE_LOG(ectx, GE_ERROR | GE_BULK | GE_USER,
+         _("`%s' failed at %s:%d with error: I/%s S/%s SC/%s SS/%s SSC/%s U/%s 
D/%s DG/%s\n"),
+            "mysql_stmt_prepare",
+            __FILE__, __LINE__,
+            mysql_stmt_error(dbhI->insert),
+            mysql_stmt_error(dbhI->select),
+            mysql_stmt_error(dbhI->selectc),
+            mysql_stmt_error(dbhI->selects),
+            mysql_stmt_error(dbhI->selectsc),
+            mysql_stmt_error(dbhI->update),
+            mysql_stmt_error(dbhI->deleteh),
+            mysql_stmt_error(dbhI->deleteg));
+      mysql_stmt_close(dbhI->insert);
+      mysql_stmt_close(dbhI->select);
+      mysql_stmt_close(dbhI->selectc);
+      mysql_stmt_close(dbhI->selects);
+      mysql_stmt_close(dbhI->selectsc);
+      mysql_stmt_close(dbhI->update);
+      mysql_stmt_close(dbhI->deleteh);
+      mysql_stmt_close(dbhI->deleteg);
+      mysql_close(dbhI->dbf);
+      dbhI->dbf = NULL;
+      return SYSERR;
+    }
+    memset(dbhI->bind,
+          0,
+          sizeof(dbhI->bind));
+    dbhI->bind[0].buffer_type = MYSQL_TYPE_LONG; /* size */
+    dbhI->bind[1].buffer_type = MYSQL_TYPE_LONG; /* type */
+    dbhI->bind[2].buffer_type = MYSQL_TYPE_LONG; /* prio */
+    dbhI->bind[3].buffer_type = MYSQL_TYPE_LONG; /* anon level */
+    dbhI->bind[4].buffer_type = MYSQL_TYPE_LONGLONG; /* expiration */
+    dbhI->bind[5].buffer_type = MYSQL_TYPE_TINY_BLOB; /* hash */
+    dbhI->bind[6].buffer_type = MYSQL_TYPE_BLOB; /* value */
+    memset(dbhI->sbind,
+          0,
+          sizeof(dbhI->sbind));
+    dbhI->sbind[0].buffer_type = MYSQL_TYPE_TINY_BLOB; /* hash */
+    dbhI->sbind[1].buffer_type = MYSQL_TYPE_LONG; /* type */
+    memset(dbhI->dbind,
+          0,
+          sizeof(dbhI->dbind));
+    dbhI->dbind[0].buffer_type = MYSQL_TYPE_TINY_BLOB; /* hash */
+    dbhI->dbind[1].buffer_type = MYSQL_TYPE_LONG; /* size */
+    dbhI->dbind[2].buffer_type = MYSQL_TYPE_LONG; /* type */
+    dbhI->dbind[3].buffer_type = MYSQL_TYPE_LONG; /* prio */
+    dbhI->dbind[4].buffer_type = MYSQL_TYPE_LONG; /* anon level */
+    dbhI->dbind[5].buffer_type = MYSQL_TYPE_LONGLONG; /* expiration */
+    dbhI->dbind[6].buffer_type = MYSQL_TYPE_BLOB; /* value */
+    memset(dbhI->ubind,
+          0,
+          sizeof(dbhI->ubind));
+    dbhI->ubind[0].buffer_type = MYSQL_TYPE_LONG;
+    dbhI->ubind[1].buffer_type = MYSQL_TYPE_LONG;
+    dbhI->ubind[2].buffer_type = MYSQL_TYPE_LONG;
+    dbhI->ubind[3].buffer_type = MYSQL_TYPE_BLOB;
+    dbhI->ubind[4].buffer_type = MYSQL_TYPE_BLOB;
+    dbhI->prepare = YES;
+  } else
+    dbhI->prepare = NO;
+  dbhI->DATABASE_Lock_ = MUTEX_CREATE(NO);
+  return OK;
+}
+
+/**
+ * Close the database connection.
+ */
+static int iclose(mysqlHandle * dbhI) {
+  if (dbhI->dbf == NULL)
+    return SYSERR;
+  if (dbhI->prepare == YES) {
+    mysql_stmt_free_result(dbhI->update);
+    mysql_stmt_free_result(dbhI->insert);
+    mysql_stmt_free_result(dbhI->select);
+    mysql_stmt_free_result(dbhI->selectc);
+    mysql_stmt_free_result(dbhI->selects);
+    mysql_stmt_free_result(dbhI->selectsc);
+    mysql_stmt_free_result(dbhI->deleteh);
+    mysql_stmt_free_result(dbhI->deleteg);
+    mysql_stmt_close(dbhI->update);
+    mysql_stmt_close(dbhI->insert);
+    mysql_stmt_close(dbhI->select);
+    mysql_stmt_close(dbhI->selectc);
+    mysql_stmt_close(dbhI->selects);
+    mysql_stmt_close(dbhI->selectsc);
+    mysql_stmt_close(dbhI->deleteh);
+    mysql_stmt_close(dbhI->deleteg);
+  }
+  MUTEX_DESTROY(dbhI->DATABASE_Lock_);
+  mysql_close(dbhI->dbf);
+  dbhI->dbf = NULL;
+  return OK;
+}
+
+
+/**
+ * Iterate over the items in the datastore
+ * using the given query to select and order
+ * the items.
+ *
+ * @param type entries of which type should be considered?
+ *        Use 0 for any type.
+ * @param iter never NULL
+ * @return the number of results, SYSERR if the
+ *   iter is non-NULL and aborted the iteration
+ */
+static int iterateHelper(unsigned int type,
+                        const char * query,
+                        Datum_Iterator iter,
+                        void * closure) {
+  MYSQL_RES *sql_res;
+  MYSQL_ROW sql_row;
+  Datastore_Datum * datum;
+  char * scratch;
+  char typestr[32];
+  int count = 0;
+  mysqlHandle dbhI;
+  cron_t now;
+
+  dbhI.cnffile = dbh->cnffile; /* shared */
+  if (OK != iopen(&dbhI, NO))
+    return SYSERR;
+
+  MUTEX_LOCK(dbhI.DATABASE_Lock_);
+  mysql_thread_init();    
+  mysql_query(dbhI.dbf,
+             "SET AUTOCOMMIT = 0");
+  mysql_query(dbhI.dbf,
+             "SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED");
+  if (type==0) {
+    typestr[0] = '\0';
+  } else {
+    SNPRINTF(typestr,
+             32,
+             "WHERE type=%u ",
+            type);
+  }
+  now = get_time();
+  scratch = MALLOC(256);
+  SNPRINTF(scratch,
+          256, 
+          query,
+          typestr,
+          now);
+  mysql_query(dbhI.dbf,
+             scratch);
+  FREE(scratch);
+  if (mysql_error(dbhI.dbf)[0]) {
+    LOG_MYSQL(GE_ERROR | GE_ADMIN | GE_BULK,
+             "mysql_query",
+             &dbhI);
+    mysql_thread_end();    
+    MUTEX_UNLOCK(dbhI.DATABASE_Lock_);
+    iclose(&dbhI);
+    return SYSERR;
+  }
+  if (!(sql_res=mysql_use_result(dbhI.dbf))) {
+    MUTEX_UNLOCK(dbhI.DATABASE_Lock_);
+    iclose(&dbhI);
+    return SYSERR;
+  }
+  while ((sql_row=mysql_fetch_row(sql_res))) {
+    datum = assembleDatum(sql_res,
+                         sql_row,
+                         &dbhI);
+    if (datum == NULL) {
+      mysql_thread_end();    
+      MUTEX_UNLOCK(dbhI.DATABASE_Lock_);
+      iclose(&dbhI);
+      return count;
+    }
+    if ( (iter != NULL) &&
+        (SYSERR == iter(&datum->key,
+                        &datum->value,
+                        closure) ) ) {
+      count = SYSERR;
+      FREE(datum);
+      break;
+    }
+    FREE(datum);
+    count++;
+  }
+  if (mysql_error(dbhI.dbf)[0]) {
+    LOG_MYSQL(GE_ERROR | GE_ADMIN | GE_BULK,
+             "mysql_query",
+             &dbhI);
+    mysql_free_result(sql_res);
+    mysql_thread_end();    
+    MUTEX_UNLOCK(dbhI.DATABASE_Lock_);
+    iclose(&dbhI);
+    return SYSERR;
+  }            
+  mysql_free_result(sql_res);
+  mysql_thread_end();    
+  MUTEX_UNLOCK(dbhI.DATABASE_Lock_);
+  iclose(&dbhI);
+  return count;
+}
+
+/**
+ * Iterate over the items in the datastore in ascending
+ * order of priority.
+ *
+ * @param type entries of which type should be considered?
+ *        Use 0 for any type.
+ * @param iter never NULL
+ * @return the number of results, SYSERR if the
+ *   iter is non-NULL and aborted the iteration
+ */
+static int iterateLowPriority(unsigned int type,
+                             Datum_Iterator iter,
+                             void * closure) {
+  return iterateHelper(type,
+                      "SELECT SQL_NO_CACHE * FROM gn070"
+                      " %s"
+                      "ORDER BY prio ASC",
+                      iter,
+                      closure);
+}
+
+/**
+ * Iterate over the items in the datastore that
+ * have anonymity level 0.
+ *
+ * @param type entries of which type should be considered?
+ *        Use 0 for any type.
+ * @param iter never NULL
+ * @return the number of results, SYSERR if the
+ *   iter is non-NULL and aborted the iteration
+ */
+static int iterateNonAnonymous(unsigned int type,
+                              int on_demand,
+                              Datum_Iterator iter,
+                              void * closure) {
+  char limit[512];
+
+  if (on_demand == YES)
+    SNPRINTF(limit,
+            512,
+            "SELECT SQL_NO_CACHE * FROM gn070"
+            " %%s WHERE expire > %%llu AND anonLevel = 0 AND type != %d",
+            ONDEMAND_BLOCK);
+  else
+    strcpy(limit,
+          "SELECT SQL_NO_CACHE * FROM gn070"
+          " %s WHERE expire > %llu AND anonLevel = 0");
+  return iterateHelper(type,
+                      limit,
+                      iter,
+                      closure);
+}
+
+/**
+ * Iterate over the items in the datastore in ascending
+ * order of expiration time.
+ *
+ * @param type entries of which type should be considered?
+ *        Use 0 for any type.
+ * @param iter never NULL
+ * @return the number of results, SYSERR if the
+ *   iter is non-NULL and aborted the iteration
+ */
+static int iterateExpirationTime(unsigned int type,
+                                Datum_Iterator iter,
+                                void * closure) {
+  return iterateHelper(type,
+                      "SELECT SQL_NO_CACHE * FROM gn070"
+                      " %s"
+                      " ORDER BY expire ASC",
+                      iter,
+                      closure);
+}
+
+/**
+ * Iterate over the items in the datastore in migration
+ * order.
+ *
+ * @param iter never NULL
+ * @return the number of results, SYSERR if the
+ *   iter is non-NULL and aborted the iteration
+ */
+static int iterateMigrationOrder(Datum_Iterator iter,
+                                void * closure) {
+  return iterateHelper(0,
+                      "SELECT SQL_NO_CACHE * FROM gn070"
+                      " %s WHERE expire > %llu"
+                      " ORDER BY expire DESC",
+                      iter,
+                      closure);
+}
+
+/**
+ * Iterate over the items in the datastore as
+ * quickly as possible (in any order).
+ *
+ * @param iter never NULL
+ * @return the number of results, SYSERR if the
+ *   iter is non-NULL and aborted the iteration
+ */
+static int iterateAllNow(Datum_Iterator iter,
+                        void * closure) {
+  return iterateHelper(0,
+                      "SELECT SQL_NO_CACHE * FROM gn070",
+                      iter,
+                      closure);
+}
+
+#define MAX_DATUM_SIZE 65536
+
+/**
+ * Iterate over the results for a particular key
+ * in the datastore.
+ *
+ * @param key maybe NULL (to match all entries)
+ * @param type entries of which type are relevant?
+ *     Use 0 for any type.
+ * @param iter maybe NULL (to just count)
+ * @return the number of results, SYSERR if the
+ *   iter is non-NULL and aborted the iteration
+ */
+static int get(const HashCode512 * query,
+              unsigned int type,       
+              Datum_Iterator iter,
+              void * closure) {
+  MYSQL_RES * sql_res;
+  int count;
+  MYSQL_STMT * stmt;
+  unsigned int size;
+  unsigned int rtype;
+  unsigned int prio;
+  unsigned int level;
+  unsigned long long expiration;
+  unsigned long datasize;
+  unsigned long twenty;
+  Datastore_Value * datum;
+  HashCode512 key;
+  unsigned long hashSize;
+#if DEBUG_MYSQL
+  EncName enc;
+#endif
+
+  if (query == NULL)
+    return iterateLowPriority(type, iter, closure);
+
+#if DEBUG_MYSQL
+  IF_GELOG(ectx,
+          GE_DEBUG | GE_REQUEST | GE_USER,
+          hash2enc(query,
+                   &enc));
+  GE_LOG(ectx,
+        GE_DEBUG | GE_REQUEST | GE_USER,
+        "MySQL looks for `%s' of type %u\n",
+        &enc,
+        type);
+#endif
+  MUTEX_LOCK(dbh->DATABASE_Lock_);
+  mysql_thread_init();    
+  if (type != 0) {
+    if (iter == NULL)
+      stmt = dbh->selectsc;
+    else
+      stmt = dbh->selects;
+  } else {
+    if (iter == NULL)
+      stmt = dbh->selectc;
+    else
+      stmt = dbh->select;
+  }
+  hashSize = sizeof(HashCode512);
+  dbh->sbind[0].buffer = (char*) query;
+  dbh->sbind[1].buffer = (char*) &type;
+  dbh->sbind[0].length = &hashSize;
+  GE_ASSERT(ectx, mysql_stmt_param_count(stmt) <= 2);
+  sql_res = mysql_stmt_result_metadata(stmt);
+  if (! sql_res) {
+    GE_LOG(ectx,
+          GE_ERROR | GE_BULK | GE_USER,
+          _("`%s' failed at %s:%d with error: %s\n"),
+          "mysql_stmt_result_metadata",
+          __FILE__, __LINE__,
+          mysql_stmt_error(stmt));
+    mysql_thread_end();    
+    MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+    return SYSERR;
+  }
+  if (7 != mysql_num_fields(sql_res)) {
+    GE_BREAK(ectx, 0);
+    mysql_thread_end();       
+    MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+    return SYSERR;
+  }
+  if (mysql_stmt_bind_param(stmt,
+                           dbh->sbind)) {
+    GE_LOG(ectx,
+          GE_ERROR | GE_BULK | GE_USER,
+          _("`%s' failed at %s:%d with error: %s\n"),
+          "mysql_stmt_bind_param",
+          __FILE__, __LINE__,
+          mysql_stmt_error(stmt));
+    mysql_thread_end();    
+    MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+    return SYSERR;
+  }
+  if (mysql_stmt_execute(stmt)) {
+    GE_LOG(ectx,
+          GE_ERROR | GE_BULK | GE_USER,
+          _("`%s' failed at %s:%d with error: %s\n"),
+          "mysql_stmt_execute",
+          __FILE__, __LINE__,
+          mysql_stmt_error(stmt));
+    mysql_thread_end();    
+    MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+    return SYSERR;
+  }
+
+  datum = MALLOC(sizeof(Datastore_Value) + MAX_DATUM_SIZE);
+  twenty = sizeof(HashCode512);
+  dbh->bind[0].buffer = (char*) &size;
+  dbh->bind[1].buffer = (char*) &rtype;
+  dbh->bind[2].buffer = (char*) &prio;
+  dbh->bind[3].buffer = (char*) &level;
+  dbh->bind[4].buffer = (char*) &expiration;
+  dbh->bind[5].buffer = (char*) &key;
+  dbh->bind[6].buffer = (char*) &datum[1];
+  dbh->bind[5].length = &twenty;
+  dbh->bind[6].length = &datasize;
+  dbh->bind[5].buffer_length = sizeof(HashCode512);
+  dbh->bind[6].buffer_length = MAX_DATUM_SIZE;
+  if (mysql_stmt_bind_result(stmt,
+                            dbh->bind)) {
+    GE_LOG(ectx,
+          GE_ERROR | GE_BULK | GE_USER,
+          _("`%s' failed at %s:%d with error: %s\n"),
+          "mysql_stmt_bind_result",
+          __FILE__, __LINE__,
+          mysql_stmt_error(stmt));
+    mysql_thread_end();    
+    MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+    FREE(datum);
+    return SYSERR;
+  }
+  if (mysql_stmt_store_result(stmt)) {
+    GE_LOG(ectx,
+          GE_ERROR | GE_BULK | GE_USER,
+          _("`%s' failed at %s:%d with error: %s\n"),
+          "mysql_stmt_store_result",
+          __FILE__, __LINE__,
+          mysql_stmt_error(stmt));
+    mysql_thread_end();    
+    MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+    FREE(datum);
+    return SYSERR;
+  }
+  datasize = MAX_DATUM_SIZE;
+  count = 0;
+  while (0 == mysql_stmt_fetch(stmt)) {
+    if ( (twenty != sizeof(HashCode512)) ||
+        (datasize != size - sizeof(Datastore_Value)) ) {
+      char scratch[512];
+
+      mysql_free_result(sql_res);
+      GE_LOG(ectx,
+            GE_WARNING | GE_BULK | GE_USER,
+            _("Invalid data in %s.  Trying to fix (by deletion).\n"),
+            _("mysql datastore"));
+      SNPRINTF(scratch,
+              512,
+              "DELETE FROM gn070 WHERE NOT ((LENGTH(hash)=%u) AND (size=%u + 
LENGTH(value)))",
+              sizeof(HashCode512),
+              sizeof(Datastore_Value));
+      if (0 != mysql_query(dbh->dbf, scratch))
+       LOG_MYSQL(GE_ERROR | GE_ADMIN | GE_BULK, "mysql_query", dbh);
+
+      FREE(datum);
+      mysql_thread_end();    
+      MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+      return count;
+    }
+    count++;
+    if (iter != NULL) {
+      datum->size = htonl(size);
+      datum->type = htonl(rtype);
+      datum->prio = htonl(prio);
+      datum->anonymityLevel = htonl(level);
+      datum->expirationTime = htonll(expiration);
+#if DEBUG_MYSQL
+      GE_LOG(ectx,
+            GE_DEBUG | GE_REQUEST | GE_USER,
+            "Found in database block with type %u.\n",
+            ntohl(*(int*)&datum[1]));
+#endif
+      if( SYSERR == iter(&key,
+                        datum,
+                        closure) ) {
+        count = SYSERR;
+       break;
+      }
+    }
+    datasize = MAX_DATUM_SIZE;
+  }
+  if (mysql_stmt_errno(stmt)) {
+    GE_LOG(ectx,
+          GE_ERROR | GE_BULK | GE_USER,
+          _("`%s' failed at %s:%d with error: %s\n"),
+          "mysql_stmt_fetch",
+          __FILE__, __LINE__,
+          mysql_stmt_error(stmt));
+  }
+  mysql_free_result(sql_res);
+  FREE(datum);
+  mysql_thread_end();    
+  MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+
+#if DEBUG_MYSQL
+  IF_GELOG(ectx,
+          GE_DEBUG | GE_REQUEST | GE_USER,
+          hash2enc(query,
+                   &enc));
+  if (count > 0) {
+    GE_LOG(ectx,
+          GE_DEBUG | GE_REQUEST | GE_USER,
+          "MySQL found %d results for `%s' of type %u.\n",
+          count,
+          &enc,
+          type);
+  } else {
+    GE_LOG(ectx,
+          GE_DEBUG | GE_REQUEST | GE_USER,
+          "MySQL iteration aborted looking for `%s' of type %u.\n",
+          &enc,
+          type);
+  }
+#endif
+  return count;
+}
+
+/**
+ * Store an item in the datastore.
+ *
+ * @return OK on success, SYSERR on error
+ */
+static int put(const HashCode512 * key,
+              const Datastore_Value * value) {
+  unsigned long contentSize;
+  unsigned long hashSize;
+  unsigned int size;
+  unsigned int type;
+  unsigned int prio;
+  unsigned int level;
+  unsigned long long expiration;
+#if DEBUG_MYSQL
+  EncName enc;
+#endif
+
+  if ( (ntohl(value->size) < sizeof(Datastore_Value)) ) {
+    GE_BREAK(ectx, 0);
+    return SYSERR;
+  }
+  MUTEX_LOCK(dbh->DATABASE_Lock_);
+  mysql_thread_init();    
+  contentSize = ntohl(value->size)-sizeof(Datastore_Value);
+  hashSize = sizeof(HashCode512);
+  size = ntohl(value->size);
+  type = ntohl(value->type);
+  prio = ntohl(value->prio);
+  level = ntohl(value->anonymityLevel);
+  expiration = ntohll(value->expirationTime);
+#if DEBUG_MYSQL
+  IF_GELOG(ectx,
+          GE_DEBUG | GE_REQUEST | GE_USER,
+          hash2enc(key,
+                   &enc));
+  GE_LOG(ectx,
+        GE_DEBUG | GE_REQUEST | GE_USER,
+        "Storing in database block with type %u and key %s.\n",
+        type,
+        &enc);
+#endif
+  dbh->bind[0].buffer = (char*) &size;
+  dbh->bind[1].buffer = (char*) &type;
+  dbh->bind[2].buffer = (char*) &prio;
+  dbh->bind[3].buffer = (char*) &level;
+  dbh->bind[4].buffer = (char*) &expiration;
+  dbh->bind[5].buffer = (char*) key;
+  dbh->bind[6].buffer = (char*) &value[1];
+  dbh->bind[5].length = &hashSize;
+  dbh->bind[6].length = &contentSize;
+
+  if (mysql_stmt_bind_param(dbh->insert,
+                           dbh->bind)) {
+    GE_LOG(ectx,
+          GE_ERROR | GE_BULK | GE_USER,
+          _("`%s' failed at %s:%d with error: %s\n"),
+          "mysql_stmt_bind_param",
+          __FILE__, __LINE__,
+          mysql_stmt_error(dbh->insert));
+    mysql_thread_end();    
+    MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+    return SYSERR;
+  }
+
+  if (mysql_stmt_execute(dbh->insert)) {
+    GE_LOG(ectx,
+          GE_ERROR | GE_BULK | GE_USER,
+          _("`%s' failed at %s:%d with error: %s\n"),
+          "mysql_stmt_execute",
+          __FILE__, __LINE__,
+          mysql_stmt_error(dbh->insert));
+    mysql_thread_end();    
+    MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+    return SYSERR;
+  }
+  mysql_thread_end();    
+  MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+  MUTEX_LOCK(lock);
+  content_size += ntohl(value->size);
+  MUTEX_UNLOCK(lock);
+  return OK;
+}
+
+/**
+ * Delete an item from the datastore.
+ *
+ * @param value maybe NULL, then all items under the
+ *        given key are deleted
+ * @return the number of items deleted, 0 if
+ *        none were found, SYSERR on errors
+ */
+static int del(const HashCode512 * key,
+              const Datastore_Value * value) {
+  int count;
+  unsigned long twenty;
+  MYSQL_STMT * stmt;
+  unsigned int size;
+  unsigned int type;
+  unsigned int prio;
+  unsigned int anon;
+  unsigned long long expiration;
+  unsigned long datasize;
+  Datastore_Value * svalue;
+  MYSQL_RES * sql_res;
+  unsigned int rtype;
+  unsigned int level;
+  HashCode512 skey;
+#if DEBUG_MYSQL
+  EncName enc;
+
+  IF_GELOG(ectx,
+          GE_DEBUG | GE_REQUEST | GE_USER,
+          hash2enc(key,
+                   &enc));
+  GE_LOG(ectx,
+        GE_DEBUG | GE_REQUEST | GE_USER,
+        "MySQL is executing deletion request for content of query `%s' and 
type %u\n",
+        &enc,
+        value == NULL ? 0 : ntohl(value->type));
+#endif
+  MUTEX_LOCK(dbh->DATABASE_Lock_);
+  mysql_thread_init();
+  twenty = sizeof(HashCode512);
+  svalue = NULL;
+  if (value == NULL) {
+    stmt = dbh->deleteh;
+    dbh->dbind[0].buffer = (char*) key;
+    dbh->dbind[0].length = &twenty;
+    GE_ASSERT(ectx, mysql_stmt_param_count(stmt) <= 1);
+
+    sql_res = mysql_stmt_result_metadata(stmt);
+    if (! sql_res) {
+      GE_LOG(ectx,
+            GE_ERROR | GE_BULK | GE_USER,
+            _("`%s' failed at %s:%d with error: %s\n"),
+            "mysql_stmt_result_metadata",
+            __FILE__, __LINE__,
+            mysql_stmt_error(stmt));
+      mysql_thread_end();    
+      MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+      return SYSERR;
+    }
+    if (7 != mysql_num_fields(sql_res)) {
+      GE_BREAK(ectx, 0);
+      MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+      return SYSERR;
+    }
+    if (mysql_stmt_bind_param(stmt,
+                             dbh->dbind)) {
+      GE_LOG(ectx,
+            GE_ERROR | GE_BULK | GE_USER,
+            _("`%s' failed at %s:%d with error: %s\n"),
+            "mysql_stmt_bind_param",
+            __FILE__, __LINE__,
+            mysql_stmt_error(stmt));
+      mysql_thread_end();      
+      MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+      return SYSERR;
+    }
+    if (mysql_stmt_execute(stmt)) {
+      GE_LOG(ectx,
+            GE_ERROR | GE_BULK | GE_USER,
+            _("`%s' failed at %s:%d with error: %s\n"),
+            "mysql_stmt_execute",
+            __FILE__, __LINE__,
+            mysql_stmt_error(stmt));
+      mysql_thread_end();
+      MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+      return SYSERR;
+    }
+    svalue = MALLOC(sizeof(Datastore_Value) + MAX_DATUM_SIZE);
+    twenty = sizeof(HashCode512);
+    dbh->bind[0].buffer = (char*) &size;
+    dbh->bind[1].buffer = (char*) &rtype;
+    dbh->bind[2].buffer = (char*) &prio;
+    dbh->bind[3].buffer = (char*) &level;
+    dbh->bind[4].buffer = (char*) &expiration;
+    dbh->bind[5].buffer = (char*) &skey;
+    dbh->bind[6].buffer = (char*) &svalue[1];
+    dbh->bind[5].length = &twenty;
+    dbh->bind[6].length = &datasize;
+    dbh->bind[5].buffer_length = sizeof(HashCode512);
+    dbh->bind[6].buffer_length = MAX_DATUM_SIZE;
+    if (mysql_stmt_bind_result(stmt,
+                              dbh->bind)) {
+      GE_LOG(ectx,
+            GE_ERROR | GE_BULK | GE_USER,
+            _("`%s' failed at %s:%d with error: %s\n"),
+            "mysql_stmt_bind_result",
+            __FILE__, __LINE__,
+            mysql_stmt_error(stmt));
+      mysql_thread_end();      
+      MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+      FREE(svalue);
+      return SYSERR;
+    }
+    if (mysql_stmt_store_result(stmt)) {
+      GE_LOG(ectx,
+            GE_ERROR | GE_BULK | GE_USER,
+            _("`%s' failed at %s:%d with error: %s\n"),
+            "mysql_stmt_store_result",
+            __FILE__, __LINE__,
+            mysql_stmt_error(stmt));
+      mysql_thread_end();        
+      MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+      FREE(svalue);
+      return SYSERR;
+    }
+    datasize = MAX_DATUM_SIZE;
+    if (0 != mysql_stmt_fetch(stmt)) {
+      GE_LOG(ectx,
+            GE_ERROR | GE_BULK | GE_USER,
+            _("`%s' failed at %s:%d with error: %s\n"),
+            "mysql_stmt_fetch",
+            __FILE__, __LINE__,
+            mysql_stmt_error(stmt));
+      mysql_thread_end();
+      MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+      FREE(svalue);
+      return SYSERR;
+    }
+    if ( (twenty != sizeof(HashCode512)) ||
+        (datasize != size - sizeof(Datastore_Value)) ) {
+      char scratch[512];
+
+      mysql_free_result(sql_res);
+      GE_LOG(ectx,
+            GE_WARNING | GE_BULK | GE_USER,
+            _("Invalid data in %s.  Trying to fix (by deletion).\n"),
+            _("mysql datastore"));
+      SNPRINTF(scratch,
+              512,
+              "DELETE FROM gn070 WHERE NOT ((LENGTH(hash)=%u) AND (size=%u + 
LENGTH(value)))",
+              sizeof(HashCode512),
+              sizeof(Datastore_Value));
+      if (0 != mysql_query(dbh->dbf, scratch))
+       LOG_MYSQL(GE_ERROR | GE_ADMIN | GE_BULK,
+                 "mysql_query", dbh);
+      FREE(svalue);
+      mysql_thread_end();
+      MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+      return 1;
+    }
+    mysql_free_result(sql_res);
+    svalue->size = htonl(size);
+    svalue->type = htonl(rtype);
+    svalue->prio = htonl(prio);
+    svalue->anonymityLevel = htonl(level);
+    svalue->expirationTime = htonll(expiration);
+    value = svalue;
+  }
+
+  stmt = dbh->deleteg;
+  type = ntohl(value->type);
+  size = ntohl(value->size);
+  prio = ntohl(value->prio);
+  anon = ntohl(value->anonymityLevel);
+  expiration = ntohll(value->expirationTime);
+  datasize = ntohl(value->size) - sizeof(Datastore_Value);
+  dbh->dbind[0].buffer = (char*) key;
+  dbh->dbind[0].length = &twenty;
+  dbh->dbind[1].buffer = (char*) &size;
+  dbh->dbind[2].buffer = (char*) &type;
+  dbh->dbind[3].buffer = (char*) &prio;
+  dbh->dbind[4].buffer = (char*) &anon;
+  dbh->dbind[5].buffer = (char*) &expiration;
+  dbh->dbind[6].buffer = (char*) &value[1];
+  dbh->dbind[6].length = &datasize;
+#if 0
+  dbh->dbind[0].buffer_length = sizeof(HashCode512);
+  dbh->dbind[6].buffer_length = size - sizeof(Datastore_Value);
+#endif
+  GE_ASSERT(ectx, mysql_stmt_param_count(stmt) <= 7);
+  if (mysql_stmt_bind_param(stmt,
+                           dbh->dbind)) {
+    GE_LOG(ectx,
+          GE_ERROR | GE_BULK | GE_USER,
+          _("`%s' failed at %s:%d with error: %s\n"),
+          "mysql_stmt_bind_param",
+          __FILE__, __LINE__,
+          mysql_stmt_error(stmt));
+    mysql_thread_end();
+    MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+    if (svalue != NULL)
+      FREE(svalue);
+    return SYSERR;
+  }
+  if (mysql_stmt_execute(stmt)) {
+    GE_LOG(ectx,
+          GE_ERROR | GE_BULK | GE_USER,
+          _("`%s' failed at %s:%d with error: %s\n"),
+          "mysql_stmt_execute",
+          __FILE__, __LINE__,
+          mysql_stmt_error(stmt));
+    mysql_thread_end();
+    MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+    if (svalue != NULL)
+      FREE(svalue);
+    return SYSERR;
+  }
+  count = mysql_stmt_affected_rows(stmt);
+  mysql_thread_end();
+  MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+#if DEBUG_MYSQL
+  GE_LOG(ectx,
+        GE_DEBUG | GE_REQUEST | GE_USER,
+        "MySQL DELETE operation affected %d rows.\n",
+        count);
+#endif
+  MUTEX_LOCK(lock);
+  content_size -= ntohl(value->size);
+  MUTEX_UNLOCK(lock);
+  if (svalue != NULL)
+    FREE(svalue);
+  return count;
+}
+
+/**
+ * Update the priority for a particular key
+ * in the datastore.
+ */
+static int update(const HashCode512 * key,
+                 const Datastore_Value * value,
+                 int delta,
+                 cron_t expire) {
+  unsigned long contentSize;
+  unsigned long twenty;
+
+  twenty = sizeof(HashCode512);
+  MUTEX_LOCK(dbh->DATABASE_Lock_);
+  mysql_thread_init();
+  contentSize = ntohl(value->size)-sizeof(Datastore_Value);
+  dbh->ubind[0].buffer = (char*) &delta;
+  dbh->ubind[1].buffer = (char*) &expire;
+  dbh->ubind[2].buffer = (char*) &expire;
+  dbh->ubind[3].buffer = (char*) key;
+  dbh->ubind[3].length = &twenty;
+  dbh->ubind[4].buffer = (char*) &value[1];
+  dbh->ubind[4].length = &contentSize;
+  GE_ASSERT(ectx,
+           mysql_stmt_param_count(dbh->update) <= 5);
+  if (mysql_stmt_bind_param(dbh->update,
+                           dbh->ubind)) {
+    GE_LOG(ectx,
+          GE_ERROR | GE_BULK | GE_USER,
+          _("`%s' failed at %s:%d with error: %s\n"),
+          "mysql_stmt_bind_param",
+          __FILE__, __LINE__,
+          mysql_stmt_error(dbh->update));
+    mysql_thread_end();
+    MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+    return SYSERR;
+  }
+  /* NOTE: as the table entry for 'prio' is defined as unsigned,
+   * mysql will zero the value if its about to go negative. (This
+   * will generate a warning though, but its probably not seen
+   * at all in this context.)
+   */
+  if (mysql_stmt_execute(dbh->update)) {
+    GE_LOG(ectx,
+          GE_ERROR | GE_BULK | GE_USER,
+          _("`%s' failed at %s:%d with error: %s\n"),
+          "mysql_stmt_execute",
+          __FILE__, __LINE__,
+          mysql_stmt_error(dbh->update));
+    mysql_thread_end();
+    MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+    return SYSERR;
+  }
+  mysql_thread_end();
+  MUTEX_UNLOCK(dbh->DATABASE_Lock_);
+  return OK;
+}
+
+/**
+ * Get the current on-disk size of the SQ store.
+ * Estimates are fine, if that's the only thing
+ * available.
+ * @return number of bytes used on disk
+ */
+static unsigned long long getSize() {
+  unsigned long long ret;
+
+  MUTEX_LOCK(lock);
+  ret = content_size;
+  if (stats)
+    stats->set(stat_size, ret);
+  MUTEX_UNLOCK(lock);
+  return ret * 2; /* common overhead seems to be 100%! */
+}
+
+/**
+ * Delete the database.  The next operation is
+ * guaranteed to be unloading of the module.
+ */
+static void drop() {
+  mysql_query(dbh->dbf,
+             "DROP TABLE gn070");
+  if (mysql_error(dbh->dbf)[0]) {
+    LOG_MYSQL(GE_ERROR | GE_ADMIN | GE_BULK,
+             "mysql_query",
+             dbh);
+  } else
+    content_size = 0;
+}
+
+SQstore_ServiceAPI *
+provide_module_sqstore_mysql(CoreAPIForApplication * capi) {
+  static SQstore_ServiceAPI api;
+  State_ServiceAPI * state;
+  char * cnffile;
+  FILE * fp;
+  struct passwd * pw;
+  size_t nX;
+  char * home_dir;
+  unsigned long long * sb;
+  MYSQL_RES *sql_res;
+  MYSQL_ROW sql_row;
+
+  ectx = capi->ectx;
+  coreAPI = capi;
+  stats = coreAPI->requestService("stats");
+  if (stats)
+    stat_size
+      = stats->create(gettext_noop("# bytes in datastore"));
+
+  /* verify that .my.cnf can be found */
+#ifndef WINDOWS
+  pw = getpwuid(getuid());
+  if(!pw)
+    GE_DIE_STRERROR(ectx,
+                   GE_FATAL | GE_ADMIN | GE_IMMEDIATE,
+                   "getpwuid");
+  home_dir = STRDUP(pw->pw_dir);
+#else
+  home_dir = (char *) MALLOC(_MAX_PATH + 1);
+  plibc_conv_to_win_path("~/", home_dir);
+#endif
+  nX = strlen(home_dir)+10;
+  cnffile = MALLOC(nX);
+  SNPRINTF(cnffile,
+          nX,
+          "%s/.my.cnf",
+          home_dir);
+  FREE(home_dir);
+  GC_get_configuration_value_filename(capi->cfg,
+                                     "MYSQL",
+                                     "CONFIG",
+                                     cnffile,
+                                     &home_dir);
+  FREE(cnffile);
+  cnffile = home_dir;
+  GE_LOG(ectx,
+        GE_DEBUG | GE_REQUEST | GE_USER,
+        _("Trying to use file `%s' for MySQL configuration.\n"),
+        cnffile);
+  fp = FOPEN(cnffile, "r");
+  if (!fp) {
+    GE_LOG_STRERROR_FILE(ectx,
+                        GE_ERROR | GE_ADMIN | GE_BULK,
+                        "fopen",
+                        cnffile);
+    if (stats != NULL)
+      coreAPI->releaseService(stats);
+    FREE(cnffile);
+    return NULL;
+  } else {
+    fclose(fp);
+  }
+  dbh = MALLOC(sizeof(mysqlHandle));
+  dbh->cnffile = cnffile;  
+  if (OK != iopen(dbh, YES)) {
+    FREE(cnffile);
+    FREE(dbh);
+    GE_LOG(ectx,
+          GE_ERROR | GE_BULK | GE_USER,
+          _("Failed to load MySQL database module.  Check that MySQL is 
running and configured properly!\n"));
+    dbh = NULL;
+    if (stats != NULL)
+      coreAPI->releaseService(stats);
+    return NULL;
+  }
+
+  lock = MUTEX_CREATE(NO);
+  state = coreAPI->requestService("state");
+  sb = NULL;
+  if (sizeof(unsigned long long)
+      != state->read(ectx,
+                    "mysql-size",
+                    (void*) &sb)) {
+
+    /* need to recompute! */
+    sql_res = NULL;
+    mysql_query(dbh->dbf,
+               SELECT_SIZE);
+    if ( (mysql_error(dbh->dbf)[0]) ||
+        (!(sql_res=mysql_use_result(dbh->dbf))) ||
+        (!(sql_row=mysql_fetch_row(sql_res))) ) {
+      LOG_MYSQL(GE_ERROR | GE_ADMIN | GE_BULK,
+               "mysql_query",
+               dbh);
+      content_size = 0;
+    } else {
+      if ( (mysql_num_fields(sql_res) != 1) ||
+          (sql_row[0] == NULL) ) {
+       GE_BREAK(ectx, mysql_num_fields(sql_res) == 1);
+       content_size = 0;
+      } else {
+       if (1 != SSCANF(sql_row[0],
+                       "%llu",
+                       &content_size)) {
+         GE_BREAK(ectx, 0);
+         content_size = 0;
+       }
+      }
+    }
+    if (sql_res != NULL)
+      mysql_free_result(sql_res);
+  } else {
+    content_size = *sb;
+    FREE(sb);
+    /* no longer valid! remember it by deleting
+       the outdated state file! */
+    state->unlink(ectx,
+                 "mysql-size");
+  }
+  coreAPI->releaseService(state);
+  api.getSize = &getSize;
+  api.put = &put;
+  api.get = &get;
+  api.iterateLowPriority = &iterateLowPriority;
+  api.iterateNonAnonymous = &iterateNonAnonymous;
+  api.iterateExpirationTime = &iterateExpirationTime;
+  api.iterateMigrationOrder = &iterateMigrationOrder;
+  api.iterateAllNow = &iterateAllNow;
+  api.del = &del;
+  api.drop = &drop;
+  api.update = &update;
+  return &api;
+}
+
+/**
+ * Shutdown the module.
+ */
+void release_module_sqstore_mysql() {
+  State_ServiceAPI * state;
+  iclose(dbh);
+  FREE(dbh->cnffile);
+  FREE(dbh);
+  dbh = NULL;
+
+  if (stats != NULL)
+    coreAPI->releaseService(stats);
+  MUTEX_DESTROY(lock);
+  state = coreAPI->requestService("state");
+  state->write(ectx,
+              "mysql-size",
+              sizeof(unsigned long long),
+              &content_size);
+  coreAPI->releaseService(state);
+  mysql_library_end();
+  ectx = NULL;
+  coreAPI = NULL;
+}
+
+/* end of mysql.c */


Property changes on: GNUnet/src/applications/sqstore_mysql_embedded/mysql.c
___________________________________________________________________
Name: svn:eol-style
   + native

Added: GNUnet/src/applications/sqstore_mysql_embedded/mysqltest.c
===================================================================
--- GNUnet/src/applications/sqstore_mysql_embedded/mysqltest.c                  
        (rev 0)
+++ GNUnet/src/applications/sqstore_mysql_embedded/mysqltest.c  2007-06-26 
02:33:42 UTC (rev 5144)
@@ -0,0 +1,264 @@
+/*
+     This file is part of GNUnet.
+     (C) 2004, 2005, 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/sqstore_sqlite/sqlitetest.c
+ * @brief Test for the sqstore implementations.
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util.h"
+#include "gnunet_util_cron.h"
+#include "gnunet_util_config_impl.h"
+#include "gnunet_protocols.h"
+#include "gnunet_sqstore_service.h"
+#include "core.h"
+
+#define ASSERT(x) do { if (! (x)) { printf("Error at %s:%d\n", __FILE__, 
__LINE__); goto FAILURE;} } while (0)
+
+static cron_t now;
+
+static Datastore_Value * initValue(int i) {
+  Datastore_Value * value;
+
+  value = MALLOC(sizeof(Datastore_Value) + 8 * i);
+  value->size = htonl(sizeof(Datastore_Value) + 8 * i);
+  value->type = htonl(i);
+  value->prio = htonl(i+1);
+  value->anonymityLevel = htonl(i);
+  value->expirationTime = htonll(now - i * cronSECONDS);
+  memset(&value[1], i, 8*i);
+  return value;
+}
+
+static int checkValue(const HashCode512 * key,
+                     const Datastore_Value * val,
+                     void * closure) {
+  int i;
+  int ret;
+  Datastore_Value * value;
+
+  i = *(int*) closure;
+  value = initValue(i);
+  if ( ( value->size == val->size) &&
+       (0 == memcmp(val,
+                   value,
+                   ntohl(val->size)) ) )
+    ret = OK;
+  else {
+    /*
+    printf("Wanted: %u, %llu; got %u, %llu - %d\n",
+          ntohl(value->size), ntohll(value->expirationTime),
+          ntohl(val->size), ntohll(val->expirationTime),
+          memcmp(val, value, ntohl(val->size))); */
+    ret = SYSERR;
+  }
+  FREE(value);
+  return ret;
+}
+
+static int iterateUp(const HashCode512 * key,
+                    const Datastore_Value * val,
+                    int * closure) {
+  int ret;
+
+  ret = checkValue(key, val, closure);
+  (*closure) += 2;
+  return ret;
+}
+
+static int iterateDown(const HashCode512 * key,
+                      const Datastore_Value * val,
+                      int * closure) {
+  int ret;
+
+  (*closure) -= 2;
+  ret = checkValue(key, val, closure);
+  return ret;
+}
+
+static int iterateDelete(const HashCode512 * key,
+                        const Datastore_Value * val,
+                        SQstore_ServiceAPI * api) {
+  if (1 == api->del(key, val))
+       return OK;
+  else
+       return SYSERR;
+}
+
+static int priorityCheck(const HashCode512 * key,
+                        const Datastore_Value * val,
+                        int * closure) {
+  int id;
+
+  id = (*closure);
+  if (id + 1 == ntohl(val->prio))
+    return OK;
+  else
+    return SYSERR;
+}
+
+static int multipleCheck(const HashCode512 * key,
+                        const Datastore_Value * val,
+                        Datastore_Value ** last) {
+  if (*last != NULL) {
+    if ( ((*last)->size == val->size) &&
+        (0 == memcmp(*last,
+                     val,
+                     ntohl(val->size)) ) )
+      return SYSERR; /* duplicate! */
+    FREE(*last);
+  }
+  *last = MALLOC(ntohl(val->size));
+  memcpy(*last,
+        val,
+        ntohl(val->size));
+  return OK;
+}
+
+
+/**
+ * Add testcode here!
+ */
+static int test(SQstore_ServiceAPI * api) {
+  Datastore_Value * value;
+  HashCode512 key;
+  unsigned long long oldSize;
+  int i;
+
+  now = 1000000;
+  oldSize = api->getSize();
+  for (i=0;i<256;i++) {
+    value = initValue(i);
+    memset(&key, 256-i, sizeof(HashCode512));
+    ASSERT(OK == api->put(&key, value));
+    FREE(value);
+  }
+  ASSERT(oldSize < api->getSize());
+  ASSERT(256 == api->iterateLowPriority(ANY_BLOCK,
+                                       NULL,
+                                       NULL));
+  ASSERT(256 == api->iterateExpirationTime(ANY_BLOCK,
+                                          NULL,
+                                          NULL));
+  for (i=255;i>=0;i--) {
+    memset(&key, 256-i, sizeof(HashCode512));
+    ASSERT(1 == api->get(&key, i, &checkValue, (void*) &i));
+  }
+
+  oldSize = api->getSize();
+  for (i=255;i>=0;i-=2) {
+    memset(&key, 256-i, sizeof(HashCode512));
+    value = initValue(i);
+    ASSERT(1 == api->del(&key, value));
+    FREE(value);
+  }
+  ASSERT(oldSize > api->getSize());
+  i = 0;
+  ASSERT(128 == api->iterateLowPriority(ANY_BLOCK,
+                                       (Datum_Iterator) &iterateUp,
+                                       &i));
+  ASSERT(256 == i);
+  ASSERT(128 == api->iterateExpirationTime(ANY_BLOCK,
+                                          (Datum_Iterator) &iterateDown,
+                                          &i));
+  ASSERT(0 == i);
+  ASSERT(128 == api->iterateExpirationTime(ANY_BLOCK,
+                                          (Datum_Iterator) &iterateDelete,
+                                          api));
+  ASSERT(0 == api->iterateExpirationTime(ANY_BLOCK,
+                                        (Datum_Iterator) &iterateDown,
+                                        &i));
+
+  i = 42;
+  value = initValue(i);
+  memset(&key, 256-i, sizeof(HashCode512));
+  api->put(&key, value);
+  ASSERT(1 == api->iterateExpirationTime(ANY_BLOCK,
+                                        (Datum_Iterator) &priorityCheck,
+                                        &i));
+  api->update(&key,
+             value,
+             4,
+             0);
+  i += 4;
+  ASSERT(1 == api->iterateExpirationTime(ANY_BLOCK,
+                                        (Datum_Iterator) &priorityCheck,
+                                        &i));
+  FREE(value);
+
+  /* test multiple results */
+  value = initValue(i+1);
+  api->put(&key, value);
+  FREE(value);
+
+  value = NULL;
+  ASSERT(2 == api->iterateExpirationTime(ANY_BLOCK,
+                                        (Datum_Iterator) &multipleCheck,
+                                        &value));
+  FREE(value);
+  api->del(&key,
+          NULL);
+  api->del(&key,
+          NULL);
+  ASSERT(0 == api->iterateExpirationTime(ANY_BLOCK,
+                                        NULL,
+                                        NULL));
+  api->drop();
+
+  return OK;
+
+ FAILURE:
+  api->drop();
+  return SYSERR;
+}
+
+int main(int argc, char *argv[]) {
+  SQstore_ServiceAPI * api;
+  int ok;
+  struct GC_Configuration * cfg;
+  struct CronManager * cron;
+
+  cfg = GC_create_C_impl();
+  if (-1 == GC_parse_configuration(cfg,
+                                  "check.conf")) {
+    GC_free(cfg);
+    return -1;
+  }
+  cron = cron_create(NULL);
+  initCore(NULL,
+          cfg,
+          cron,
+          NULL);
+  api = requestService("sqstore");
+  if (api != NULL) {
+    ok = test(api);
+    releaseService(api);
+  } else
+    ok = SYSERR;
+  doneCore();
+  cron_destroy(cron);
+  GC_free(cfg);
+  if (ok == SYSERR)
+    return 1;
+  return 0;
+}
+
+/* end of sqlitetest.c */


Property changes on: GNUnet/src/applications/sqstore_mysql_embedded/mysqltest.c
___________________________________________________________________
Name: svn:eol-style
   + native

Added: GNUnet/src/applications/sqstore_mysql_embedded/mysqltest2.c
===================================================================
--- GNUnet/src/applications/sqstore_mysql_embedded/mysqltest2.c                 
        (rev 0)
+++ GNUnet/src/applications/sqstore_mysql_embedded/mysqltest2.c 2007-06-26 
02:33:42 UTC (rev 5144)
@@ -0,0 +1,280 @@
+/*
+     This file is part of GNUnet.
+     (C) 2004, 2005, 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/sqstore_sqlite/sqlitetest2.c
+ * @brief Test for the sqstore implementations.
+ * @author Christian Grothoff
+ *
+ * This testcase inserts a bunch of (variable size) data and then deletes
+ * data until the (reported) database size drops below a given threshold.
+ * This is iterated 10 times, with the actual size of the content stored,
+ * the database size reported and the file size on disk being printed for
+ * each iteration.  The code also prints a "I" for every 40 blocks
+ * inserted and a "D" for every 40 blocks deleted.  The deletion
+ * strategy alternates between "lowest priority" and "earliest expiration".
+ * Priorities and expiration dates are set using a pseudo-random value
+ * within a realistic range.
+ * <p>
+ *
+ * Note that the disk overhead calculations are not very sane for
+ * MySQL: we take the entire /var/lib/mysql directory (best we can
+ * do for ISAM), which may contain other data and which never
+ * shrinks.  The scanning of the entire mysql directory during
+ * each report is also likely to be the cause of a minor
+ * slowdown compared to sqlite.<p>
+ */
+
+#include "platform.h"
+#include "gnunet_util.h"
+#include "gnunet_util_cron.h"
+#include "gnunet_util_crypto.h"
+#include "gnunet_util_config_impl.h"
+#include "gnunet_protocols.h"
+#include "gnunet_sqstore_service.h"
+#include "core.h"
+
+#define ASSERT(x) do { if (! (x)) { printf("Error at %s:%d\n", __FILE__, 
__LINE__); goto FAILURE;} } while (0)
+
+/**
+ * Target datastore size (in bytes).
+ * <p>
+ * Example impact of total size on the reported number
+ * of operations (insert and delete) per second (once
+ * roughly stabilized -- this is not "sound" experimental
+ * data but just a rough idea) for a particular machine:
+ * <pre>
+ *    4: 60   at   7k ops total
+ *    8: 50   at   3k ops total
+ *   16: 48   at   8k ops total
+ *   32: 46   at   8k ops total
+ *   64: 61   at   9k ops total
+ *  128: 89   at   9k ops total
+ * 4092: 11   at 383k ops total (12 GB stored, 14.8 GB DB size on disk, 2.5 GB 
reported)
+ * </pre>
+ * Pure insertion performance into an empty DB initially peaks
+ * at about 400 ops.  The performance seems to drop especially
+ * once the existing (fragmented) ISAM space is filled up and
+ * the DB needs to grow on disk.  This could be explained with
+ * ISAM looking more carefully for defragmentation opportunities.
+ * <p>
+ * MySQL disk space overheads (for otherwise unused database when
+ * run with 128 MB target data size; actual size 651 MB, useful
+ * data stored 520 MB) are quite large in the range of 25-30%.
+ * <p>
+ * This kind of processing seems to be IO bound (system is roughly
+ * at 90% wait, 10% CPU).  This is with MySQL 5.0.
+ *
+ */
+#define MAX_SIZE 1024LL * 1024 * 16
+
+/**
+ * Report progress outside of major reports? Should probably be YES if
+ * size is > 16 MB.
+ */
+#define REPORT_ID NO
+
+/**
+ * Number of put operations equivalent to 1/10th of MAX_SIZE
+ */
+#define PUT_10 MAX_SIZE / 32 / 1024 / 10
+
+/**
+ * Progress report frequency.  1/10th of a put operation block.
+ */
+#define REP_FREQ PUT_10 / 10
+
+/**
+ * Total number of iterations (each iteration doing
+ * PUT_10 put operations); we report full status every
+ * 10 iterations.  Abort with CTRL-C.
+ */
+#define ITERATIONS 100
+
+/**
+ * Name of the database on disk. 
+ * You may have to adjust this path and the access
+ * permission to the respective directory in order
+ * to obtain all of the performance information.
+ */
+#define DB_NAME "/var/lib/mysql"
+
+static unsigned long long stored_bytes;
+
+static unsigned long long stored_entries;
+
+static unsigned long long stored_ops;
+
+static cron_t start_time;
+
+static int putValue(SQstore_ServiceAPI * api,
+                   int i) {
+  Datastore_Value * value;
+  size_t size;
+  static HashCode512 key;
+  static int ic;
+
+  /* most content is 32k */
+  size = sizeof(Datastore_Value) + 32 * 1024;
+  if (weak_randomi(16) == 0) /* but some of it is less! */
+    size = sizeof(Datastore_Value) + weak_randomi(32 * 1024);
+  size = size - (size & 7); /* always multiple of 8 */
+
+  /* generate random key */
+  hash(&key,
+       sizeof(HashCode512),
+       &key);
+  value = MALLOC(size);
+  value->size = htonl(size);
+  value->type = htonl(i);
+  value->prio = htonl(weak_randomi(100));
+  value->anonymityLevel = htonl(i);
+  value->expirationTime = htonll(get_time() + weak_randomi(1000));
+  memset(&value[1],
+        i,
+        size - sizeof(Datastore_Value));
+  if (OK != api->put(&key, value)) {
+    FREE(value);
+    fprintf(stderr, "E");
+    return SYSERR;
+  }
+  ic++;
+#if REPORT_ID
+  if (ic % REP_FREQ == 0)
+    fprintf(stderr, "I");
+#endif
+  stored_bytes += ntohl(value->size);
+  stored_ops++;
+  stored_entries++;
+  FREE(value);
+  return OK;
+}
+
+static int
+iterateDelete(const HashCode512 * key,
+             const Datastore_Value * val,
+             void * cls) {
+  SQstore_ServiceAPI * api = cls;
+  static int dc;
+
+  if (api->getSize() < MAX_SIZE)
+    return SYSERR;
+  if (GNUNET_SHUTDOWN_TEST() == YES)
+    return SYSERR;
+  dc++;
+#if REPORT_ID
+  if (dc % REP_FREQ == 0)
+    fprintf(stderr, "D");
+#endif
+  GE_ASSERT(NULL, 1 == api->del(key, val));
+  stored_bytes -= ntohl(val->size);
+  stored_entries--;
+  return OK;
+}
+
+/**
+ * Add testcode here!
+ */
+static int test(SQstore_ServiceAPI * api) {
+  int i;
+  int j;
+  unsigned long long size;
+  int have_file;
+  struct stat sbuf;
+
+  have_file = 0 == stat(DB_NAME, &sbuf);
+
+  for (i=0;i<ITERATIONS;i++) {
+#if REPORT_ID
+    fprintf(stderr, ".");
+#endif
+    /* insert data equivalent to 1/10th of MAX_SIZE */
+    for (j=0;j<PUT_10;j++) {
+      ASSERT(OK == putValue(api, j));
+      if (GNUNET_SHUTDOWN_TEST() == YES)
+       break;
+    }
+
+    /* trim down below MAX_SIZE again */
+    if ((i % 2) == 0)
+      api->iterateLowPriority(0, &iterateDelete, api);
+    else
+      api->iterateExpirationTime(0, &iterateDelete, api);
+
+    size = 0;
+    if (have_file)
+      disk_file_size(NULL,
+                    DB_NAME,
+                    &size,
+                    NO);
+    printf(
+#if REPORT_ID
+          "\n"
+#endif
+          "Useful %llu, API %llu, disk %llu (%.2f%%) / %lluk ops / %llu 
ops/s\n",
+          stored_bytes / 1024,  /* used size in k */
+          api->getSize() / 1024, /* API-reported size in k */
+          size / 1024, /* disk size in kb */
+          (100.0 * size / stored_bytes) - 100, /* overhead */
+          (stored_ops * 2 - stored_entries) / 1024, /* total operations (in k) 
*/
+          1000 * (stored_ops * 2 - stored_entries) / (1 + get_time() - 
start_time)); /* operations per second */
+    if (GNUNET_SHUTDOWN_TEST() == YES)
+      break;
+  }
+  api->drop();
+  return OK;
+
+ FAILURE:
+  api->drop();
+  return SYSERR;
+}
+
+int main(int argc, char *argv[]) {
+  SQstore_ServiceAPI * api;
+  int ok;
+  struct GC_Configuration * cfg;
+  struct CronManager * cron;
+
+  cfg = GC_create_C_impl();
+  if (-1 == GC_parse_configuration(cfg,
+                                  "check.conf")) {
+    GC_free(cfg);
+    return -1;
+  }
+  cron = cron_create(NULL);
+  initCore(NULL,
+          cfg,
+          cron,
+          NULL);
+  api = requestService("sqstore");
+  if (api != NULL) {
+    start_time = get_time();
+    ok = test(api);
+    releaseService(api);
+  } else
+    ok = SYSERR;
+  doneCore();
+  cron_destroy(cron);
+  GC_free(cfg);
+  if (ok == SYSERR)
+    return 1;
+  return 0;
+}
+
+/* end of mysqltest2.c */


Property changes on: GNUnet/src/applications/sqstore_mysql_embedded/mysqltest2.c
___________________________________________________________________
Name: svn:eol-style
   + native

Added: GNUnet/src/applications/sqstore_mysql_embedded/mysqltest3.c
===================================================================
--- GNUnet/src/applications/sqstore_mysql_embedded/mysqltest3.c                 
        (rev 0)
+++ GNUnet/src/applications/sqstore_mysql_embedded/mysqltest3.c 2007-06-26 
02:33:42 UTC (rev 5144)
@@ -0,0 +1,198 @@
+/*
+     This file is part of GNUnet.
+     (C) 2004, 2005, 2006, 2007 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/sqstore_mysql/mysqltest3.c
+ * @brief Profile sqstore iterators.
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util.h"
+#include "gnunet_util_cron.h"
+#include "gnunet_util_crypto.h"
+#include "gnunet_util_config_impl.h"
+#include "gnunet_protocols.h"
+#include "gnunet_sqstore_service.h"
+#include "core.h"
+
+/**
+ * Target datastore size (in bytes).  Realistic sizes are
+ * more like 16 GB (not the default of 16 MB); however,
+ * those take too long to run them in the usual "make check"
+ * sequence.  Hence the value used for shipping is tiny.
+ */
+#define MAX_SIZE 1024LL * 1024 * 128
+
+#define ITERATIONS 10
+
+/**
+ * Number of put operations equivalent to 1/10th of MAX_SIZE
+ */
+#define PUT_10 (MAX_SIZE / 32 / 1024 / ITERATIONS)
+
+static unsigned long long stored_bytes;
+
+static unsigned long long stored_entries;
+
+static unsigned long long stored_ops;
+
+static cron_t start_time;
+
+static int putValue(SQstore_ServiceAPI * api,
+                   int i) {
+  Datastore_Value * value;
+  size_t size;
+  static HashCode512 key;
+  static int ic;
+
+  /* most content is 32k */
+  size = sizeof(Datastore_Value) + 32 * 1024;
+  if (weak_randomi(16) == 0) /* but some of it is less! */
+    size = sizeof(Datastore_Value) + weak_randomi(32 * 1024);
+  size = size - (size & 7); /* always multiple of 8 */
+
+  /* generate random key */
+  hash(&key,
+       sizeof(HashCode512),
+       &key);
+  value = MALLOC(size);
+  value->size = htonl(size);
+  value->type = htonl(i);
+  value->prio = htonl(weak_randomi(100));
+  value->anonymityLevel = htonl(i);
+  value->expirationTime = htonll(get_time() + 60 * cronHOURS + 
weak_randomi(1000));
+  memset(&value[1],
+        i,
+        size - sizeof(Datastore_Value));
+  if (OK != api->put(&key, value)) {
+    FREE(value);
+    fprintf(stderr, "E");
+    return SYSERR;
+  }
+  ic++;
+  stored_bytes += ntohl(value->size);
+  stored_ops++;
+  stored_entries++;
+  FREE(value);
+  return OK;
+}
+
+static int
+iterateDummy(const HashCode512 * key,
+            const Datastore_Value * val,
+            void * cls) {
+  if (GNUNET_SHUTDOWN_TEST() == YES)
+    return SYSERR;
+  return OK;
+}
+
+static int test(SQstore_ServiceAPI * api) {
+  int i;
+  int j;
+  cron_t start;
+  cron_t end;
+
+  for (i=0;i<ITERATIONS;i++) {
+    /* insert data equivalent to 1/10th of MAX_SIZE */
+    start = get_time();
+    for (j=0;j<PUT_10;j++) {
+      if (OK != putValue(api, j))
+       break;
+      if (GNUNET_SHUTDOWN_TEST() == YES)
+       break;
+    }
+    end = get_time();
+    printf("%3u insertion              took %20llums\n", i, end-start);
+    if (GNUNET_SHUTDOWN_TEST() == YES)
+      break;
+    start = get_time();
+    api->iterateLowPriority(0, &iterateDummy, api);
+    end = get_time();
+    printf("%3u low priority iteration took %20llums\n", i, end-start);
+    if (GNUNET_SHUTDOWN_TEST() == YES)
+      break;
+    start = get_time();
+    api->iterateExpirationTime(0, &iterateDummy, api);
+    end = get_time();
+    printf("%3u expiration t iteration took %20llums\n", i, end-start);
+    if (GNUNET_SHUTDOWN_TEST() == YES)
+      break;
+    start = get_time();
+    api->iterateNonAnonymous(0, NO, &iterateDummy, api);
+    end = get_time();
+    printf("%3u non anonymou iteration took %20llums\n", i, end-start);
+    if (GNUNET_SHUTDOWN_TEST() == YES)
+      break;
+    start = get_time();
+    api->iterateNonAnonymous(0, YES, &iterateDummy, api);
+    end = get_time();
+    printf("%3u non anon YES iteration took %20llums\n", i, end-start);
+    if (GNUNET_SHUTDOWN_TEST() == YES)
+      break;
+    start = get_time();
+    api->iterateMigrationOrder(&iterateDummy, api);
+    end = get_time();
+    printf("%3u migration or iteration took %20llums\n", i, end-start);
+    if (GNUNET_SHUTDOWN_TEST() == YES)
+      break;
+    start = get_time();
+    api->iterateAllNow(&iterateDummy, api);
+    end = get_time();
+    printf("%3u all now      iteration took %20llums\n", i, end-start);
+    if (GNUNET_SHUTDOWN_TEST() == YES)
+      break;
+  }
+  api->drop();
+  return OK;
+}
+
+int main(int argc, char *argv[]) {
+  SQstore_ServiceAPI * api;
+  int ok;
+  struct GC_Configuration * cfg;
+  struct CronManager * cron;
+
+  cfg = GC_create_C_impl();
+  if (-1 == GC_parse_configuration(cfg,
+                                  "check.conf")) {
+    GC_free(cfg);
+    return -1;
+  }
+  cron = cron_create(NULL);
+  initCore(NULL,
+          cfg,
+          cron,
+          NULL);
+  api = requestService("sqstore");
+  if (api != NULL) {
+    start_time = get_time();
+    ok = test(api);
+    releaseService(api);
+  } else
+    ok = SYSERR;
+  doneCore();
+  cron_destroy(cron);
+  GC_free(cfg);
+  if (ok == SYSERR)
+    return 1;
+  return 0;
+}
+
+/* end of mysqltest3.c */


Property changes on: GNUnet/src/applications/sqstore_mysql_embedded/mysqltest3.c
___________________________________________________________________
Name: svn:eol-style
   + native





reply via email to

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