aboutsummaryrefslogtreecommitdiff
path: root/src/datacache
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2010-08-13 19:43:17 +0000
committerChristian Grothoff <christian@grothoff.org>2010-08-13 19:43:17 +0000
commit54edcbe9ce37e934a0d045fdde27e9caa3ac145a (patch)
tree1f87dffbbb93f09bb4d0b606022ad9595d11bad8 /src/datacache
parent2151b951b91971bd9c906b12ab940b0ee0038001 (diff)
downloadgnunet-54edcbe9ce37e934a0d045fdde27e9caa3ac145a.tar.gz
gnunet-54edcbe9ce37e934a0d045fdde27e9caa3ac145a.zip
mysql hackery
Diffstat (limited to 'src/datacache')
-rw-r--r--src/datacache/Makefile.am70
-rw-r--r--src/datacache/perf_datacache.c52
-rw-r--r--src/datacache/perf_datacache_data_mysql.conf12
-rw-r--r--src/datacache/perf_datacache_data_sqlite.conf (renamed from src/datacache/perf_datacache_data.conf)0
-rw-r--r--src/datacache/plugin_datacache_mysql.c1092
-rw-r--r--src/datacache/test_datacache.c50
-rw-r--r--src/datacache/test_datacache_data_mysql.conf12
-rw-r--r--src/datacache/test_datacache_data_sqlite.conf (renamed from src/datacache/test_datacache_data.conf)0
-rw-r--r--src/datacache/test_datacache_quota.c50
9 files changed, 1258 insertions, 80 deletions
diff --git a/src/datacache/Makefile.am b/src/datacache/Makefile.am
index a10343046..0598c2673 100644
--- a/src/datacache/Makefile.am
+++ b/src/datacache/Makefile.am
@@ -14,6 +14,9 @@ endif
14if HAVE_SQLITE 14if HAVE_SQLITE
15 SQLITE_PLUGIN = libgnunet_plugin_datacache_sqlite.la 15 SQLITE_PLUGIN = libgnunet_plugin_datacache_sqlite.la
16endif 16endif
17if HAVE_MYSQL
18 MYSQL_PLUGIN = libgnunet_plugin_datacache_mysql.la
19endif
17 20
18lib_LTLIBRARIES = \ 21lib_LTLIBRARIES = \
19 libgnunetdatacache.la 22 libgnunetdatacache.la
@@ -31,6 +34,7 @@ libgnunetdatacache_la_LDFLAGS = \
31 34
32plugin_LTLIBRARIES = \ 35plugin_LTLIBRARIES = \
33 $(SQLITE_PLUGIN) \ 36 $(SQLITE_PLUGIN) \
37 $(MYSQL_PLUGIN) \
34 libgnunet_plugin_datacache_template.la 38 libgnunet_plugin_datacache_template.la
35 39
36 40
@@ -42,6 +46,17 @@ libgnunet_plugin_datacache_sqlite_la_LIBADD = \
42libgnunet_plugin_datacache_sqlite_la_LDFLAGS = \ 46libgnunet_plugin_datacache_sqlite_la_LDFLAGS = \
43 $(GN_PLUGIN_LDFLAGS) 47 $(GN_PLUGIN_LDFLAGS)
44 48
49libgnunet_plugin_datacache_mysql_la_SOURCES = \
50 plugin_datacache_mysql.c
51libgnunet_plugin_datacache_mysql_la_LIBADD = \
52 $(top_builddir)/src/statistics/libgnunetstatistics.la \
53 $(top_builddir)/src/util/libgnunetutil.la \
54 $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient
55libgnunet_plugin_datacache_mysql_la_CPPFLAGS = \
56 $(MYSQL_CPPFLAGS)
57libgnunet_plugin_datacache_mysql_la_LDFLAGS = \
58 $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient
59
45libgnunet_plugin_datacache_template_la_SOURCES = \ 60libgnunet_plugin_datacache_template_la_SOURCES = \
46 plugin_datacache_template.c 61 plugin_datacache_template.c
47libgnunet_plugin_datacache_template_la_LIBADD = \ 62libgnunet_plugin_datacache_template_la_LIBADD = \
@@ -51,36 +66,65 @@ libgnunet_plugin_datacache_template_la_LDFLAGS = \
51 66
52 67
53if HAVE_SQLITE 68if HAVE_SQLITE
54 SQLITE_TESTS = \ 69SQLITE_TESTS = \
55 test_datacache \ 70 test_datacache_sqlite \
56 test_datacache_quota \ 71 test_datacache_quota_sqlite \
57 perf_datacache 72 perf_datacache_sqlite
58endif 73endif
59 74
60check_PROGRAMS = $(SQLITE_TESTS) 75if HAVE_MYSQL
76MYSQL_TESTS = \
77 test_datacache_mysql \
78 test_datacache_quota_mysql \
79 perf_datacache_mysql
80endif
81
82check_PROGRAMS = \
83 $(SQLITE_TESTS) \
84 $(MYSQL_TESTS)
61 85
62if !DISABLE_TEST_RUN 86if !DISABLE_TEST_RUN
63TESTS = $(check_PROGRAMS) 87TESTS = $(check_PROGRAMS)
64endif 88endif
65 89
66test_datacache_SOURCES = \ 90test_datacache_sqlite_SOURCES = \
91 test_datacache.c
92test_datacache_sqlite_LDADD = \
93 $(top_builddir)/src/datacache/libgnunetdatacache.la \
94 $(top_builddir)/src/util/libgnunetutil.la
95
96test_datacache_quota_sqlite_SOURCES = \
97 test_datacache_quota.c
98test_datacache_quota_sqlite_LDADD = \
99 $(top_builddir)/src/datacache/libgnunetdatacache.la \
100 $(top_builddir)/src/util/libgnunetutil.la
101
102perf_datacache_sqlite_SOURCES = \
103 perf_datacache.c
104perf_datacache_sqlite_LDADD = \
105 $(top_builddir)/src/datacache/libgnunetdatacache.la \
106 $(top_builddir)/src/util/libgnunetutil.la
107
108test_datacache_mysql_SOURCES = \
67 test_datacache.c 109 test_datacache.c
68test_datacache_LDADD = \ 110test_datacache_mysql_LDADD = \
69 $(top_builddir)/src/datacache/libgnunetdatacache.la \ 111 $(top_builddir)/src/datacache/libgnunetdatacache.la \
70 $(top_builddir)/src/util/libgnunetutil.la 112 $(top_builddir)/src/util/libgnunetutil.la
71 113
72test_datacache_quota_SOURCES = \ 114test_datacache_quota_mysql_SOURCES = \
73 test_datacache_quota.c 115 test_datacache_quota.c
74test_datacache_quota_LDADD = \ 116test_datacache_quota_mysql_LDADD = \
75 $(top_builddir)/src/datacache/libgnunetdatacache.la \ 117 $(top_builddir)/src/datacache/libgnunetdatacache.la \
76 $(top_builddir)/src/util/libgnunetutil.la 118 $(top_builddir)/src/util/libgnunetutil.la
77 119
78perf_datacache_SOURCES = \ 120perf_datacache_mysql_SOURCES = \
79 perf_datacache.c 121 perf_datacache.c
80perf_datacache_LDADD = \ 122perf_datacache_mysql_LDADD = \
81 $(top_builddir)/src/datacache/libgnunetdatacache.la \ 123 $(top_builddir)/src/datacache/libgnunetdatacache.la \
82 $(top_builddir)/src/util/libgnunetutil.la 124 $(top_builddir)/src/util/libgnunetutil.la
83 125
84EXTRA_DIST = \ 126EXTRA_DIST = \
85 test_datacache_data.conf \ 127 test_datacache_data_sqlite.conf \
86 perf_datacache_data.conf 128 perf_datacache_data_sqlite.conf \
129 test_datacache_data_mysql.conf \
130 perf_datacache_data_mysql.conf
diff --git a/src/datacache/perf_datacache.c b/src/datacache/perf_datacache.c
index a577927d0..e2eb474d4 100644
--- a/src/datacache/perf_datacache.c
+++ b/src/datacache/perf_datacache.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2006, 2009 Christian Grothoff (and other contributing authors) 3 (C) 2006, 2009, 2010 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -36,6 +36,12 @@ static int ok;
36 36
37static unsigned int found; 37static unsigned int found;
38 38
39/**
40 * Name of plugin under test.
41 */
42static const char *plugin_name;
43
44
39static int 45static int
40checkIt (void *cls, 46checkIt (void *cls,
41 struct GNUNET_TIME_Absolute exp, 47 struct GNUNET_TIME_Absolute exp,
@@ -119,12 +125,15 @@ FAILURE:
119} 125}
120 126
121 127
122static int 128int
123check () 129main (int argc, char *argv[])
124{ 130{
125 char *const argv[] = { "perf-datacache-api", 131 const char *pos;
132 char cfg_name[128];
133 char *const xargv[] = {
134 "perf-datacache",
126 "-c", 135 "-c",
127 "perf_datacache_data.conf", 136 cfg_name,
128#if VERBOSE 137#if VERBOSE
129 "-L", "DEBUG", 138 "-L", "DEBUG",
130#endif 139#endif
@@ -133,31 +142,28 @@ check ()
133 struct GNUNET_GETOPT_CommandLineOption options[] = { 142 struct GNUNET_GETOPT_CommandLineOption options[] = {
134 GNUNET_GETOPT_OPTION_END 143 GNUNET_GETOPT_OPTION_END
135 }; 144 };
136 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
137 argv, "perf-datacache-api", "nohelp",
138 options, &run, NULL);
139 if (ok != 0)
140 fprintf (stderr, "Missed some perfcases: %d\n", ok);
141 return ok;
142}
143
144
145int
146main (int argc, char *argv[])
147{
148 int ret;
149 145
150 GNUNET_DISK_directory_remove ("/tmp/perf-gnunetd-datacache"); 146 GNUNET_log_setup ("perf-datacache",
151 GNUNET_log_setup ("perf-datacache-api",
152#if VERBOSE 147#if VERBOSE
153 "DEBUG", 148 "DEBUG",
154#else 149#else
155 "WARNING", 150 "WARNING",
156#endif 151#endif
157 NULL); 152 NULL);
158 ret = check (); 153 /* determine name of plugin to use */
159 154 plugin_name = argv[0];
160 return ret; 155 while (NULL != (pos = strstr(plugin_name, "_")))
156 plugin_name = pos+1;
157 GNUNET_snprintf (cfg_name,
158 sizeof (cfg_name),
159 "perf_datacache_data_%s.conf",
160 plugin_name);
161 GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1,
162 xargv, "perf-datacache", "nohelp",
163 options, &run, NULL);
164 if (ok != 0)
165 fprintf (stderr, "Missed some perfcases: %d\n", ok);
166 return ok;
161} 167}
162 168
163/* end of perf_datacache.c */ 169/* end of perf_datacache.c */
diff --git a/src/datacache/perf_datacache_data_mysql.conf b/src/datacache/perf_datacache_data_mysql.conf
new file mode 100644
index 000000000..5a5f97c63
--- /dev/null
+++ b/src/datacache/perf_datacache_data_mysql.conf
@@ -0,0 +1,12 @@
1
2[perfcache]
3QUOTA = 500000
4DATABASE = mysql
5
6[datacache-mysql]
7DATABASE = gnunetcheck
8# CONFIG = ~/.my.cnf
9# USER =
10# PASSWORD =
11# HOST =
12# PORT = \ No newline at end of file
diff --git a/src/datacache/perf_datacache_data.conf b/src/datacache/perf_datacache_data_sqlite.conf
index 55e178d99..55e178d99 100644
--- a/src/datacache/perf_datacache_data.conf
+++ b/src/datacache/perf_datacache_data_sqlite.conf
diff --git a/src/datacache/plugin_datacache_mysql.c b/src/datacache/plugin_datacache_mysql.c
new file mode 100644
index 000000000..4559a9d39
--- /dev/null
+++ b/src/datacache/plugin_datacache_mysql.c
@@ -0,0 +1,1092 @@
1/*
2 This file is part of GNUnet
3 (C) 2006, 2009, 2010 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file datacache/plugin_datacache_mysql.c
23 * @brief mysql for an implementation of a database backend for the datacache
24 * @author Christian Grothoff
25 *
26 * SETUP INSTRUCTIONS:
27 *
28 * 1) Access mysql as root,
29 * <pre>
30 *
31 * $ mysql -u root -p
32 *
33 * </pre>
34 * and do the following. [You should replace $USER with the username
35 * that will be running the gnunetd process].
36 * <pre>
37 *
38 CREATE DATABASE gnunet;
39 GRANT select,insert,update,delete,create,alter,drop,create temporary tables
40 ON gnunet.* TO $USER@localhost;
41 SET PASSWORD FOR $USER@localhost=PASSWORD('$the_password_you_like');
42 FLUSH PRIVILEGES;
43 *
44 * </pre>
45 * 2) In the $HOME directory of $USER, create a ".my.cnf" file
46 * with the following lines
47 * <pre>
48
49 [client]
50 user=$USER
51 password=$the_password_you_like
52
53 * </pre>
54 *
55 * Thats it -- now you can configure your datastores in GNUnet to
56 * use MySQL. Note that .my.cnf file is a security risk unless its on
57 * a safe partition etc. The $HOME/.my.cnf can of course be a symbolic
58 * link. Even greater security risk can be achieved by setting no
59 * password for $USER. Luckily $USER has only priviledges to mess
60 * up GNUnet's tables, nothing else (unless you give him more,
61 * of course).<p>
62 *
63 * 3) Still, perhaps you should briefly try if the DB connection
64 * works. First, login as $USER. Then use,
65 *
66 * <pre>
67 * $ mysql -u $USER -p $the_password_you_like
68 * mysql> use gnunet;
69 * </pre>
70 *
71 * If you get the message &quot;Database changed&quot; it probably works.
72 *
73 * [If you get &quot;ERROR 2002: Can't connect to local MySQL server
74 * through socket '/tmp/mysql.sock' (2)&quot; it may be resolvable by
75 * &quot;ln -s /var/run/mysqld/mysqld.sock /tmp/mysql.sock&quot;
76 * so there may be some additional trouble depending on your mysql setup.]
77 *
78 * REPAIRING TABLES:
79 * - Its probably healthy to check your tables for inconsistencies
80 * every now and then.
81 * - If you get odd SEGVs on gnunetd startup, it might be that the mysql
82 * databases have been corrupted.
83 * - The tables can be verified/fixed in two ways;
84 * 1) by running mysqlcheck -A, or
85 * 2) by executing (inside of mysql using the GNUnet database):
86 * mysql> SHOW TABLES;
87 * mysql> REPAIR TABLE gnXXX;
88 *
89 * Make sure to replace XXX with the actual names of all tables.
90 *
91 * PROBLEMS?
92 *
93 * If you have problems related to the mysql module, your best
94 * friend is probably the mysql manual. The first thing to check
95 * is that mysql is basically operational, that you can connect
96 * to it, create tables, issue queries etc.
97 */
98#include "platform.h"
99#include "gnunet_util_lib.h"
100#include "plugin_datacache.h"
101#include <mysql/mysql.h>
102
103#define DEBUG_DATACACHE_MYSQL GNUNET_NO
104
105/**
106 * Estimate of the per-entry overhead (including indices).
107 */
108#define OVERHEAD ((4*2+4*2+8*2+8*2+sizeof(GNUNET_HashCode)*5+8))
109
110/**
111 * Maximum number of supported parameters for a prepared
112 * statement. Increase if needed.
113 */
114#define MAX_PARAM 16
115
116/**
117 * Die with an error message that indicates
118 * a failure of the command 'cmd' with the message given
119 * by strerror(errno).
120 */
121#define DIE_MYSQL(cmd, dbh) do { GNUNET_log(GNUNET_ERROR_TYPE__ERROR, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); abort(); } while(0);
122
123/**
124 * Log an error message at log-level 'level' that indicates
125 * a failure of the command 'cmd' on file 'filename'
126 * with the message given by strerror(errno).
127 */
128#define LOG_MYSQL(level, cmd, dbh) do { GNUNET_log(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); } while(0);
129
130struct GNUNET_MysqlStatementHandle
131{
132 struct GNUNET_MysqlStatementHandle *next;
133
134 struct GNUNET_MysqlStatementHandle *prev;
135
136 char *query;
137
138 MYSQL_STMT *statement;
139
140 int valid;
141
142};
143
144
145/**
146 * Context for all functions in this plugin.
147 */
148struct Plugin
149{
150 /**
151 * Our execution environment.
152 */
153 struct GNUNET_DATACACHE_PluginEnvironment *env;
154
155 /**
156 * Handle to the mysql database.
157 */
158 MYSQL *dbf;
159
160 struct GNUNET_MysqlStatementHandle *shead;
161
162 struct GNUNET_MysqlStatementHandle *stail;
163
164 /**
165 * Filename of "my.cnf" (msyql configuration).
166 */
167 char *cnffile;
168
169#define SELECT_VALUE_STMT "SELECT value,expire FROM gn080dstore FORCE INDEX (hashidx) WHERE hash=? AND type=? AND expire >= ? LIMIT 1 OFFSET ?"
170 struct GNUNET_MysqlStatementHandle *select_value;
171
172#define COUNT_VALUE_STMT "SELECT count(*) FROM gn080dstore FORCE INDEX (hashidx) WHERE hash=? AND type=? AND expire >= ?"
173 struct GNUNET_MysqlStatementHandle *count_value;
174
175#define SELECT_OLD_VALUE_STMT "SELECT hash, vhash, type, value FROM gn080dstore FORCE INDEX (expireidx) ORDER BY puttime ASC LIMIT 1"
176 struct GNUNET_MysqlStatementHandle *select_old_value;
177
178#define DELETE_VALUE_STMT "DELETE FROM gn080dstore WHERE hash = ? AND vhash = ? AND type = ? AND value = ?"
179 struct GNUNET_MysqlStatementHandle *delete_value;
180
181#define INSERT_VALUE_STMT "INSERT INTO gn080dstore (type, puttime, expire, hash, vhash, value) "\
182 "VALUES (?, ?, ?, ?, ?, ?)"
183 struct GNUNET_MysqlStatementHandle *insert_value;
184
185#define UPDATE_VALUE_STMT "UPDATE gn080dstore FORCE INDEX (allidx) SET puttime=?, expire=? "\
186 "WHERE hash=? AND vhash=? AND type=?"
187 struct GNUNET_MysqlStatementHandle *update_value;
188
189};
190
191
192/**
193 * Obtain the location of ".my.cnf".
194 * @return NULL on error
195 */
196static char *
197get_my_cnf_path (const struct GNUNET_CONFIGURATION_Handle *cfg)
198{
199 char *cnffile;
200 char *home_dir;
201 struct stat st;
202#ifndef WINDOWS
203 struct passwd *pw;
204#endif
205 int configured;
206
207#ifndef WINDOWS
208 pw = getpwuid (getuid ());
209 if (!pw)
210 {
211 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
212 "getpwuid");
213 return NULL;
214 }
215 if (GNUNET_YES ==
216 GNUNET_CONFIGURATION_have_value (cfg,
217 "datacache-mysql", "CONFIG"))
218 {
219 GNUNET_assert (GNUNET_OK ==
220 GNUNET_CONFIGURATION_get_value_filename (cfg,
221 "datacache-mysql", "CONFIG", &cnffile));
222 configured = GNUNET_YES;
223 }
224 else
225 {
226 home_dir = GNUNET_strdup (pw->pw_dir);
227#else
228 home_dir = (char *) GNUNET_malloc (_MAX_PATH + 1);
229 plibc_conv_to_win_path ("~/", home_dir);
230#endif
231 GNUNET_asprintf (&cnffile, "%s/.my.cnf", home_dir);
232 GNUNET_free (home_dir);
233 configured = GNUNET_NO;
234 }
235 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
236 _("Trying to use file `%s' for MySQL configuration.\n"),
237 cnffile);
238 if ((0 != STAT (cnffile, &st)) ||
239 (0 != ACCESS (cnffile, R_OK)) || (!S_ISREG (st.st_mode)))
240 {
241 if (configured == GNUNET_YES)
242 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
243 _("Could not access file `%s': %s\n"), cnffile,
244 STRERROR (errno));
245 GNUNET_free (cnffile);
246 return NULL;
247 }
248 return cnffile;
249}
250
251
252/**
253 * Free a prepared statement.
254 */
255static void
256prepared_statement_destroy (struct Plugin *plugin,
257 struct GNUNET_MysqlStatementHandle
258 *s)
259{
260 GNUNET_CONTAINER_DLL_remove (plugin->shead,
261 plugin->stail,
262 s);
263 if (s->valid)
264 mysql_stmt_close (s->statement);
265 GNUNET_free (s->query);
266 GNUNET_free (s);
267}
268
269
270/**
271 * Close database connection and all prepared statements (we got a DB
272 * disconnect error).
273 */
274static int
275iclose (struct Plugin *plugin)
276{
277 struct GNUNET_MysqlStatementHandle *spos;
278
279 spos = plugin->shead;
280 while (NULL != plugin->shead)
281 prepared_statement_destroy (plugin,
282 plugin->shead);
283 if (plugin->dbf != NULL)
284 {
285 mysql_close (plugin->dbf);
286 plugin->dbf = NULL;
287 }
288 return GNUNET_OK;
289}
290
291
292/**
293 * Open the connection with the database (and initialize
294 * our default options).
295 *
296 * @return GNUNET_OK on success
297 */
298static int
299iopen (struct Plugin *ret)
300{
301 char *mysql_dbname;
302 char *mysql_server;
303 char *mysql_user;
304 char *mysql_password;
305 unsigned long long mysql_port;
306 my_bool reconnect;
307 unsigned int timeout;
308
309 ret->dbf = mysql_init (NULL);
310 if (ret->dbf == NULL)
311 return GNUNET_SYSERR;
312 if (ret->cnffile != NULL)
313 mysql_options (ret->dbf, MYSQL_READ_DEFAULT_FILE, ret->cnffile);
314 mysql_options (ret->dbf, MYSQL_READ_DEFAULT_GROUP, "client");
315 reconnect = 0;
316 mysql_options (ret->dbf, MYSQL_OPT_RECONNECT, &reconnect);
317 mysql_options (ret->dbf,
318 MYSQL_OPT_CONNECT_TIMEOUT, (const void *) &timeout);
319 mysql_options(ret->dbf, MYSQL_SET_CHARSET_NAME, "UTF8");
320 timeout = 60; /* in seconds */
321 mysql_options (ret->dbf, MYSQL_OPT_READ_TIMEOUT, (const void *) &timeout);
322 mysql_options (ret->dbf, MYSQL_OPT_WRITE_TIMEOUT, (const void *) &timeout);
323 mysql_dbname = NULL;
324 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (ret->env->cfg,
325 "datacache-mysql", "DATABASE"))
326 GNUNET_assert (GNUNET_OK ==
327 GNUNET_CONFIGURATION_get_value_string (ret->env->cfg,
328 "datacache-mysql", "DATABASE",
329 &mysql_dbname));
330 else
331 mysql_dbname = GNUNET_strdup ("gnunet");
332 mysql_user = NULL;
333 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (ret->env->cfg,
334 "datacache-mysql", "USER"))
335 {
336 GNUNET_assert (GNUNET_OK ==
337 GNUNET_CONFIGURATION_get_value_string (ret->env->cfg,
338 "datacache-mysql", "USER",
339 &mysql_user));
340 }
341 mysql_password = NULL;
342 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (ret->env->cfg,
343 "datacache-mysql", "PASSWORD"))
344 {
345 GNUNET_assert (GNUNET_OK ==
346 GNUNET_CONFIGURATION_get_value_string (ret->env->cfg,
347 "datacache-mysql", "PASSWORD",
348 &mysql_password));
349 }
350 mysql_server = NULL;
351 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (ret->env->cfg,
352 "datacache-mysql", "HOST"))
353 {
354 GNUNET_assert (GNUNET_OK ==
355 GNUNET_CONFIGURATION_get_value_string (ret->env->cfg,
356 "datacache-mysql", "HOST",
357 &mysql_server));
358 }
359 mysql_port = 0;
360 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (ret->env->cfg,
361 "datacache-mysql", "PORT"))
362 {
363 GNUNET_assert (GNUNET_OK ==
364 GNUNET_CONFIGURATION_get_value_number (ret->env->cfg, "datacache-mysql",
365 "PORT", &mysql_port));
366 }
367
368 GNUNET_assert (mysql_dbname != NULL);
369 mysql_real_connect (ret->dbf, mysql_server, mysql_user, mysql_password,
370 mysql_dbname, (unsigned int) mysql_port, NULL,
371 CLIENT_IGNORE_SIGPIPE);
372 GNUNET_free_non_null (mysql_server);
373 GNUNET_free_non_null (mysql_user);
374 GNUNET_free_non_null (mysql_password);
375 GNUNET_free (mysql_dbname);
376 if (mysql_error (ret->dbf)[0])
377 {
378 LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR,
379 "mysql_real_connect", ret);
380 return GNUNET_SYSERR;
381 }
382 return GNUNET_OK;
383}
384
385
386/**
387 * Run the given MySQL statement.
388 *
389 * @return GNUNET_OK on success, GNUNET_SYSERR on error
390 */
391static int
392run_statement (struct Plugin *plugin,
393 const char *statement)
394{
395 if ((NULL == plugin->dbf) && (GNUNET_OK != iopen (plugin)))
396 return GNUNET_SYSERR;
397 mysql_query (plugin->dbf, statement);
398 if (mysql_error (plugin->dbf)[0])
399 {
400 LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR,
401 "mysql_query", plugin);
402 iclose (plugin);
403 return GNUNET_SYSERR;
404 }
405 return GNUNET_OK;
406}
407
408/**
409 * Create a prepared statement.
410 *
411 * @return NULL on error
412 */
413static struct GNUNET_MysqlStatementHandle *
414prepared_statement_create (struct Plugin *plugin,
415 const char *statement)
416{
417 struct GNUNET_MysqlStatementHandle *ret;
418
419 ret = GNUNET_malloc (sizeof (struct GNUNET_MysqlStatementHandle));
420 ret->query = GNUNET_strdup (statement);
421 GNUNET_CONTAINER_DLL_insert (plugin->shead,
422 plugin->stail,
423 ret);
424 return ret;
425}
426
427
428/**
429 * Prepare a statement for running.
430 *
431 * @return GNUNET_OK on success
432 */
433static int
434prepare_statement (struct Plugin *plugin,
435 struct GNUNET_MysqlStatementHandle *ret)
436{
437 if (GNUNET_YES == ret->valid)
438 return GNUNET_OK;
439 if ((NULL == plugin->dbf) &&
440 (GNUNET_OK != iopen (plugin)))
441 return GNUNET_SYSERR;
442 ret->statement = mysql_stmt_init (plugin->dbf);
443 if (ret->statement == NULL)
444 {
445 iclose (plugin);
446 return GNUNET_SYSERR;
447 }
448 if (mysql_stmt_prepare (ret->statement,
449 ret->query,
450 strlen (ret->query)))
451 {
452 LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR,
453 "mysql_stmt_prepare",
454 plugin);
455 mysql_stmt_close (ret->statement);
456 ret->statement = NULL;
457 iclose (plugin);
458 return GNUNET_SYSERR;
459 }
460 ret->valid = GNUNET_YES;
461 return GNUNET_OK;
462
463}
464
465
466/**
467 * Bind the parameters for the given MySQL statement
468 * and run it.
469 *
470 * @param s statement to bind and run
471 * @param ap arguments for the binding
472 * @return GNUNET_SYSERR on error, GNUNET_OK on success
473 */
474static int
475init_params (struct Plugin *plugin,
476 struct GNUNET_MysqlStatementHandle *s,
477 va_list ap)
478{
479 MYSQL_BIND qbind[MAX_PARAM];
480 unsigned int pc;
481 unsigned int off;
482 enum enum_field_types ft;
483
484 pc = mysql_stmt_param_count (s->statement);
485 if (pc > MAX_PARAM)
486 {
487 /* increase internal constant! */
488 GNUNET_break (0);
489 return GNUNET_SYSERR;
490 }
491 memset (qbind, 0, sizeof (qbind));
492 off = 0;
493 ft = 0;
494 while ((pc > 0) && (-1 != (ft = va_arg (ap, enum enum_field_types))))
495 {
496 qbind[off].buffer_type = ft;
497 switch (ft)
498 {
499 case MYSQL_TYPE_FLOAT:
500 qbind[off].buffer = va_arg (ap, float *);
501 break;
502 case MYSQL_TYPE_LONGLONG:
503 qbind[off].buffer = va_arg (ap, unsigned long long *);
504 qbind[off].is_unsigned = va_arg (ap, int);
505 break;
506 case MYSQL_TYPE_LONG:
507 qbind[off].buffer = va_arg (ap, unsigned int *);
508 qbind[off].is_unsigned = va_arg (ap, int);
509 break;
510 case MYSQL_TYPE_VAR_STRING:
511 case MYSQL_TYPE_STRING:
512 case MYSQL_TYPE_BLOB:
513 qbind[off].buffer = va_arg (ap, void *);
514 qbind[off].buffer_length = va_arg (ap, unsigned long);
515 qbind[off].length = va_arg (ap, unsigned long *);
516 break;
517 default:
518 /* unsupported type */
519 GNUNET_break (0);
520 return GNUNET_SYSERR;
521 }
522 pc--;
523 off++;
524 }
525 if (!((pc == 0) && (ft != -1) && (va_arg (ap, int) == -1)))
526 {
527 GNUNET_break (0);
528 return GNUNET_SYSERR;
529 }
530 if (mysql_stmt_bind_param (s->statement, qbind))
531 {
532 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
533 _("`%s' failed at %s:%d with error: %s\n"),
534 "mysql_stmt_bind_param",
535 __FILE__, __LINE__, mysql_stmt_error (s->statement));
536 iclose (plugin);
537 return GNUNET_SYSERR;
538 }
539 if (mysql_stmt_execute (s->statement))
540 {
541 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
542 _("`%s' failed at %s:%d with error: %s\n"),
543 "mysql_stmt_execute",
544 __FILE__, __LINE__, mysql_stmt_error (s->statement));
545 iclose (plugin);
546 return GNUNET_SYSERR;
547 }
548 return GNUNET_OK;
549}
550
551/**
552 * Type of a callback that will be called for each
553 * data set returned from MySQL.
554 *
555 * @param cls user-defined argument
556 * @param num_values number of elements in values
557 * @param values values returned by MySQL
558 * @return GNUNET_OK to continue iterating, GNUNET_SYSERR to abort
559 */
560typedef int (*GNUNET_MysqlDataProcessor) (void *cls,
561 unsigned int num_values,
562 MYSQL_BIND * values);
563
564
565/**
566 * Run a prepared SELECT statement.
567 *
568 * @param result_size number of elements in results array
569 * @param results pointer to already initialized MYSQL_BIND
570 * array (of sufficient size) for passing results
571 * @param processor function to call on each result
572 * @param processor_cls extra argument to processor
573 * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
574 * values (size + buffer-reference for pointers); terminated
575 * with "-1"
576 * @return GNUNET_SYSERR on error, otherwise
577 * the number of successfully affected (or queried) rows
578 */
579static int
580prepared_statement_run_select (struct Plugin *plugin,
581 struct GNUNET_MysqlStatementHandle
582 *s,
583 unsigned int result_size,
584 MYSQL_BIND * results,
585 GNUNET_MysqlDataProcessor
586 processor, void *processor_cls,
587 ...)
588{
589 va_list ap;
590 int ret;
591 unsigned int rsize;
592 int total;
593
594 if (GNUNET_OK != prepare_statement (plugin, s))
595 {
596 GNUNET_break (0);
597 return GNUNET_SYSERR;
598 }
599 va_start (ap, processor_cls);
600 if (GNUNET_OK != init_params (plugin, s, ap))
601 {
602 GNUNET_break (0);
603 va_end (ap);
604 return GNUNET_SYSERR;
605 }
606 va_end (ap);
607 rsize = mysql_stmt_field_count (s->statement);
608 if (rsize > result_size)
609 {
610 GNUNET_break (0);
611 return GNUNET_SYSERR;
612 }
613 if (mysql_stmt_bind_result (s->statement, results))
614 {
615 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
616 _("`%s' failed at %s:%d with error: %s\n"),
617 "mysql_stmt_bind_result",
618 __FILE__, __LINE__, mysql_stmt_error (s->statement));
619 iclose (plugin);
620 return GNUNET_SYSERR;
621 }
622
623 total = 0;
624 while (1)
625 {
626 ret = mysql_stmt_fetch (s->statement);
627 if (ret == MYSQL_NO_DATA)
628 break;
629 if (ret != 0)
630 {
631 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
632 _("`%s' failed at %s:%d with error: %s\n"),
633 "mysql_stmt_fetch",
634 __FILE__, __LINE__, mysql_stmt_error (s->statement));
635 iclose (plugin);
636 return GNUNET_SYSERR;
637 }
638 if (processor != NULL)
639 if (GNUNET_OK != processor (processor_cls, rsize, results))
640 break;
641 total++;
642 }
643 mysql_stmt_reset (s->statement);
644 return total;
645}
646
647
648
649/**
650 * Run a prepared statement that does NOT produce results.
651 *
652 * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
653 * values (size + buffer-reference for pointers); terminated
654 * with "-1"
655 * @param insert_id NULL or address where to store the row ID of whatever
656 * was inserted (only for INSERT statements!)
657 * @return GNUNET_SYSERR on error, otherwise
658 * the number of successfully affected rows
659 */
660static int
661prepared_statement_run (struct Plugin *plugin,
662 struct GNUNET_MysqlStatementHandle *s,
663 unsigned long long *insert_id, ...)
664{
665 va_list ap;
666 int affected;
667
668 if (GNUNET_OK != prepare_statement (plugin, s))
669 return GNUNET_SYSERR;
670 va_start (ap, insert_id);
671 if (GNUNET_OK != init_params (plugin, s, ap))
672 {
673 va_end (ap);
674 return GNUNET_SYSERR;
675 }
676 va_end (ap);
677 affected = mysql_stmt_affected_rows (s->statement);
678 if (NULL != insert_id)
679 *insert_id = (unsigned long long) mysql_stmt_insert_id (s->statement);
680 mysql_stmt_reset (s->statement);
681 return affected;
682}
683
684
685static int
686itable (struct Plugin *plugin)
687{
688#define MRUNS(a) (GNUNET_OK != run_statement (plugin, a) )
689 if (MRUNS ("CREATE TEMPORARY TABLE gn080dstore ("
690 " type INT(11) UNSIGNED NOT NULL DEFAULT 0,"
691 " puttime BIGINT UNSIGNED NOT NULL DEFAULT 0,"
692 " expire BIGINT UNSIGNED NOT NULL DEFAULT 0,"
693 " hash BINARY(64) NOT NULL DEFAULT '',"
694 " vhash BINARY(64) NOT NULL DEFAULT '',"
695 " value BLOB NOT NULL DEFAULT '',"
696 " INDEX hashidx (hash(64),type,expire),"
697 " INDEX allidx (hash(64),vhash(64),type),"
698 " INDEX expireidx (puttime)" ") ENGINE=InnoDB") ||
699 MRUNS ("SET AUTOCOMMIT = 1"))
700 return GNUNET_SYSERR;
701#undef MRUNS
702#define PINIT(a,b) (NULL == (a = prepared_statement_create(plugin, b)))
703 if (PINIT (plugin->select_value, SELECT_VALUE_STMT) ||
704 PINIT (plugin->count_value, COUNT_VALUE_STMT) ||
705 PINIT (plugin->select_old_value, SELECT_OLD_VALUE_STMT) ||
706 PINIT (plugin->delete_value, DELETE_VALUE_STMT) ||
707 PINIT (plugin->insert_value, INSERT_VALUE_STMT) ||
708 PINIT (plugin->update_value, UPDATE_VALUE_STMT))
709 return GNUNET_SYSERR;
710#undef PINIT
711 return GNUNET_OK;
712}
713
714
715/**
716 * Store an item in the datastore.
717 *
718 * @param cls closure (our "struct Plugin")
719 * @param key key to store data under
720 * @param size number of bytes in data
721 * @param data data to store
722 * @param type type of the value
723 * @param discard_time when to discard the value in any case
724 * @return 0 on error, number of bytes used otherwise
725 */
726static uint32_t
727mysql_plugin_put (void *cls,
728 const GNUNET_HashCode * key,
729 uint32_t size,
730 const char *data,
731 enum GNUNET_BLOCK_Type type,
732 struct GNUNET_TIME_Absolute discard_time)
733{
734 struct Plugin *plugin = cls;
735 struct GNUNET_TIME_Absolute now;
736 unsigned long k_length;
737 unsigned long h_length;
738 unsigned long v_length;
739 unsigned long long v_now;
740 unsigned long long v_discard_time;
741 unsigned int v_type;
742 GNUNET_HashCode vhash;
743 int ret;
744
745 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
746 return GNUNET_SYSERR;
747 GNUNET_CRYPTO_hash (data, size, &vhash);
748 now = GNUNET_TIME_absolute_get ();
749
750 /* first try UPDATE */
751 h_length = sizeof (GNUNET_HashCode);
752 k_length = sizeof (GNUNET_HashCode);
753 v_length = size;
754 v_type = type;
755 v_now = (unsigned long long) now.value;
756 v_discard_time = (unsigned long long) discard_time.value;
757 if (GNUNET_OK ==
758 prepared_statement_run (plugin,
759 plugin->update_value,
760 NULL,
761 MYSQL_TYPE_LONGLONG,
762 &v_now,
763 GNUNET_YES,
764 MYSQL_TYPE_LONGLONG,
765 &v_discard_time,
766 GNUNET_YES,
767 MYSQL_TYPE_BLOB,
768 key,
769 sizeof (GNUNET_HashCode),
770 &k_length,
771 MYSQL_TYPE_BLOB,
772 &vhash,
773 sizeof (GNUNET_HashCode),
774 &h_length,
775 MYSQL_TYPE_LONG,
776 &v_type,
777 GNUNET_YES, -1))
778 return GNUNET_OK;
779
780 /* now try INSERT */
781 h_length = sizeof (GNUNET_HashCode);
782 k_length = sizeof (GNUNET_HashCode);
783 v_length = size;
784 if (GNUNET_OK !=
785 (ret = prepared_statement_run (plugin,
786 plugin->insert_value,
787 NULL,
788 MYSQL_TYPE_LONG,
789 &type,
790 GNUNET_YES,
791 MYSQL_TYPE_LONGLONG,
792 &v_now,
793 GNUNET_YES,
794 MYSQL_TYPE_LONGLONG,
795 &v_discard_time,
796 GNUNET_YES,
797 MYSQL_TYPE_BLOB,
798 key,
799 sizeof (GNUNET_HashCode),
800 &k_length,
801 MYSQL_TYPE_BLOB,
802 &vhash,
803 sizeof (GNUNET_HashCode),
804 &h_length,
805 MYSQL_TYPE_BLOB,
806 data,
807 (unsigned long) size,
808 &v_length, -1)))
809 {
810 if (ret == GNUNET_SYSERR)
811 itable (plugin);
812 return GNUNET_SYSERR;
813 }
814 return size + OVERHEAD;
815}
816
817
818static int
819return_ok (void *cls, unsigned int num_values, MYSQL_BIND * values)
820{
821 return GNUNET_OK;
822}
823
824
825/**
826 * Iterate over the results for a particular key
827 * in the datastore.
828 *
829 * @param cls closure (our "struct Plugin")
830 * @param key
831 * @param type entries of which type are relevant?
832 * @param iter maybe NULL (to just count)
833 * @param iter_cls closure for iter
834 * @return the number of results found
835 */
836static unsigned int
837mysql_plugin_get (void *cls,
838 const GNUNET_HashCode * key,
839 enum GNUNET_BLOCK_Type type,
840 GNUNET_DATACACHE_Iterator iter,
841 void *iter_cls)
842{
843 struct Plugin *plugin = cls;
844 MYSQL_BIND rbind[3];
845 unsigned long h_length;
846 unsigned long v_length;
847 unsigned long long v_expire;
848 struct GNUNET_TIME_Absolute now;
849 struct GNUNET_TIME_Absolute expire;
850 unsigned int cnt;
851 unsigned long long total;
852 unsigned long long v_now;
853 unsigned int off;
854 unsigned int v_type;
855 int ret;
856 char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
857
858 now = GNUNET_TIME_absolute_get ();
859 h_length = sizeof (GNUNET_HashCode);
860 v_length = sizeof (buffer);
861 total = -1;
862 memset (rbind, 0, sizeof (rbind));
863 rbind[0].buffer_type = MYSQL_TYPE_LONGLONG;
864 rbind[0].buffer = &total;
865 rbind[0].is_unsigned = GNUNET_YES;
866 v_type = type;
867 v_now = (unsigned long long) now.value;
868 if ((GNUNET_OK !=
869 (ret = prepared_statement_run_select (plugin,
870 plugin->count_value,
871 1,
872 rbind,
873 return_ok,
874 NULL,
875 MYSQL_TYPE_BLOB,
876 key,
877 sizeof
878 (GNUNET_HashCode),
879 &h_length,
880 MYSQL_TYPE_LONG,
881 &v_type, GNUNET_YES,
882 MYSQL_TYPE_LONGLONG,
883 &v_now, GNUNET_YES,
884 -1)))
885 || (-1 == total))
886 {
887 if (ret == GNUNET_SYSERR)
888 itable (plugin);
889 return GNUNET_SYSERR;
890 }
891 if ((iter == NULL) || (total == 0))
892 return (int) total;
893
894 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total);
895 cnt = 0;
896 while (cnt < total)
897 {
898 memset (rbind, 0, sizeof (rbind));
899 rbind[0].buffer_type = MYSQL_TYPE_BLOB;
900 rbind[0].buffer_length = sizeof (buffer);
901 rbind[0].length = &v_length;
902 rbind[0].buffer = buffer;
903 rbind[1].buffer_type = MYSQL_TYPE_LONGLONG;
904 rbind[1].is_unsigned = 1;
905 rbind[1].buffer = &v_expire;
906 off = (off + 1) % total;
907 if (GNUNET_OK !=
908 (ret = prepared_statement_run_select (plugin,
909 plugin->select_value,
910 2,
911 rbind,
912 return_ok,
913 NULL,
914 MYSQL_TYPE_BLOB,
915 key,
916 sizeof
917 (GNUNET_HashCode),
918 &h_length,
919 MYSQL_TYPE_LONG,
920 &v_type,
921 GNUNET_YES,
922 MYSQL_TYPE_LONGLONG,
923 &v_now,
924 GNUNET_YES,
925 MYSQL_TYPE_LONG,
926 &off,
927 GNUNET_YES,
928 -1)))
929 {
930 if (ret == GNUNET_SYSERR)
931 itable (plugin);
932 return GNUNET_SYSERR;
933 }
934 cnt++;
935 expire.value = v_expire;
936 if (GNUNET_OK != iter (iter_cls,
937 expire,
938 key,
939 v_length, buffer,
940 type))
941 break;
942 }
943 return cnt;
944}
945
946
947/**
948 * Delete the entry with the lowest expiration value
949 * from the datacache right now.
950 *
951 * @param cls closure (our "struct Plugin")
952 * @return GNUNET_OK on success, GNUNET_SYSERR on error
953 */
954static int
955mysql_plugin_del (void *cls)
956{
957 struct Plugin *plugin = cls;
958
959 MYSQL_BIND rbind[5];
960 unsigned int v_type;
961 GNUNET_HashCode v_key;
962 GNUNET_HashCode vhash;
963 unsigned long k_length;
964 unsigned long h_length;
965 unsigned long v_length;
966 int ret;
967 char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
968
969 k_length = sizeof (GNUNET_HashCode);
970 h_length = sizeof (GNUNET_HashCode);
971 v_length = sizeof (buffer);
972 memset (rbind, 0, sizeof (rbind));
973 rbind[0].buffer_type = MYSQL_TYPE_BLOB;
974 rbind[0].buffer_length = sizeof (GNUNET_HashCode);
975 rbind[0].length = &k_length;
976 rbind[0].buffer = &v_key;
977 rbind[1].buffer_type = MYSQL_TYPE_BLOB;
978 rbind[1].buffer_length = sizeof (GNUNET_HashCode);
979 rbind[1].length = &h_length;
980 rbind[1].buffer = &vhash;
981 rbind[2].buffer_type = MYSQL_TYPE_LONG;
982 rbind[2].is_unsigned = 1;
983 rbind[2].buffer = &v_type;
984 rbind[3].buffer_type = MYSQL_TYPE_BLOB;
985 rbind[3].buffer_length = sizeof (buffer);
986 rbind[3].length = &v_length;
987 rbind[3].buffer = buffer;
988 if ((GNUNET_OK !=
989 (ret = prepared_statement_run_select (plugin,
990 plugin->select_old_value,
991 4,
992 rbind,
993 return_ok,
994 NULL,
995 -1))) ||
996 (GNUNET_OK !=
997 (ret = prepared_statement_run (plugin,
998 plugin->delete_value,
999 NULL,
1000 MYSQL_TYPE_BLOB,
1001 &v_key,
1002 sizeof (GNUNET_HashCode),
1003 &k_length,
1004 MYSQL_TYPE_BLOB,
1005 &vhash,
1006 sizeof (GNUNET_HashCode),
1007 &h_length,
1008 MYSQL_TYPE_LONG,
1009 &v_type,
1010 GNUNET_YES,
1011 MYSQL_TYPE_BLOB,
1012 buffer,
1013 (unsigned long)
1014 sizeof (buffer),
1015 &v_length, -1))))
1016 {
1017 if (ret == GNUNET_SYSERR)
1018 itable (plugin);
1019 return GNUNET_SYSERR;
1020 }
1021 plugin->env->delete_notify (plugin->env->cls,
1022 &v_key,
1023 v_length + OVERHEAD);
1024
1025 return GNUNET_OK;
1026}
1027
1028
1029/**
1030 * Entry point for the plugin.
1031 *
1032 * @param cls closure (the "struct GNUNET_DATACACHE_PluginEnvironmnet")
1033 * @return the plugin's closure (our "struct Plugin")
1034 */
1035void *
1036libgnunet_plugin_datacache_mysql_init (void *cls)
1037{
1038 struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
1039 struct GNUNET_DATACACHE_PluginFunctions *api;
1040 struct Plugin *plugin;
1041
1042 plugin = GNUNET_malloc (sizeof (struct Plugin));
1043 plugin->env = env;
1044 plugin->cnffile = get_my_cnf_path (env->cfg);
1045 if (GNUNET_OK !=
1046 iopen (plugin))
1047 {
1048 GNUNET_free_non_null (plugin->cnffile);
1049 GNUNET_free (plugin);
1050 return NULL;
1051 }
1052 if (GNUNET_OK !=
1053 itable (plugin))
1054 {
1055 iclose (plugin);
1056 GNUNET_free_non_null (plugin->cnffile);
1057 GNUNET_free (plugin);
1058 return NULL;
1059 }
1060 api = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_PluginFunctions));
1061 api->cls = plugin;
1062 api->get = &mysql_plugin_get;
1063 api->put = &mysql_plugin_put;
1064 api->del = &mysql_plugin_del;
1065 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
1066 "mysql", _("MySQL datacache running\n"));
1067 return api;
1068}
1069
1070
1071/**
1072 * Exit point from the plugin.
1073 *
1074 * @param cls closure (our "struct Plugin")
1075 * @return NULL
1076 */
1077void *
1078libgnunet_plugin_datacache_mysql_done (void *cls)
1079{
1080 struct GNUNET_DATACACHE_PluginFunctions *api = cls;
1081 struct Plugin *plugin = api->cls;
1082
1083 iclose (plugin);
1084 GNUNET_free_non_null (plugin->cnffile);
1085 GNUNET_free (plugin);
1086 GNUNET_free (api);
1087 mysql_library_end ();
1088 return NULL;
1089}
1090
1091
1092/* end of plugin_datacache_mysql.c */
diff --git a/src/datacache/test_datacache.c b/src/datacache/test_datacache.c
index 8e09a7692..c5acf365a 100644
--- a/src/datacache/test_datacache.c
+++ b/src/datacache/test_datacache.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2006, 2009 Christian Grothoff (and other contributing authors) 3 (C) 2006, 2009, 2010 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -32,6 +32,11 @@
32 32
33static int ok; 33static int ok;
34 34
35/**
36 * Name of plugin under test.
37 */
38static const char *plugin_name;
39
35 40
36static int 41static int
37checkIt (void *cls, 42checkIt (void *cls,
@@ -120,12 +125,15 @@ FAILURE:
120} 125}
121 126
122 127
123static int 128int
124check () 129main (int argc, char *argv[])
125{ 130{
126 char *const argv[] = { "test-datacache-api", 131 const char *pos;
132 char cfg_name[128];
133 char *const xargv[] = {
134 "test-datacache",
127 "-c", 135 "-c",
128 "test_datacache_data.conf", 136 cfg_name,
129#if VERBOSE 137#if VERBOSE
130 "-L", "DEBUG", 138 "-L", "DEBUG",
131#endif 139#endif
@@ -134,30 +142,28 @@ check ()
134 struct GNUNET_GETOPT_CommandLineOption options[] = { 142 struct GNUNET_GETOPT_CommandLineOption options[] = {
135 GNUNET_GETOPT_OPTION_END 143 GNUNET_GETOPT_OPTION_END
136 }; 144 };
137 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
138 argv, "test-datacache-api", "nohelp",
139 options, &run, NULL);
140 if (ok != 0)
141 fprintf (stderr, "Missed some testcases: %d\n", ok);
142 return ok;
143}
144 145
145 146 GNUNET_log_setup ("test-datacache",
146int
147main (int argc, char *argv[])
148{
149 int ret;
150
151 GNUNET_log_setup ("test-datacache-api",
152#if VERBOSE 147#if VERBOSE
153 "DEBUG", 148 "DEBUG",
154#else 149#else
155 "WARNING", 150 "WARNING",
156#endif 151#endif
157 NULL); 152 NULL);
158 ret = check (); 153 /* determine name of plugin to use */
159 154 plugin_name = argv[0];
160 return ret; 155 while (NULL != (pos = strstr(plugin_name, "_")))
156 plugin_name = pos+1;
157 GNUNET_snprintf (cfg_name,
158 sizeof (cfg_name),
159 "test_datacache_data_%s.conf",
160 plugin_name);
161 GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1,
162 xargv, "test-datacache", "nohelp",
163 options, &run, NULL);
164 if (ok != 0)
165 fprintf (stderr, "Missed some testcases: %d\n", ok);
166 return ok;
161} 167}
162 168
163/* end of test_datacache.c */ 169/* end of test_datacache.c */
diff --git a/src/datacache/test_datacache_data_mysql.conf b/src/datacache/test_datacache_data_mysql.conf
new file mode 100644
index 000000000..3086497df
--- /dev/null
+++ b/src/datacache/test_datacache_data_mysql.conf
@@ -0,0 +1,12 @@
1
2[testcache]
3QUOTA = 1000000
4DATABASE = mysql
5
6[datacache-mysql]
7DATABASE = gnunetcheck
8# CONFIG = ~/.my.cnf
9# USER =
10# PASSWORD =
11# HOST =
12# PORT = \ No newline at end of file
diff --git a/src/datacache/test_datacache_data.conf b/src/datacache/test_datacache_data_sqlite.conf
index 2e8606682..2e8606682 100644
--- a/src/datacache/test_datacache_data.conf
+++ b/src/datacache/test_datacache_data_sqlite.conf
diff --git a/src/datacache/test_datacache_quota.c b/src/datacache/test_datacache_quota.c
index f4686b6a3..9028196bd 100644
--- a/src/datacache/test_datacache_quota.c
+++ b/src/datacache/test_datacache_quota.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2006, 2009 Christian Grothoff (and other contributing authors) 3 (C) 2006, 2009, 2010 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -33,6 +33,11 @@
33static int ok; 33static int ok;
34 34
35/** 35/**
36 * Name of plugin under test.
37 */
38static const char *plugin_name;
39
40/**
36 * Quota is 1 MB. Each iteration of the test puts in about 1 MB of 41 * Quota is 1 MB. Each iteration of the test puts in about 1 MB of
37 * data. We do 10 iterations. Afterwards we check that the data from 42 * data. We do 10 iterations. Afterwards we check that the data from
38 * the first 5 iterations has all been discarded and that at least 43 * the first 5 iterations has all been discarded and that at least
@@ -110,12 +115,15 @@ FAILURE:
110} 115}
111 116
112 117
113static int 118int
114check () 119main (int argc, char *argv[])
115{ 120{
116 char *const argv[] = { "test-datacache-quota", 121 const char *pos;
122 char cfg_name[128];
123 char *const xargv[] = {
124 "test-datacache-quota",
117 "-c", 125 "-c",
118 "test_datacache_data.conf", 126 cfg_name,
119#if VERBOSE 127#if VERBOSE
120 "-L", "DEBUG", 128 "-L", "DEBUG",
121#endif 129#endif
@@ -124,20 +132,7 @@ check ()
124 struct GNUNET_GETOPT_CommandLineOption options[] = { 132 struct GNUNET_GETOPT_CommandLineOption options[] = {
125 GNUNET_GETOPT_OPTION_END 133 GNUNET_GETOPT_OPTION_END
126 }; 134 };
127 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, 135
128 argv, "test-datacache-quota", "nohelp",
129 options, &run, NULL);
130 if (ok != 0)
131 fprintf (stderr, "Missed some testcases: %d\n", ok);
132 return ok;
133}
134
135
136int
137main (int argc, char *argv[])
138{
139 int ret;
140
141 GNUNET_log_setup ("test-datacache-quota", 136 GNUNET_log_setup ("test-datacache-quota",
142#if VERBOSE 137#if VERBOSE
143 "DEBUG", 138 "DEBUG",
@@ -145,9 +140,20 @@ main (int argc, char *argv[])
145 "WARNING", 140 "WARNING",
146#endif 141#endif
147 NULL); 142 NULL);
148 ret = check (); 143 /* determine name of plugin to use */
149 144 plugin_name = argv[0];
150 return ret; 145 while (NULL != (pos = strstr(plugin_name, "_")))
146 plugin_name = pos+1;
147 GNUNET_snprintf (cfg_name,
148 sizeof (cfg_name),
149 "test_datacache_data_%s.conf",
150 plugin_name);
151 GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1,
152 xargv, "test-datacache-quota", "nohelp",
153 options, &run, NULL);
154 if (ok != 0)
155 fprintf (stderr, "Missed some testcases: %d\n", ok);
156 return ok;
151} 157}
152 158
153/* end of test_datacache_quota.c */ 159/* end of test_datacache_quota.c */