2 This file is part of GNUnet
3 (C) 2006, 2009, 2010 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file datacache/plugin_datacache_mysql.c
23 * @brief mysql for an implementation of a database backend for the datacache
24 * @author Christian Grothoff
28 * 1) Access mysql as root,
34 * and do the following. [You should replace $USER with the username
35 * that will be running the gnunetd process].
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');
45 * 2) In the $HOME directory of $USER, create a ".my.cnf" file
46 * with the following lines
51 password=$the_password_you_like
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,
63 * 3) Still, perhaps you should briefly try if the DB connection
64 * works. First, login as $USER. Then use,
67 * $ mysql -u $USER -p $the_password_you_like
71 * If you get the message "Database changed" it probably works.
73 * [If you get "ERROR 2002: Can't connect to local MySQL server
74 * through socket '/tmp/mysql.sock' (2)" it may be resolvable by
75 * "ln -s /var/run/mysqld/mysqld.sock /tmp/mysql.sock"
76 * so there may be some additional trouble depending on your mysql setup.]
79 * - Its probably healthy to check your tables for inconsistencies
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):
87 * mysql> REPAIR TABLE gnXXX;
89 * Make sure to replace XXX with the actual names of all tables.
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.
99 #include "gnunet_util_lib.h"
100 #include "plugin_datacache.h"
101 #include <mysql/mysql.h>
103 #define DEBUG_DATACACHE_MYSQL GNUNET_NO
106 * Estimate of the per-entry overhead (including indices).
108 #define OVERHEAD ((4*2+4*2+8*2+8*2+sizeof(GNUNET_HashCode)*5+8))
111 * Maximum number of supported parameters for a prepared
112 * statement. Increase if needed.
117 * Die with an error message that indicates
118 * a failure of the command 'cmd' with the message given
119 * by strerror(errno).
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);
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).
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);
130 struct GNUNET_MysqlStatementHandle
132 struct GNUNET_MysqlStatementHandle *next;
134 struct GNUNET_MysqlStatementHandle *prev;
138 MYSQL_STMT *statement;
146 * Context for all functions in this plugin.
151 * Our execution environment.
153 struct GNUNET_DATACACHE_PluginEnvironment *env;
156 * Handle to the mysql database.
160 struct GNUNET_MysqlStatementHandle *shead;
162 struct GNUNET_MysqlStatementHandle *stail;
165 * Filename of "my.cnf" (msyql configuration).
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;
172 #define COUNT_VALUE_STMT "SELECT count(*) FROM gn080dstore FORCE INDEX (hashidx) WHERE hash=? AND type=? AND expire >= ?"
173 struct GNUNET_MysqlStatementHandle *count_value;
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;
178 #define DELETE_VALUE_STMT "DELETE FROM gn080dstore WHERE hash = ? AND vhash = ? AND type = ? AND value = ?"
179 struct GNUNET_MysqlStatementHandle *delete_value;
181 #define INSERT_VALUE_STMT "INSERT INTO gn080dstore (type, puttime, expire, hash, vhash, value) "\
182 "VALUES (?, ?, ?, ?, ?, ?)"
183 struct GNUNET_MysqlStatementHandle *insert_value;
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;
193 * Obtain the location of ".my.cnf".
194 * @return NULL on error
197 get_my_cnf_path (const struct GNUNET_CONFIGURATION_Handle *cfg)
208 pw = getpwuid (getuid ());
211 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
216 GNUNET_CONFIGURATION_have_value (cfg,
217 "datacache-mysql", "CONFIG"))
219 GNUNET_assert (GNUNET_OK ==
220 GNUNET_CONFIGURATION_get_value_filename (cfg,
221 "datacache-mysql", "CONFIG", &cnffile));
222 configured = GNUNET_YES;
226 home_dir = GNUNET_strdup (pw->pw_dir);
228 home_dir = (char *) GNUNET_malloc (_MAX_PATH + 1);
229 plibc_conv_to_win_path ("~/", home_dir);
231 GNUNET_asprintf (&cnffile, "%s/.my.cnf", home_dir);
232 GNUNET_free (home_dir);
233 configured = GNUNET_NO;
235 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
236 _("Trying to use file `%s' for MySQL configuration.\n"),
238 if ((0 != STAT (cnffile, &st)) ||
239 (0 != ACCESS (cnffile, R_OK)) || (!S_ISREG (st.st_mode)))
241 if (configured == GNUNET_YES)
242 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
243 _("Could not access file `%s': %s\n"), cnffile,
245 GNUNET_free (cnffile);
253 * Free a prepared statement.
256 prepared_statement_destroy (struct Plugin *plugin,
257 struct GNUNET_MysqlStatementHandle
260 GNUNET_CONTAINER_DLL_remove (plugin->shead,
264 mysql_stmt_close (s->statement);
265 GNUNET_free (s->query);
271 * Close database connection and all prepared statements (we got a DB
275 iclose (struct Plugin *plugin)
277 struct GNUNET_MysqlStatementHandle *spos;
279 spos = plugin->shead;
280 while (NULL != plugin->shead)
281 prepared_statement_destroy (plugin,
283 if (plugin->dbf != NULL)
285 mysql_close (plugin->dbf);
293 * Open the connection with the database (and initialize
294 * our default options).
296 * @return GNUNET_OK on success
299 iopen (struct Plugin *ret)
304 char *mysql_password;
305 unsigned long long mysql_port;
307 unsigned int timeout;
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");
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);
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",
331 mysql_dbname = GNUNET_strdup ("gnunet");
333 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (ret->env->cfg,
334 "datacache-mysql", "USER"))
336 GNUNET_assert (GNUNET_OK ==
337 GNUNET_CONFIGURATION_get_value_string (ret->env->cfg,
338 "datacache-mysql", "USER",
341 mysql_password = NULL;
342 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (ret->env->cfg,
343 "datacache-mysql", "PASSWORD"))
345 GNUNET_assert (GNUNET_OK ==
346 GNUNET_CONFIGURATION_get_value_string (ret->env->cfg,
347 "datacache-mysql", "PASSWORD",
351 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (ret->env->cfg,
352 "datacache-mysql", "HOST"))
354 GNUNET_assert (GNUNET_OK ==
355 GNUNET_CONFIGURATION_get_value_string (ret->env->cfg,
356 "datacache-mysql", "HOST",
360 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (ret->env->cfg,
361 "datacache-mysql", "PORT"))
363 GNUNET_assert (GNUNET_OK ==
364 GNUNET_CONFIGURATION_get_value_number (ret->env->cfg, "datacache-mysql",
365 "PORT", &mysql_port));
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])
378 LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR,
379 "mysql_real_connect", ret);
380 return GNUNET_SYSERR;
387 * Run the given MySQL statement.
389 * @return GNUNET_OK on success, GNUNET_SYSERR on error
392 run_statement (struct Plugin *plugin,
393 const char *statement)
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])
400 LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR,
401 "mysql_query", plugin);
403 return GNUNET_SYSERR;
409 * Create a prepared statement.
411 * @return NULL on error
413 static struct GNUNET_MysqlStatementHandle *
414 prepared_statement_create (struct Plugin *plugin,
415 const char *statement)
417 struct GNUNET_MysqlStatementHandle *ret;
419 ret = GNUNET_malloc (sizeof (struct GNUNET_MysqlStatementHandle));
420 ret->query = GNUNET_strdup (statement);
421 GNUNET_CONTAINER_DLL_insert (plugin->shead,
429 * Prepare a statement for running.
431 * @return GNUNET_OK on success
434 prepare_statement (struct Plugin *plugin,
435 struct GNUNET_MysqlStatementHandle *ret)
437 if (GNUNET_YES == ret->valid)
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)
446 return GNUNET_SYSERR;
448 if (mysql_stmt_prepare (ret->statement,
450 strlen (ret->query)))
452 LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR,
453 "mysql_stmt_prepare",
455 mysql_stmt_close (ret->statement);
456 ret->statement = NULL;
458 return GNUNET_SYSERR;
460 ret->valid = GNUNET_YES;
467 * Bind the parameters for the given MySQL statement
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
475 init_params (struct Plugin *plugin,
476 struct GNUNET_MysqlStatementHandle *s,
479 MYSQL_BIND qbind[MAX_PARAM];
482 enum enum_field_types ft;
484 pc = mysql_stmt_param_count (s->statement);
487 /* increase internal constant! */
489 return GNUNET_SYSERR;
491 memset (qbind, 0, sizeof (qbind));
494 while ((pc > 0) && (-1 != (ft = va_arg (ap, enum enum_field_types))))
496 qbind[off].buffer_type = ft;
499 case MYSQL_TYPE_FLOAT:
500 qbind[off].buffer = va_arg (ap, float *);
502 case MYSQL_TYPE_LONGLONG:
503 qbind[off].buffer = va_arg (ap, unsigned long long *);
504 qbind[off].is_unsigned = va_arg (ap, int);
506 case MYSQL_TYPE_LONG:
507 qbind[off].buffer = va_arg (ap, unsigned int *);
508 qbind[off].is_unsigned = va_arg (ap, int);
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 *);
518 /* unsupported type */
520 return GNUNET_SYSERR;
525 if (!((pc == 0) && (ft != -1) && (va_arg (ap, int) == -1)))
528 return GNUNET_SYSERR;
530 if (mysql_stmt_bind_param (s->statement, qbind))
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));
537 return GNUNET_SYSERR;
539 if (mysql_stmt_execute (s->statement))
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));
546 return GNUNET_SYSERR;
552 * Type of a callback that will be called for each
553 * data set returned from MySQL.
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
560 typedef int (*GNUNET_MysqlDataProcessor) (void *cls,
561 unsigned int num_values,
562 MYSQL_BIND * values);
566 * Run a prepared SELECT statement.
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
576 * @return GNUNET_SYSERR on error, otherwise
577 * the number of successfully affected (or queried) rows
580 prepared_statement_run_select (struct Plugin *plugin,
581 struct GNUNET_MysqlStatementHandle
583 unsigned int result_size,
584 MYSQL_BIND * results,
585 GNUNET_MysqlDataProcessor
586 processor, void *processor_cls,
594 if (GNUNET_OK != prepare_statement (plugin, s))
597 return GNUNET_SYSERR;
599 va_start (ap, processor_cls);
600 if (GNUNET_OK != init_params (plugin, s, ap))
604 return GNUNET_SYSERR;
607 rsize = mysql_stmt_field_count (s->statement);
608 if (rsize > result_size)
611 return GNUNET_SYSERR;
613 if (mysql_stmt_bind_result (s->statement, results))
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));
620 return GNUNET_SYSERR;
626 ret = mysql_stmt_fetch (s->statement);
627 if (ret == MYSQL_NO_DATA)
631 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
632 _("`%s' failed at %s:%d with error: %s\n"),
634 __FILE__, __LINE__, mysql_stmt_error (s->statement));
636 return GNUNET_SYSERR;
638 if (processor != NULL)
639 if (GNUNET_OK != processor (processor_cls, rsize, results))
643 mysql_stmt_reset (s->statement);
650 * Run a prepared statement that does NOT produce results.
652 * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
653 * values (size + buffer-reference for pointers); terminated
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
661 prepared_statement_run (struct Plugin *plugin,
662 struct GNUNET_MysqlStatementHandle *s,
663 unsigned long long *insert_id, ...)
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))
674 return GNUNET_SYSERR;
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);
686 itable (struct Plugin *plugin)
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;
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;
716 * Store an item in the datastore.
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
727 mysql_plugin_put (void *cls,
728 const GNUNET_HashCode * key,
731 enum GNUNET_BLOCK_Type type,
732 struct GNUNET_TIME_Absolute discard_time)
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;
742 GNUNET_HashCode vhash;
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 ();
750 /* first try UPDATE */
751 h_length = sizeof (GNUNET_HashCode);
752 k_length = sizeof (GNUNET_HashCode);
755 v_now = (unsigned long long) now.value;
756 v_discard_time = (unsigned long long) discard_time.value;
758 prepared_statement_run (plugin,
759 plugin->update_value,
769 sizeof (GNUNET_HashCode),
773 sizeof (GNUNET_HashCode),
781 h_length = sizeof (GNUNET_HashCode);
782 k_length = sizeof (GNUNET_HashCode);
785 (ret = prepared_statement_run (plugin,
786 plugin->insert_value,
799 sizeof (GNUNET_HashCode),
803 sizeof (GNUNET_HashCode),
807 (unsigned long) size,
810 if (ret == GNUNET_SYSERR)
812 return GNUNET_SYSERR;
814 return size + OVERHEAD;
819 return_ok (void *cls, unsigned int num_values, MYSQL_BIND * values)
826 * Iterate over the results for a particular key
829 * @param cls closure (our "struct Plugin")
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
837 mysql_plugin_get (void *cls,
838 const GNUNET_HashCode * key,
839 enum GNUNET_BLOCK_Type type,
840 GNUNET_DATACACHE_Iterator iter,
843 struct Plugin *plugin = cls;
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;
851 unsigned long long total;
852 unsigned long long v_now;
856 char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
858 now = GNUNET_TIME_absolute_get ();
859 h_length = sizeof (GNUNET_HashCode);
860 v_length = sizeof (buffer);
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;
867 v_now = (unsigned long long) now.value;
869 (ret = prepared_statement_run_select (plugin,
887 if (ret == GNUNET_SYSERR)
889 return GNUNET_SYSERR;
891 if ((iter == NULL) || (total == 0))
894 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total);
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;
908 (ret = prepared_statement_run_select (plugin,
909 plugin->select_value,
930 if (ret == GNUNET_SYSERR)
932 return GNUNET_SYSERR;
935 expire.value = v_expire;
936 if (GNUNET_OK != iter (iter_cls,
948 * Delete the entry with the lowest expiration value
949 * from the datacache right now.
951 * @param cls closure (our "struct Plugin")
952 * @return GNUNET_OK on success, GNUNET_SYSERR on error
955 mysql_plugin_del (void *cls)
957 struct Plugin *plugin = cls;
961 GNUNET_HashCode v_key;
962 GNUNET_HashCode vhash;
963 unsigned long k_length;
964 unsigned long h_length;
965 unsigned long v_length;
967 char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
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;
989 (ret = prepared_statement_run_select (plugin,
990 plugin->select_old_value,
997 (ret = prepared_statement_run (plugin,
998 plugin->delete_value,
1002 sizeof (GNUNET_HashCode),
1006 sizeof (GNUNET_HashCode),
1017 if (ret == GNUNET_SYSERR)
1019 return GNUNET_SYSERR;
1021 plugin->env->delete_notify (plugin->env->cls,
1023 v_length + OVERHEAD);
1030 * Entry point for the plugin.
1032 * @param cls closure (the "struct GNUNET_DATACACHE_PluginEnvironmnet")
1033 * @return the plugin's closure (our "struct Plugin")
1036 libgnunet_plugin_datacache_mysql_init (void *cls)
1038 struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
1039 struct GNUNET_DATACACHE_PluginFunctions *api;
1040 struct Plugin *plugin;
1042 plugin = GNUNET_malloc (sizeof (struct Plugin));
1044 plugin->cnffile = get_my_cnf_path (env->cfg);
1048 GNUNET_free_non_null (plugin->cnffile);
1049 GNUNET_free (plugin);
1056 GNUNET_free_non_null (plugin->cnffile);
1057 GNUNET_free (plugin);
1060 api = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_PluginFunctions));
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"));
1072 * Exit point from the plugin.
1074 * @param cls closure (our "struct Plugin")
1078 libgnunet_plugin_datacache_mysql_done (void *cls)
1080 struct GNUNET_DATACACHE_PluginFunctions *api = cls;
1081 struct Plugin *plugin = api->cls;
1084 GNUNET_free_non_null (plugin->cnffile);
1085 GNUNET_free (plugin);
1087 mysql_library_end ();
1092 /* end of plugin_datacache_mysql.c */