2 This file is part of GNUnet
3 (C) 2009, 2010, 2011 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 datastore/plugin_datastore_mysql.c
23 * @brief mysql-based datastore backend
24 * @author Igor Wronsky
25 * @author Christian Grothoff
27 * NOTE: This db module does NOT work with mysql prior to 4.1 since
28 * it uses prepared statements. MySQL 5.0.46 promises to fix a bug
29 * in MyISAM that is causing us grief. At the time of this writing,
30 * that version is yet to be released. In anticipation, the code
31 * will use MyISAM with 5.0.46 (and higher). If you run such a
32 * version, please run "make check" to verify that the MySQL bug
33 * was actually fixed in your version (and if not, change the
34 * code below to use MyISAM for gn071).
39 * + On up-to-date hardware where mysql can be used comfortably, this
40 * module will have better performance than the other db choices
41 * (according to our tests).
42 * + Its often possible to recover the mysql database from internal
43 * inconsistencies. The other db choices do not support repair!
45 * - Memory usage (Comment: "I have 1G and it never caused me trouble")
48 * MANUAL SETUP INSTRUCTIONS
50 * 1) in /etc/gnunet.conf, set
55 * 2) Then access mysql as root,
59 * and do the following. [You should replace $USER with the username
60 * that will be running the gnunetd process].
62 CREATE DATABASE gnunet;
63 GRANT select,insert,update,delete,create,alter,drop,create temporary tables
64 ON gnunet.* TO $USER@localhost;
65 SET PASSWORD FOR $USER@localhost=PASSWORD('$the_password_you_like');
68 * 3) In the $HOME directory of $USER, create a ".my.cnf" file
69 * with the following lines
73 password=$the_password_you_like
76 * Thats it. Note that .my.cnf file is a security risk unless its on
77 * a safe partition etc. The $HOME/.my.cnf can of course be a symbolic
78 * link. Even greater security risk can be achieved by setting no
79 * password for $USER. Luckily $USER has only priviledges to mess
80 * up GNUnet's tables, nothing else (unless you give him more,
83 * 4) Still, perhaps you should briefly try if the DB connection
84 * works. First, login as $USER. Then use,
87 $ mysql -u $USER -p $the_password_you_like
91 * If you get the message "Database changed" it probably works.
93 * [If you get "ERROR 2002: Can't connect to local MySQL server
94 * through socket '/tmp/mysql.sock' (2)" it may be resolvable by
95 * "ln -s /var/run/mysqld/mysqld.sock /tmp/mysql.sock"
96 * so there may be some additional trouble depending on your mysql setup.]
100 * - Its probably healthy to check your tables for inconsistencies
101 * every now and then.
102 * - If you get odd SEGVs on gnunetd startup, it might be that the mysql
103 * databases have been corrupted.
104 * - The tables can be verified/fixed in two ways;
105 * 1) by running mysqlcheck -A, or
106 * 2) by executing (inside of mysql using the GNUnet database):
108 mysql> REPAIR TABLE gn090;
113 * If you have problems related to the mysql module, your best
114 * friend is probably the mysql manual. The first thing to check
115 * is that mysql is basically operational, that you can connect
116 * to it, create tables, issue queries etc.
119 #include "platform.h"
120 #include "gnunet_datastore_plugin.h"
121 #include "gnunet_util_lib.h"
122 #include <mysql/mysql.h>
124 #define DEBUG_MYSQL GNUNET_NO
126 #define MAX_DATUM_SIZE 65536
129 * Maximum number of supported parameters for a prepared
130 * statement. Increase if needed.
135 * Die with an error message that indicates
136 * a failure of the command 'cmd' with the message given
137 * by strerror(errno).
139 #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);
142 * Log an error message at log-level 'level' that indicates
143 * a failure of the command 'cmd' on file 'filename'
144 * with the message given by strerror(errno).
146 #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);
149 struct GNUNET_MysqlStatementHandle
151 struct GNUNET_MysqlStatementHandle *next;
153 struct GNUNET_MysqlStatementHandle *prev;
157 MYSQL_STMT *statement;
164 * Context for the universal iterator.
166 struct NextRequestClosure;
169 * Type of a function that will prepare
170 * the next iteration.
173 * @param nc the next context; NULL for the last
174 * call which gives the callback a chance to
175 * clean up the closure
176 * @return GNUNET_OK on success, GNUNET_NO if there are
177 * no more values, GNUNET_SYSERR on error
179 typedef int (*PrepareFunction)(void *cls,
180 struct NextRequestClosure *nc);
183 struct NextRequestClosure
185 struct Plugin *plugin;
187 struct GNUNET_TIME_Absolute now;
190 * Function to call to prepare the next
193 PrepareFunction prep;
202 enum GNUNET_BLOCK_Type type;
204 PluginIterator dviter;
217 * Context for all functions in this plugin.
222 * Our execution environment.
224 struct GNUNET_DATASTORE_PluginEnvironment *env;
227 * Handle to talk to MySQL.
232 * We keep all prepared statements in a DLL. This is the head.
234 struct GNUNET_MysqlStatementHandle *shead;
237 * We keep all prepared statements in a DLL. This is the tail.
239 struct GNUNET_MysqlStatementHandle *stail;
242 * Filename of "my.cnf" (msyql configuration).
247 * Closure of the 'next_task' (must be freed if 'next_task' is cancelled).
249 struct NextRequestClosure *next_task_nc;
252 * Pending task with scheduler for running the next request.
254 GNUNET_SCHEDULER_TaskIdentifier next_task;
257 * Prepared statements.
259 #define INSERT_ENTRY "INSERT INTO gn090 (repl,type,prio,anonLevel,expire,hash,vhash,value) VALUES (?,?,?,?,?,?,?,?)"
260 struct GNUNET_MysqlStatementHandle *insert_entry;
262 #define DELETE_ENTRY_BY_UID "DELETE FROM gn090 WHERE uid=?"
263 struct GNUNET_MysqlStatementHandle *delete_entry_by_uid;
265 #define COUNT_ENTRY_BY_HASH "SELECT count(*) FROM gn090 WHERE hash=?"
266 struct GNUNET_MysqlStatementHandle *count_entry_by_hash;
268 #define SELECT_ENTRY_BY_HASH "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 WHERE hash=? ORDER BY uid LIMIT 1 OFFSET ?"
269 struct GNUNET_MysqlStatementHandle *select_entry_by_hash;
271 #define COUNT_ENTRY_BY_HASH_AND_VHASH "SELECT count(*) FROM gn090 WHERE hash=? AND vhash=?"
272 struct GNUNET_MysqlStatementHandle *count_entry_by_hash_and_vhash;
274 #define SELECT_ENTRY_BY_HASH_AND_VHASH "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 WHERE hash=? AND vhash=? ORDER BY uid LIMIT 1 OFFSET ?"
275 struct GNUNET_MysqlStatementHandle *select_entry_by_hash_and_vhash;
277 #define COUNT_ENTRY_BY_HASH_AND_TYPE "SELECT count(*) FROM gn090 WHERE hash=? AND type=?"
278 struct GNUNET_MysqlStatementHandle *count_entry_by_hash_and_type;
280 #define SELECT_ENTRY_BY_HASH_AND_TYPE "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 WHERE hash=? AND type=? ORDER BY uid LIMIT 1 OFFSET ?"
281 struct GNUNET_MysqlStatementHandle *select_entry_by_hash_and_type;
283 #define COUNT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT count(*) FROM gn090 WHERE hash=? AND vhash=? AND type=?"
284 struct GNUNET_MysqlStatementHandle *count_entry_by_hash_vhash_and_type;
286 #define SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 WHERE hash=? AND vhash=? AND type=? ORDER BY uid ASC LIMIT 1 OFFSET ?"
287 struct GNUNET_MysqlStatementHandle *select_entry_by_hash_vhash_and_type;
289 #define UPDATE_ENTRY "UPDATE gn090 SET prio=prio+?,expire=IF(expire>=?,expire,?) WHERE uid=?"
290 struct GNUNET_MysqlStatementHandle *update_entry;
292 #define DEC_REPL "UPDATE gn090 SET repl=GREATEST (0, repl - 1) WHERE uid=?"
293 struct GNUNET_MysqlStatementHandle *dec_repl;
295 #define SELECT_SIZE "SELECT SUM(BIT_LENGTH(value) DIV 8) FROM gn090"
296 struct GNUNET_MysqlStatementHandle *get_size;
298 #define SELECT_IT_NON_ANONYMOUS "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 WHERE anonLevel=0 ORDER BY uid DESC LIMIT 1 OFFSET ?"
299 struct GNUNET_MysqlStatementHandle *zero_iter;
301 #define SELECT_IT_EXPIRATION "(SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 WHERE expire < ? ORDER BY prio ASC LIMIT 1) "\
303 "(SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 ORDER BY prio ASC LIMIT 1) "\
304 "ORDER BY expire ASC LIMIT 1"
305 struct GNUNET_MysqlStatementHandle *select_expiration;
307 #define SELECT_IT_REPLICATION "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 ORDER BY repl DESC,RAND() LIMIT 1"
308 struct GNUNET_MysqlStatementHandle *select_replication;
314 * Obtain the location of ".my.cnf".
316 * @param cfg our configuration
317 * @return NULL on error
320 get_my_cnf_path (const struct GNUNET_CONFIGURATION_Handle *cfg)
331 pw = getpwuid (getuid ());
334 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
339 GNUNET_CONFIGURATION_have_value (cfg,
340 "datastore-mysql", "CONFIG"))
342 GNUNET_assert (GNUNET_OK ==
343 GNUNET_CONFIGURATION_get_value_filename (cfg,
344 "datastore-mysql", "CONFIG", &cnffile));
345 configured = GNUNET_YES;
349 home_dir = GNUNET_strdup (pw->pw_dir);
351 home_dir = (char *) GNUNET_malloc (_MAX_PATH + 1);
352 plibc_conv_to_win_path ("~/", home_dir);
354 GNUNET_asprintf (&cnffile, "%s/.my.cnf", home_dir);
355 GNUNET_free (home_dir);
356 configured = GNUNET_NO;
358 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
359 _("Trying to use file `%s' for MySQL configuration.\n"),
361 if ((0 != STAT (cnffile, &st)) ||
362 (0 != ACCESS (cnffile, R_OK)) || (!S_ISREG (st.st_mode)))
364 if (configured == GNUNET_YES)
365 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
366 _("Could not access file `%s': %s\n"), cnffile,
368 GNUNET_free (cnffile);
377 * Free a prepared statement.
379 * @param plugin plugin context
380 * @param s prepared statement
383 prepared_statement_destroy (struct Plugin *plugin,
384 struct GNUNET_MysqlStatementHandle
387 GNUNET_CONTAINER_DLL_remove (plugin->shead,
391 mysql_stmt_close (s->statement);
392 GNUNET_free (s->query);
398 * Close database connection and all prepared statements (we got a DB
402 iclose (struct Plugin *plugin)
404 struct GNUNET_MysqlStatementHandle *spos;
406 spos = plugin->shead;
407 while (NULL != plugin->shead)
408 prepared_statement_destroy (plugin,
410 if (plugin->dbf != NULL)
412 mysql_close (plugin->dbf);
420 * Open the connection with the database (and initialize
421 * our default options).
423 * @return GNUNET_OK on success
426 iopen (struct Plugin *ret)
431 char *mysql_password;
432 unsigned long long mysql_port;
434 unsigned int timeout;
436 ret->dbf = mysql_init (NULL);
437 if (ret->dbf == NULL)
438 return GNUNET_SYSERR;
439 if (ret->cnffile != NULL)
440 mysql_options (ret->dbf, MYSQL_READ_DEFAULT_FILE, ret->cnffile);
441 mysql_options (ret->dbf, MYSQL_READ_DEFAULT_GROUP, "client");
443 mysql_options (ret->dbf, MYSQL_OPT_RECONNECT, &reconnect);
444 mysql_options (ret->dbf,
445 MYSQL_OPT_CONNECT_TIMEOUT, (const void *) &timeout);
446 mysql_options(ret->dbf, MYSQL_SET_CHARSET_NAME, "UTF8");
447 timeout = 60; /* in seconds */
448 mysql_options (ret->dbf, MYSQL_OPT_READ_TIMEOUT, (const void *) &timeout);
449 mysql_options (ret->dbf, MYSQL_OPT_WRITE_TIMEOUT, (const void *) &timeout);
451 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (ret->env->cfg,
452 "datastore-mysql", "DATABASE"))
453 GNUNET_assert (GNUNET_OK ==
454 GNUNET_CONFIGURATION_get_value_string (ret->env->cfg,
455 "datastore-mysql", "DATABASE",
458 mysql_dbname = GNUNET_strdup ("gnunet");
460 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (ret->env->cfg,
461 "datastore-mysql", "USER"))
463 GNUNET_assert (GNUNET_OK ==
464 GNUNET_CONFIGURATION_get_value_string (ret->env->cfg,
465 "datastore-mysql", "USER",
468 mysql_password = NULL;
469 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (ret->env->cfg,
470 "datastore-mysql", "PASSWORD"))
472 GNUNET_assert (GNUNET_OK ==
473 GNUNET_CONFIGURATION_get_value_string (ret->env->cfg,
474 "datastore-mysql", "PASSWORD",
478 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (ret->env->cfg,
479 "datastore-mysql", "HOST"))
481 GNUNET_assert (GNUNET_OK ==
482 GNUNET_CONFIGURATION_get_value_string (ret->env->cfg,
483 "datastore-mysql", "HOST",
487 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (ret->env->cfg,
488 "datastore-mysql", "PORT"))
490 GNUNET_assert (GNUNET_OK ==
491 GNUNET_CONFIGURATION_get_value_number (ret->env->cfg, "datastore-mysql",
492 "PORT", &mysql_port));
495 GNUNET_assert (mysql_dbname != NULL);
496 mysql_real_connect (ret->dbf,
498 mysql_user, mysql_password,
500 (unsigned int) mysql_port, NULL,
501 CLIENT_IGNORE_SIGPIPE);
502 GNUNET_free_non_null (mysql_server);
503 GNUNET_free_non_null (mysql_user);
504 GNUNET_free_non_null (mysql_password);
505 GNUNET_free (mysql_dbname);
506 if (mysql_error (ret->dbf)[0])
508 LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR,
509 "mysql_real_connect", ret);
510 return GNUNET_SYSERR;
517 * Run the given MySQL statement.
519 * @param plugin plugin context
520 * @param statement SQL statement to run
521 * @return GNUNET_OK on success, GNUNET_SYSERR on error
524 run_statement (struct Plugin *plugin,
525 const char *statement)
527 if ((NULL == plugin->dbf) && (GNUNET_OK != iopen (plugin)))
528 return GNUNET_SYSERR;
529 mysql_query (plugin->dbf, statement);
530 if (mysql_error (plugin->dbf)[0])
532 LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR,
533 "mysql_query", plugin);
535 return GNUNET_SYSERR;
542 * Create a prepared statement.
544 * @param plugin plugin context
545 * @param statement SQL statement text to prepare
546 * @return NULL on error
548 static struct GNUNET_MysqlStatementHandle *
549 prepared_statement_create (struct Plugin *plugin,
550 const char *statement)
552 struct GNUNET_MysqlStatementHandle *ret;
554 ret = GNUNET_malloc (sizeof (struct GNUNET_MysqlStatementHandle));
555 ret->query = GNUNET_strdup (statement);
556 GNUNET_CONTAINER_DLL_insert (plugin->shead,
564 * Prepare a statement for running.
566 * @param plugin plugin context
567 * @param ret handle to prepared statement
568 * @return GNUNET_OK on success
571 prepare_statement (struct Plugin *plugin,
572 struct GNUNET_MysqlStatementHandle *ret)
574 if (GNUNET_YES == ret->valid)
576 if ((NULL == plugin->dbf) &&
577 (GNUNET_OK != iopen (plugin)))
578 return GNUNET_SYSERR;
579 ret->statement = mysql_stmt_init (plugin->dbf);
580 if (ret->statement == NULL)
583 return GNUNET_SYSERR;
585 if (mysql_stmt_prepare (ret->statement,
587 strlen (ret->query)))
589 LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR,
590 "mysql_stmt_prepare",
592 mysql_stmt_close (ret->statement);
593 ret->statement = NULL;
595 return GNUNET_SYSERR;
597 ret->valid = GNUNET_YES;
604 * Bind the parameters for the given MySQL statement
607 * @param plugin plugin context
608 * @param s statement to bind and run
609 * @param ap arguments for the binding
610 * @return GNUNET_SYSERR on error, GNUNET_OK on success
613 init_params (struct Plugin *plugin,
614 struct GNUNET_MysqlStatementHandle *s,
617 MYSQL_BIND qbind[MAX_PARAM];
620 enum enum_field_types ft;
622 pc = mysql_stmt_param_count (s->statement);
625 /* increase internal constant! */
627 return GNUNET_SYSERR;
629 memset (qbind, 0, sizeof (qbind));
632 while ((pc > 0) && (-1 != (int) (ft = va_arg (ap, enum enum_field_types))))
634 qbind[off].buffer_type = ft;
637 case MYSQL_TYPE_FLOAT:
638 qbind[off].buffer = va_arg (ap, float *);
640 case MYSQL_TYPE_LONGLONG:
641 qbind[off].buffer = va_arg (ap, unsigned long long *);
642 qbind[off].is_unsigned = va_arg (ap, int);
644 case MYSQL_TYPE_LONG:
645 qbind[off].buffer = va_arg (ap, unsigned int *);
646 qbind[off].is_unsigned = va_arg (ap, int);
648 case MYSQL_TYPE_VAR_STRING:
649 case MYSQL_TYPE_STRING:
650 case MYSQL_TYPE_BLOB:
651 qbind[off].buffer = va_arg (ap, void *);
652 qbind[off].buffer_length = va_arg (ap, unsigned long);
653 qbind[off].length = va_arg (ap, unsigned long *);
656 /* unsupported type */
658 return GNUNET_SYSERR;
663 if (! ( (pc == 0) && (-1 != (int) ft) && (va_arg (ap, int) == -1) ) )
666 return GNUNET_SYSERR;
668 if (mysql_stmt_bind_param (s->statement, qbind))
670 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
671 _("`%s' failed at %s:%d with error: %s\n"),
672 "mysql_stmt_bind_param",
673 __FILE__, __LINE__, mysql_stmt_error (s->statement));
675 return GNUNET_SYSERR;
677 if (mysql_stmt_execute (s->statement))
679 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
680 _("`%s' failed at %s:%d with error: %s\n"),
681 "mysql_stmt_execute",
682 __FILE__, __LINE__, mysql_stmt_error (s->statement));
684 return GNUNET_SYSERR;
690 * Type of a callback that will be called for each
691 * data set returned from MySQL.
693 * @param cls user-defined argument
694 * @param num_values number of elements in values
695 * @param values values returned by MySQL
696 * @return GNUNET_OK to continue iterating, GNUNET_SYSERR to abort
698 typedef int (*GNUNET_MysqlDataProcessor) (void *cls,
699 unsigned int num_values,
704 * Run a prepared SELECT statement.
706 * @param plugin plugin context
707 * @param s statement to run
708 * @param result_size number of elements in results array
709 * @param results pointer to already initialized MYSQL_BIND
710 * array (of sufficient size) for passing results
711 * @param processor function to call on each result
712 * @param processor_cls extra argument to processor
713 * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
714 * values (size + buffer-reference for pointers); terminated
716 * @return GNUNET_SYSERR on error, otherwise
717 * the number of successfully affected (or queried) rows
720 prepared_statement_run_select (struct Plugin *plugin,
721 struct GNUNET_MysqlStatementHandle *s,
722 unsigned int result_size,
724 GNUNET_MysqlDataProcessor processor, void *processor_cls,
732 if (GNUNET_OK != prepare_statement (plugin, s))
735 return GNUNET_SYSERR;
737 va_start (ap, processor_cls);
738 if (GNUNET_OK != init_params (plugin, s, ap))
742 return GNUNET_SYSERR;
745 rsize = mysql_stmt_field_count (s->statement);
746 if (rsize > result_size)
749 return GNUNET_SYSERR;
751 if (mysql_stmt_bind_result (s->statement, results))
753 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
754 _("`%s' failed at %s:%d with error: %s\n"),
755 "mysql_stmt_bind_result",
756 __FILE__, __LINE__, mysql_stmt_error (s->statement));
758 return GNUNET_SYSERR;
764 ret = mysql_stmt_fetch (s->statement);
765 if (ret == MYSQL_NO_DATA)
769 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
770 _("`%s' failed at %s:%d with error: %s\n"),
772 __FILE__, __LINE__, mysql_stmt_error (s->statement));
774 return GNUNET_SYSERR;
776 if (processor != NULL)
777 if (GNUNET_OK != processor (processor_cls, rsize, results))
781 mysql_stmt_reset (s->statement);
787 * Run a prepared statement that does NOT produce results.
789 * @param plugin plugin context
790 * @param s statement to run
791 * @param insert_id NULL or address where to store the row ID of whatever
792 * was inserted (only for INSERT statements!)
793 * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
794 * values (size + buffer-reference for pointers); terminated
796 * @return GNUNET_SYSERR on error, otherwise
797 * the number of successfully affected rows
800 prepared_statement_run (struct Plugin *plugin,
801 struct GNUNET_MysqlStatementHandle *s,
802 unsigned long long *insert_id, ...)
807 if (GNUNET_OK != prepare_statement (plugin, s))
808 return GNUNET_SYSERR;
809 va_start (ap, insert_id);
810 if (GNUNET_OK != init_params (plugin, s, ap))
813 return GNUNET_SYSERR;
816 affected = mysql_stmt_affected_rows (s->statement);
817 if (NULL != insert_id)
818 *insert_id = (unsigned long long) mysql_stmt_insert_id (s->statement);
819 mysql_stmt_reset (s->statement);
825 * Delete an entry from the gn090 table.
827 * @param plugin plugin context
828 * @param uid unique ID of the entry to delete
829 * @return GNUNET_OK on success, GNUNET_NO if no such value exists, GNUNET_SYSERR on error
832 do_delete_entry (struct Plugin *plugin,
833 unsigned long long uid)
838 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
839 "Deleting value %llu from gn090 table\n",
842 ret = prepared_statement_run (plugin,
843 plugin->delete_entry_by_uid,
845 MYSQL_TYPE_LONGLONG, &uid, GNUNET_YES,
849 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
850 "Deleting value %llu from gn090 table failed\n",
857 * Function that simply returns GNUNET_OK
859 * @param cls closure, not used
860 * @param num_values not used
861 * @param values not used
865 return_ok (void *cls,
866 unsigned int num_values,
874 * Get an estimate of how much space the database is
877 * @param cls our "struct Plugin *"
878 * @return number of bytes used on disk
880 static unsigned long long
881 mysql_plugin_get_size (void *cls)
883 struct Plugin *plugin = cls;
887 memset (cbind, 0, sizeof (cbind));
889 cbind[0].buffer_type = MYSQL_TYPE_LONGLONG;
890 cbind[0].buffer = &total;
891 cbind[0].is_unsigned = GNUNET_NO;
893 prepared_statement_run_select (plugin,
904 * Store an item in the datastore.
907 * @param key key for the item
908 * @param size number of bytes in data
909 * @param data content stored
910 * @param type type of the content
911 * @param priority priority of the content
912 * @param anonymity anonymity-level for the content
913 * @param replication replication-level for the content
914 * @param expiration expiration time for the content
915 * @param msg set to error message
916 * @return GNUNET_OK on success
919 mysql_plugin_put (void *cls,
920 const GNUNET_HashCode * key,
923 enum GNUNET_BLOCK_Type type,
926 uint32_t replication,
927 struct GNUNET_TIME_Absolute expiration,
930 struct Plugin *plugin = cls;
931 unsigned int irepl = replication;
932 unsigned int itype = type;
933 unsigned int ipriority = priority;
934 unsigned int ianonymity = anonymity;
935 unsigned long long lexpiration = expiration.abs_value;
936 unsigned long hashSize;
937 unsigned long hashSize2;
939 GNUNET_HashCode vhash;
941 if (size > MAX_DATUM_SIZE)
944 return GNUNET_SYSERR;
946 hashSize = sizeof (GNUNET_HashCode);
947 hashSize2 = sizeof (GNUNET_HashCode);
949 GNUNET_CRYPTO_hash (data, size, &vhash);
951 prepared_statement_run (plugin,
952 plugin->insert_entry,
954 MYSQL_TYPE_LONG, &irepl, GNUNET_YES,
955 MYSQL_TYPE_LONG, &itype, GNUNET_YES,
956 MYSQL_TYPE_LONG, &ipriority, GNUNET_YES,
957 MYSQL_TYPE_LONG, &ianonymity, GNUNET_YES,
958 MYSQL_TYPE_LONGLONG, &lexpiration, GNUNET_YES,
959 MYSQL_TYPE_BLOB, key, hashSize, &hashSize,
960 MYSQL_TYPE_BLOB, &vhash, hashSize2, &hashSize2,
961 MYSQL_TYPE_BLOB, data, lsize, &lsize,
963 return GNUNET_SYSERR;
965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
966 "Inserted value `%s' with size %u into gn090 table\n",
968 (unsigned int) size);
971 plugin->env->duc (plugin->env->cls,
978 * Update the priority for a particular key in the datastore. If
979 * the expiration time in value is different than the time found in
980 * the datastore, the higher value should be kept. For the
981 * anonymity level, the lower value is to be used. The specified
982 * priority should be added to the existing priority, ignoring the
985 * Note that it is possible for multiple values to match this put.
986 * In that case, all of the respective values are updated.
988 * @param cls our "struct Plugin*"
989 * @param uid unique identifier of the datum
990 * @param delta by how much should the priority
991 * change? If priority + delta < 0 the
992 * priority should be set to 0 (never go
994 * @param expire new expiration time should be the
995 * MAX of any existing expiration time and
997 * @param msg set to error message
998 * @return GNUNET_OK on success
1001 mysql_plugin_update (void *cls,
1004 struct GNUNET_TIME_Absolute expire,
1007 struct Plugin *plugin = cls;
1008 unsigned long long vkey = uid;
1009 unsigned long long lexpire = expire.abs_value;
1013 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1014 "Updating value %llu adding %d to priority and maxing exp at %llu\n",
1019 ret = prepared_statement_run (plugin,
1020 plugin->update_entry,
1022 MYSQL_TYPE_LONG, &delta, GNUNET_NO,
1023 MYSQL_TYPE_LONGLONG, &lexpire, GNUNET_YES,
1024 MYSQL_TYPE_LONGLONG, &lexpire, GNUNET_YES,
1025 MYSQL_TYPE_LONGLONG, &vkey, GNUNET_YES,
1027 if (ret != GNUNET_OK)
1029 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1030 "Failed to update value %llu\n",
1040 * Continuation of "mysql_next_request".
1042 * @param next_cls the next context
1043 * @param tc the task context (unused)
1046 mysql_next_request_cont (void *next_cls,
1047 const struct GNUNET_SCHEDULER_TaskContext *tc)
1049 struct NextRequestClosure *nrc = next_cls;
1050 struct Plugin *plugin;
1053 unsigned int priority;
1054 unsigned int anonymity;
1055 unsigned long long exp;
1056 unsigned long hashSize;
1058 unsigned long long uid;
1059 char value[GNUNET_DATASTORE_MAX_VALUE_SIZE];
1060 GNUNET_HashCode key;
1061 struct GNUNET_TIME_Absolute expiration;
1062 MYSQL_BIND *rbind = nrc->rbind;
1064 plugin = nrc->plugin;
1065 plugin->next_task = GNUNET_SCHEDULER_NO_TASK;
1066 plugin->next_task_nc = NULL;
1068 if (GNUNET_YES == nrc->end_it)
1070 GNUNET_assert (nrc->plugin->next_task == GNUNET_SCHEDULER_NO_TASK);
1071 nrc->now = GNUNET_TIME_absolute_get ();
1072 hashSize = sizeof (GNUNET_HashCode);
1073 memset (nrc->rbind, 0, sizeof (nrc->rbind));
1075 rbind[0].buffer_type = MYSQL_TYPE_LONG;
1076 rbind[0].buffer = &type;
1077 rbind[0].is_unsigned = 1;
1078 rbind[1].buffer_type = MYSQL_TYPE_LONG;
1079 rbind[1].buffer = &priority;
1080 rbind[1].is_unsigned = 1;
1081 rbind[2].buffer_type = MYSQL_TYPE_LONG;
1082 rbind[2].buffer = &anonymity;
1083 rbind[2].is_unsigned = 1;
1084 rbind[3].buffer_type = MYSQL_TYPE_LONGLONG;
1085 rbind[3].buffer = &exp;
1086 rbind[3].is_unsigned = 1;
1087 rbind[4].buffer_type = MYSQL_TYPE_BLOB;
1088 rbind[4].buffer = &key;
1089 rbind[4].buffer_length = hashSize;
1090 rbind[4].length = &hashSize;
1091 rbind[5].buffer_type = MYSQL_TYPE_BLOB;
1092 rbind[5].buffer = value;
1093 rbind[5].buffer_length = size = sizeof (value);
1094 rbind[5].length = &size;
1095 rbind[6].buffer_type = MYSQL_TYPE_LONGLONG;
1096 rbind[6].buffer = &uid;
1097 rbind[6].is_unsigned = 1;
1099 if (GNUNET_OK != nrc->prep (nrc->prep_cls,
1102 GNUNET_assert (nrc->plugin->next_task == GNUNET_SCHEDULER_NO_TASK);
1103 GNUNET_assert (size <= sizeof(value));
1104 if ( (rbind[4].buffer_length != sizeof (GNUNET_HashCode)) ||
1105 (hashSize != sizeof (GNUNET_HashCode)) )
1111 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1112 "Found %u-byte value under key `%s' with prio %u, anon %u, expire %llu selecting from gn090 table\n",
1113 (unsigned int) size,
1119 expiration.abs_value = exp;
1120 ret = nrc->dviter (nrc->dviter_cls,
1121 (nrc->one_shot == GNUNET_YES) ? NULL : nrc,
1124 type, priority, anonymity, expiration,
1126 if (ret == GNUNET_SYSERR)
1128 nrc->end_it = GNUNET_YES;
1131 if (ret == GNUNET_NO)
1133 do_delete_entry (plugin, uid);
1135 plugin->env->duc (plugin->env->cls,
1138 if (nrc->one_shot == GNUNET_YES)
1142 /* call dviter with "end of set" */
1143 GNUNET_assert (nrc->plugin->next_task == GNUNET_SCHEDULER_NO_TASK);
1144 nrc->dviter (nrc->dviter_cls,
1145 NULL, NULL, 0, NULL, 0, 0, 0,
1146 GNUNET_TIME_UNIT_ZERO_ABS, 0);
1147 GNUNET_assert (nrc->plugin->next_task == GNUNET_SCHEDULER_NO_TASK);
1148 nrc->prep (nrc->prep_cls, NULL);
1149 GNUNET_assert (nrc->plugin->next_task == GNUNET_SCHEDULER_NO_TASK);
1155 * Function invoked on behalf of a "PluginIterator"
1156 * asking the database plugin to call the iterator
1157 * with the next item.
1159 * @param next_cls whatever argument was given
1160 * to the PluginIterator as "next_cls".
1161 * @param end_it set to GNUNET_YES if we
1162 * should terminate the iteration early
1163 * (iterator should be still called once more
1164 * to signal the end of the iteration).
1167 mysql_plugin_next_request (void *next_cls,
1170 struct NextRequestClosure *nrc = next_cls;
1172 if (GNUNET_YES == end_it)
1173 nrc->end_it = GNUNET_YES;
1174 nrc->plugin->next_task_nc = nrc;
1175 nrc->plugin->next_task = GNUNET_SCHEDULER_add_now (&mysql_next_request_cont,
1181 * Context for 'get_statement_prepare'.
1185 GNUNET_HashCode key;
1186 GNUNET_HashCode vhash;
1189 unsigned int anonymity;
1190 unsigned long long expiration;
1191 unsigned long long vkey;
1192 unsigned long long total;
1200 get_statement_prepare (void *cls,
1201 struct NextRequestClosure *nrc)
1203 struct GetContext *gc = cls;
1204 struct Plugin *plugin;
1206 unsigned long hashSize;
1213 if (gc->count == gc->total)
1215 plugin = nrc->plugin;
1216 hashSize = sizeof (GNUNET_HashCode);
1217 if (++gc->off >= gc->total)
1220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1221 "Obtaining result number %d/%lld at offset %u for GET `%s'\n",
1225 GNUNET_h2s (&gc->key));
1231 ret = prepared_statement_run_select (plugin,
1232 plugin->select_entry_by_hash_vhash_and_type,
1235 MYSQL_TYPE_BLOB, &gc->key, hashSize, &hashSize,
1236 MYSQL_TYPE_BLOB, &gc->vhash, hashSize, &hashSize,
1237 MYSQL_TYPE_LONG, &nrc->type, GNUNET_YES,
1238 MYSQL_TYPE_LONG, &gc->off, GNUNET_YES,
1244 prepared_statement_run_select (plugin,
1245 plugin->select_entry_by_hash_and_type,
1248 MYSQL_TYPE_BLOB, &gc->key, hashSize, &hashSize,
1249 MYSQL_TYPE_LONG, &nrc->type, GNUNET_YES,
1250 MYSQL_TYPE_LONG, &gc->off, GNUNET_YES,
1259 prepared_statement_run_select (plugin,
1260 plugin->select_entry_by_hash_and_vhash,
1263 MYSQL_TYPE_BLOB, &gc->key, hashSize, &hashSize,
1264 MYSQL_TYPE_BLOB, &gc->vhash, hashSize, &hashSize,
1265 MYSQL_TYPE_LONG, &gc->off, GNUNET_YES,
1271 prepared_statement_run_select (plugin,
1272 plugin->select_entry_by_hash,
1275 MYSQL_TYPE_BLOB, &gc->key, hashSize, &hashSize,
1276 MYSQL_TYPE_LONG, &gc->off, GNUNET_YES,
1286 * Iterate over the results for a particular key in the datastore.
1288 * @param cls closure
1289 * @param key maybe NULL (to match all entries)
1290 * @param vhash hash of the value, maybe NULL (to
1291 * match all values that have the right key).
1292 * Note that for DBlocks there is no difference
1293 * betwen key and vhash, but for other blocks
1295 * @param type entries of which type are relevant?
1296 * Use 0 for any type.
1297 * @param iter function to call on each matching value;
1298 * will be called once with a NULL value at the end
1299 * @param iter_cls closure for iter
1302 mysql_plugin_get (void *cls,
1303 const GNUNET_HashCode *key,
1304 const GNUNET_HashCode *vhash,
1305 enum GNUNET_BLOCK_Type type,
1306 PluginIterator iter, void *iter_cls)
1308 struct Plugin *plugin = cls;
1309 unsigned int itype = type;
1311 MYSQL_BIND cbind[1];
1312 struct GetContext *gc;
1313 struct NextRequestClosure *nrc;
1315 unsigned long hashSize;
1316 unsigned long hashSize2;
1318 GNUNET_assert (key != NULL);
1321 hashSize = sizeof (GNUNET_HashCode);
1322 hashSize2 = sizeof (GNUNET_HashCode);
1323 memset (cbind, 0, sizeof (cbind));
1325 cbind[0].buffer_type = MYSQL_TYPE_LONGLONG;
1326 cbind[0].buffer = &total;
1327 cbind[0].is_unsigned = GNUNET_NO;
1333 prepared_statement_run_select (plugin,
1334 plugin->count_entry_by_hash_vhash_and_type,
1337 MYSQL_TYPE_BLOB, key, hashSize, &hashSize,
1338 MYSQL_TYPE_BLOB, vhash, hashSize2, &hashSize2,
1339 MYSQL_TYPE_LONG, &itype, GNUNET_YES,
1345 prepared_statement_run_select (plugin,
1346 plugin->count_entry_by_hash_and_type,
1349 MYSQL_TYPE_BLOB, key, hashSize, &hashSize,
1350 MYSQL_TYPE_LONG, &itype, GNUNET_YES,
1359 prepared_statement_run_select (plugin,
1360 plugin->count_entry_by_hash_and_vhash,
1363 MYSQL_TYPE_BLOB, key, hashSize, &hashSize,
1364 MYSQL_TYPE_BLOB, vhash, hashSize2, &hashSize2,
1371 prepared_statement_run_select (plugin,
1372 plugin->count_entry_by_hash,
1375 MYSQL_TYPE_BLOB, key, hashSize, &hashSize,
1379 if ((ret != GNUNET_OK) || (0 >= total))
1382 NULL, NULL, 0, NULL, 0, 0, 0,
1383 GNUNET_TIME_UNIT_ZERO_ABS, 0);
1387 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1388 "Iterating over %lld results for GET `%s'\n",
1392 gc = GNUNET_malloc (sizeof (struct GetContext));
1396 gc->have_vhash = GNUNET_YES;
1400 gc->off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total);
1403 nrc = GNUNET_malloc (sizeof (struct NextRequestClosure));
1404 nrc->plugin = plugin;
1407 nrc->dviter_cls = iter_cls;
1408 nrc->prep = &get_statement_prepare;
1410 mysql_plugin_next_request (nrc, GNUNET_NO);
1415 * Run the prepared statement to get the next data item ready.
1417 * @param cls not used
1418 * @param nrc closure for the next request iterator
1419 * @return GNUNET_OK on success, GNUNET_NO if there is no additional item
1422 iterator_zero_prepare (void *cls,
1423 struct NextRequestClosure *nrc)
1425 struct Plugin *plugin;
1430 plugin = nrc->plugin;
1431 ret = prepared_statement_run_select (plugin,
1435 MYSQL_TYPE_LONG, &nrc->count, GNUNET_YES,
1443 * Select a subset of the items in the datastore and call
1444 * the given iterator for each of them.
1446 * @param cls our "struct Plugin*"
1447 * @param type entries of which type should be considered?
1448 * Use 0 for any type.
1449 * @param iter function to call on each matching value;
1450 * will be called once with a NULL value at the end
1451 * @param iter_cls closure for iter
1454 mysql_plugin_iter_zero_anonymity (void *cls,
1455 enum GNUNET_BLOCK_Type type,
1456 PluginIterator iter,
1459 struct Plugin *plugin = cls;
1460 struct NextRequestClosure *nrc;
1462 nrc = GNUNET_malloc (sizeof (struct NextRequestClosure));
1463 nrc->plugin = plugin;
1466 nrc->dviter_cls = iter_cls;
1467 nrc->prep = &iterator_zero_prepare;
1468 mysql_plugin_next_request (nrc, GNUNET_NO);
1473 * Run the SELECT statement for the replication function.
1475 * @param cls the 'struct Plugin'
1476 * @param nrc the context (not used)
1479 replication_prepare (void *cls,
1480 struct NextRequestClosure *nrc)
1482 struct Plugin *plugin = cls;
1484 return prepared_statement_run_select (plugin,
1485 plugin->select_replication,
1494 * Context for 'repl_iter' function.
1502 struct Plugin *plugin;
1505 * Function to call for the result (or the NULL).
1507 PluginIterator iter;
1517 * Wrapper for the iterator for 'sqlite_plugin_replication_get'.
1518 * Decrements the replication counter and calls the original
1521 * @param cls closure
1522 * @param next_cls closure to pass to the "next" function.
1523 * @param key key for the content
1524 * @param size number of bytes in data
1525 * @param data content stored
1526 * @param type type of the content
1527 * @param priority priority of the content
1528 * @param anonymity anonymity-level for the content
1529 * @param expiration expiration time for the content
1530 * @param uid unique identifier for the datum;
1531 * maybe 0 if no unique identifier is available
1533 * @return GNUNET_SYSERR to abort the iteration, GNUNET_OK to continue
1534 * (continue on call to "next", of course),
1535 * GNUNET_NO to delete the item and continue (if supported)
1538 repl_iter (void *cls,
1540 const GNUNET_HashCode *key,
1543 enum GNUNET_BLOCK_Type type,
1546 struct GNUNET_TIME_Absolute expiration,
1549 struct ReplCtx *rc = cls;
1550 struct Plugin *plugin = rc->plugin;
1551 unsigned long long oid;
1555 ret = rc->iter (rc->iter_cls,
1558 type, priority, anonymity, expiration,
1562 oid = (unsigned long long) uid;
1563 iret = prepared_statement_run (plugin,
1566 MYSQL_TYPE_LONGLONG, &oid, GNUNET_YES,
1568 if (iret == GNUNET_SYSERR)
1570 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1571 "Failed to reduce replication counter\n");
1572 return GNUNET_SYSERR;
1580 * Get a random item for replication. Returns a single, not expired, random item
1581 * from those with the highest replication counters. The item's
1582 * replication counter is decremented by one IF it was positive before.
1583 * Call 'iter' with all values ZERO or NULL if the datastore is empty.
1585 * @param cls closure
1586 * @param iter function to call the value (once only).
1587 * @param iter_cls closure for iter
1590 mysql_plugin_replication_get (void *cls,
1591 PluginIterator iter, void *iter_cls)
1593 struct Plugin *plugin = cls;
1594 struct NextRequestClosure *nrc;
1599 rc.iter_cls = iter_cls;
1600 nrc = GNUNET_malloc (sizeof (struct NextRequestClosure));
1601 nrc->plugin = plugin;
1602 nrc->now = GNUNET_TIME_absolute_get ();
1603 nrc->prep = &replication_prepare;
1604 nrc->prep_cls = plugin;
1606 nrc->dviter = &repl_iter;
1607 nrc->dviter_cls = &rc;
1608 nrc->end_it = GNUNET_NO;
1609 nrc->one_shot = GNUNET_YES;
1610 mysql_next_request_cont (nrc, NULL);
1615 * Run the SELECT statement for the expiration function.
1617 * @param cls the 'struct Plugin'
1618 * @param nrc the context (not used)
1619 * @return GNUNET_OK on success, GNUNET_NO if there are
1620 * no more values, GNUNET_SYSERR on error
1623 expiration_prepare (void *cls,
1624 struct NextRequestClosure *nrc)
1626 struct Plugin *plugin = cls;
1631 nt = (long long) nrc->now.abs_value;
1632 return prepared_statement_run_select
1634 plugin->select_expiration,
1637 MYSQL_TYPE_LONGLONG, &nt, GNUNET_YES,
1643 * Get a random item for expiration.
1644 * Call 'iter' with all values ZERO or NULL if the datastore is empty.
1646 * @param cls closure
1647 * @param iter function to call the value (once only).
1648 * @param iter_cls closure for iter
1651 mysql_plugin_expiration_get (void *cls,
1652 PluginIterator iter, void *iter_cls)
1654 struct Plugin *plugin = cls;
1655 struct NextRequestClosure *nrc;
1657 nrc = GNUNET_malloc (sizeof (struct NextRequestClosure));
1658 nrc->plugin = plugin;
1659 nrc->now = GNUNET_TIME_absolute_get ();
1660 nrc->prep = &expiration_prepare;
1661 nrc->prep_cls = plugin;
1664 nrc->dviter_cls = iter_cls;
1665 nrc->end_it = GNUNET_NO;
1666 nrc->one_shot = GNUNET_YES;
1667 mysql_next_request_cont (nrc, NULL);
1674 * @param cls the "struct Plugin*"
1677 mysql_plugin_drop (void *cls)
1679 struct Plugin *plugin = cls;
1681 if (GNUNET_OK != run_statement (plugin,
1682 "DROP TABLE gn090"))
1684 plugin->env->duc (plugin->env->cls, 0);
1689 * Entry point for the plugin.
1691 * @param cls the "struct GNUNET_DATASTORE_PluginEnvironment*"
1692 * @return our "struct Plugin*"
1695 libgnunet_plugin_datastore_mysql_init (void *cls)
1697 struct GNUNET_DATASTORE_PluginEnvironment *env = cls;
1698 struct GNUNET_DATASTORE_PluginFunctions *api;
1699 struct Plugin *plugin;
1701 plugin = GNUNET_malloc (sizeof (struct Plugin));
1703 plugin->cnffile = get_my_cnf_path (env->cfg);
1704 if (GNUNET_OK != iopen (plugin))
1707 GNUNET_free_non_null (plugin->cnffile);
1708 GNUNET_free (plugin);
1711 #define MRUNS(a) (GNUNET_OK != run_statement (plugin, a) )
1712 #define PINIT(a,b) (NULL == (a = prepared_statement_create(plugin, b)))
1713 if (MRUNS ("CREATE TABLE IF NOT EXISTS gn090 ("
1714 " repl INT(11) UNSIGNED NOT NULL DEFAULT 0,"
1715 " type INT(11) UNSIGNED NOT NULL DEFAULT 0,"
1716 " prio INT(11) UNSIGNED NOT NULL DEFAULT 0,"
1717 " anonLevel INT(11) UNSIGNED NOT NULL DEFAULT 0,"
1718 " expire BIGINT UNSIGNED NOT NULL DEFAULT 0,"
1719 " hash BINARY(64) NOT NULL DEFAULT '',"
1720 " vhash BINARY(64) NOT NULL DEFAULT '',"
1721 " value BLOB NOT NULL DEFAULT '',"
1722 " uid BIGINT NOT NULL AUTO_INCREMENT,"
1723 " PRIMARY KEY (uid)"
1724 " INDEX idx_hash (hash(64)),"
1725 " INDEX idx_hash_uid (hash(64),uid),"
1726 " INDEX idx_hash_vhash (hash(64),vhash(64)),"
1727 " INDEX idx_hash_type_uid (hash(64),type,uid),"
1728 " INDEX idx_prio (prio),"
1729 " INDEX idx_repl (repl),"
1730 " INDEX idx_expire_prio (expire,prio),"
1731 " INDEX idx_anonLevel_uid (anonLevel,uid)"
1732 ") ENGINE=InnoDB") ||
1733 MRUNS ("SET AUTOCOMMIT = 1") ||
1734 PINIT (plugin->insert_entry, INSERT_ENTRY) ||
1735 PINIT (plugin->delete_entry_by_uid, DELETE_ENTRY_BY_UID) ||
1736 PINIT (plugin->select_entry_by_hash, SELECT_ENTRY_BY_HASH) ||
1737 PINIT (plugin->select_entry_by_hash_and_vhash, SELECT_ENTRY_BY_HASH_AND_VHASH)
1738 || PINIT (plugin->select_entry_by_hash_and_type, SELECT_ENTRY_BY_HASH_AND_TYPE)
1739 || PINIT (plugin->select_entry_by_hash_vhash_and_type,
1740 SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE)
1741 || PINIT (plugin->count_entry_by_hash, COUNT_ENTRY_BY_HASH)
1742 || PINIT (plugin->get_size, SELECT_SIZE)
1743 || PINIT (plugin->count_entry_by_hash_and_vhash, COUNT_ENTRY_BY_HASH_AND_VHASH)
1744 || PINIT (plugin->count_entry_by_hash_and_type, COUNT_ENTRY_BY_HASH_AND_TYPE)
1745 || PINIT (plugin->count_entry_by_hash_vhash_and_type,
1746 COUNT_ENTRY_BY_HASH_VHASH_AND_TYPE)
1747 || PINIT (plugin->update_entry, UPDATE_ENTRY)
1748 || PINIT (plugin->dec_repl, DEC_REPL)
1749 || PINIT (plugin->zero_iter, SELECT_IT_NON_ANONYMOUS)
1750 || PINIT (plugin->select_expiration, SELECT_IT_EXPIRATION)
1751 || PINIT (plugin->select_replication, SELECT_IT_REPLICATION) )
1754 GNUNET_free_non_null (plugin->cnffile);
1755 GNUNET_free (plugin);
1761 api = GNUNET_malloc (sizeof (struct GNUNET_DATASTORE_PluginFunctions));
1763 api->get_size = &mysql_plugin_get_size;
1764 api->put = &mysql_plugin_put;
1765 api->next_request = &mysql_plugin_next_request;
1766 api->get = &mysql_plugin_get;
1767 api->replication_get = &mysql_plugin_replication_get;
1768 api->expiration_get = &mysql_plugin_expiration_get;
1769 api->update = &mysql_plugin_update;
1770 api->iter_zero_anonymity = &mysql_plugin_iter_zero_anonymity;
1771 api->drop = &mysql_plugin_drop;
1772 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
1773 "mysql", _("Mysql database running\n"));
1779 * Exit point from the plugin.
1780 * @param cls our "struct Plugin*"
1781 * @return always NULL
1784 libgnunet_plugin_datastore_mysql_done (void *cls)
1786 struct GNUNET_DATASTORE_PluginFunctions *api = cls;
1787 struct Plugin *plugin = api->cls;
1790 if (plugin->next_task != GNUNET_SCHEDULER_NO_TASK)
1792 GNUNET_SCHEDULER_cancel (plugin->next_task);
1793 plugin->next_task = GNUNET_SCHEDULER_NO_TASK;
1794 plugin->next_task_nc->prep (plugin->next_task_nc->prep_cls, NULL);
1795 GNUNET_free (plugin->next_task_nc);
1796 plugin->next_task_nc = NULL;
1798 GNUNET_free_non_null (plugin->cnffile);
1799 GNUNET_free (plugin);
1801 mysql_library_end ();
1805 /* end of plugin_datastore_mysql.c */