⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mysql.c

📁 GNUnet是一个安全的点对点网络框架
💻 C
📖 第 1 页 / 共 5 页
字号:
/*     This file is part of GNUnet.     (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Christian Grothoff (and other contributing authors)     GNUnet is free software; you can redistribute it and/or modify     it under the terms of the GNU General Public License as published     by the Free Software Foundation; either version 2, or (at your     option) any later version.     GNUnet is distributed in the hope that it will be useful, but     WITHOUT ANY WARRANTY; without even the implied warranty of     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     General Public License for more details.     You should have received a copy of the GNU General Public License     along with GNUnet; see the file COPYING.  If not, write to the     Free Software Foundation, Inc., 59 Temple Place - Suite 330,     Boston, MA 02111-1307, USA.*//** * @file applications/sqstore_mysql/mysql.c * @author Igor Wronsky and Christian Grothoff * * Database: MySQL * * NOTE: This db module does NOT work with mysql prior to 4.1 since * it uses prepared statements.  MySQL 5.0.46 promises to fix a bug * in MyISAM that is causing us grief.  At the time of this writing, * that version is yet to be released.  In anticipation, the code * will use MyISAM with 5.0.46 (and higher).  If you run such a * version, please run "make check" to verify that the MySQL bug * was actually fixed in your version (and if not, change the * code below to use MyISAM for gn071). * * HIGHLIGHTS * * Pros * + On up-to-date hardware where mysql can be used comfortably, this *   module will have better performance than the other db choices *   (according to our tests). * + Its often possible to recover the mysql database from internal *   inconsistencies. The other db choices do not support repair! * Cons * - Memory usage (Comment: "I have 1G and it never caused me trouble") * - Manual setup * * MANUAL SETUP INSTRUCTIONS * * 1) in /etc/gnunet.conf, set *    <pre> * *     sqstore = "sqstore_mysql" * *    </pre> * 2) Then access mysql as root, *    <pre> * *    $ mysql -u root -p * *    </pre> *    and do the following. [You should replace $USER with the username *    that will be running the gnunetd process]. *    <pre> *      CREATE DATABASE gnunet;      GRANT select,insert,update,delete,create,alter,drop,create temporary tables         ON gnunet.* TO $USER@localhost;      SET PASSWORD FOR $USER@localhost=PASSWORD('$the_password_you_like');      FLUSH PRIVILEGES; * *    </pre> * 3) In the $HOME directory of $USER, create a ".my.cnf" file *    with the following lines *    <pre>      [client]      user=$USER      password=$the_password_you_like *    </pre> * * Thats it. Note that .my.cnf file is a security risk unless its on * a safe partition etc. The $HOME/.my.cnf can of course be a symbolic * link. Even greater security risk can be achieved by setting no * password for $USER.  Luckily $USER has only priviledges to mess * up GNUnet's tables, nothing else (unless you give him more, * of course).<p> * * 4) Still, perhaps you should briefly try if the DB connection *    works. First, login as $USER. Then use, * *    <pre> *    $ mysql -u $USER -p $the_password_you_like *    mysql> use gnunet; *    </pre> * *    If you get the message &quot;Database changed&quot; it probably works. * *    [If you get &quot;ERROR 2002: Can't connect to local MySQL server *     through socket '/tmp/mysql.sock' (2)&quot; it may be resolvable by *     &quot;ln -s /var/run/mysqld/mysqld.sock /tmp/mysql.sock&quot; *     so there may be some additional trouble depending on your mysql setup.] * * REPAIRING TABLES * * - Its probably healthy to check your tables for inconsistencies *   every now and then. * - If you get odd SEGVs on gnunetd startup, it might be that the mysql *   databases have been corrupted. * - The tables can be verified/fixed in two ways; *   1) by running mysqlcheck -A, or *   2) by executing (inside of mysql using the GNUnet database): *   mysql> REPAIR TABLE gn080; *   mysql> REPAIR TABLE gn072; * * PROBLEMS? * * If you have problems related to the mysql module, your best * friend is probably the mysql manual. The first thing to check * is that mysql is basically operational, that you can connect * to it, create tables, issue queries etc. * */#include "platform.h"#include "gnunet_util.h"#include "gnunet_protocols.h"#include "gnunet_sqstore_service.h"#include "gnunet_stats_service.h"#include "gnunet_state_service.h"#include <mysql/mysql.h>#define DEBUG_MYSQL GNUNET_NO#define DEBUG_TIME_MYSQL GNUNET_NO#define MAX_DATUM_SIZE 65536/** * Die with an error message that indicates * a failure of the command 'cmd' with the message given * by strerror(errno). */#define DIE_MYSQL(cmd, dbh) do { GNUNET_GE_LOG(ectx, GNUNET_GE_FATAL | GNUNET_GE_ADMIN | GNUNET_GE_IMMEDIATE, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); abort(); } while(0);/** * Log an error message at log-level 'level' that indicates * a failure of the command 'cmd' on file 'filename' * with the message given by strerror(errno). */#define LOG_MYSQL(level, cmd, dbh) do { GNUNET_GE_LOG(ectx, level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); } while(0);static GNUNET_Stats_ServiceAPI *stats;static GNUNET_CoreAPIForPlugins *coreAPI;static unsigned int stat_size;/** * Size of the mysql database on disk. */static unsigned long long content_size;/** * Lock for updating content_size */static struct GNUNET_Mutex *lock;static struct GNUNET_GE_Context *ectx;/** * @brief mysql wrapper */typedef struct{  MYSQL *dbf;  char *cnffile;  int valid;  /* stuff dealing with gn072 table */#define SELECT_VALUE "SELECT value FROM gn072 WHERE vkey=?"  MYSQL_STMT *select_value;#define DELETE_VALUE "DELETE FROM gn072 WHERE vkey=?"  MYSQL_STMT *delete_value;#define INSERT_VALUE "INSERT INTO gn072 (value) VALUES (?)"  MYSQL_STMT *insert_value;  /* stuff dealing with gn080 table */#define INSERT_ENTRY "INSERT INTO gn080 (size,type,prio,anonLevel,expire,hash,vhash,vkey) VALUES (?,?,?,?,?,?,?,?)"  MYSQL_STMT *insert_entry;#define DELETE_ENTRY_BY_VKEY "DELETE FROM gn080 WHERE vkey=?"  MYSQL_STMT *delete_entry_by_vkey;#define SELECT_ENTRY_BY_HASH "SELECT size,type,prio,anonLevel,expire,hash,vkey FROM gn080 FORCE INDEX (hash_vkey) WHERE hash=? AND vkey > ? ORDER BY vkey ASC LIMIT 1 OFFSET ?"  MYSQL_STMT *select_entry_by_hash;#define SELECT_ENTRY_BY_HASH_AND_VHASH "SELECT size,type,prio,anonLevel,expire,hash,vkey FROM gn080 FORCE INDEX (hash_vhash_vkey) WHERE hash=? AND vhash=? AND vkey > ? ORDER BY vkey ASC LIMIT 1 OFFSET ?"  MYSQL_STMT *select_entry_by_hash_and_vhash;#define SELECT_ENTRY_BY_HASH_AND_TYPE "SELECT size,type,prio,anonLevel,expire,hash,vkey FROM gn080 FORCE INDEX (hash_vkey) WHERE hash=? AND vkey > ? AND type=? ORDER BY vkey ASC LIMIT 1 OFFSET ?"  MYSQL_STMT *select_entry_by_hash_and_type;#define SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT size,type,prio,anonLevel,expire,hash,vkey FROM gn080 FORCE INDEX (hash_vhash_vkey) WHERE hash=? AND vhash=? AND vkey > ? AND type=? ORDER BY vkey ASC LIMIT 1 OFFSET ?"  MYSQL_STMT *select_entry_by_hash_vhash_and_type;#define COUNT_ENTRY_BY_HASH "SELECT count(*) FROM gn080 FORCE INDEX (hash) WHERE hash=?"  MYSQL_STMT *count_entry_by_hash;#define COUNT_ENTRY_BY_HASH_AND_VHASH "SELECT count(*) FROM gn080 FORCE INDEX (hash_vhash_vkey) WHERE hash=? AND vhash=?"  MYSQL_STMT *count_entry_by_hash_and_vhash;#define COUNT_ENTRY_BY_HASH_AND_TYPE "SELECT count(*) FROM gn080 FORCE INDEX (hash) WHERE hash=? AND type=?"  MYSQL_STMT *count_entry_by_hash_and_type;#define COUNT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT count(*) FROM gn080 FORCE INDEX (hash_vhash) WHERE hash=? AND vhash=? AND type=?"  MYSQL_STMT *count_entry_by_hash_vhash_and_type;#define UPDATE_ENTRY "UPDATE gn080 SET prio=prio+?,expire=IF(expire>=?,expire,?) WHERE vkey=?"  MYSQL_STMT *update_entry;#if 0  /* old, easier to read statments -- do not use,     C code no longer works with these! */#define SELECT_IT_LOW_PRIORITY "SELECT size,type,prio,anonLevel,expire,hash,vkey FROM gn080 WHERE ( (prio = ? AND vkey > ?) OR (prio > ? AND vkey != ?) )"\                               "ORDER BY prio ASC,vkey ASC LIMIT 1"#define SELECT_IT_NON_ANONYMOUS "SELECT size,type,prio,anonLevel,expire,hash,vkey FROM gn080 WHERE ( (prio = ? AND vkey < ?) OR (prio < ? AND vkey != ?) ) "\                                "AND anonLevel=0 AND type != 0xFFFFFFFF "\                                "ORDER BY prio DESC,vkey DESC LIMIT 1"#define SELECT_IT_EXPIRATION_TIME "SELECT size,type,prio,anonLevel,expire,hash,vkey FROM gn080 WHERE ( (expire = ? AND vkey > ?) OR (expire > ? AND vkey != ?) ) "\                                  "ORDER BY expire ASC,vkey ASC LIMIT 1"#define SELECT_IT_MIGRATION_ORDER "SELECT size,type,prio,anonLevel,expire,hash,vkey FROM gn080 WHERE ( (expire = ? AND vkey < ?) OR (expire < ? AND vkey != ?) ) "\                                  "AND expire > ? AND type!=3 "\                                  "ORDER BY expire DESC,vkey DESC LIMIT 1"#endif/* warning, slighly crazy mysql statements ahead.  Essentially, MySQL does not handle   "OR" very well, so we need to use UNION instead.  And UNION does not   automatically apply a LIMIT on the outermost clause, so we need to   repeat ourselves quite a bit.  All hail the performance gods (and thanks   to #mysql on freenode) */#define SELECT_IT_LOW_PRIORITY "(SELECT size,type,prio,anonLevel,expire,hash,vkey FROM gn080 FORCE INDEX(prio) WHERE (prio = ? AND vkey > ?) "\                               "ORDER BY prio ASC,vkey ASC LIMIT 1) "\                               "UNION "\                               "(SELECT size,type,prio,anonLevel,expire,hash,vkey FROM gn080 FORCE INDEX(prio) WHERE (prio > ? AND vkey != ?)"\                               "ORDER BY prio ASC,vkey ASC LIMIT 1)"\                               "ORDER BY prio ASC,vkey ASC LIMIT 1"#define SELECT_IT_NON_ANONYMOUS "(SELECT size,type,prio,anonLevel,expire,hash,vkey FROM gn080 FORCE INDEX(prio) WHERE (prio = ? AND vkey < ?)"\                                " AND anonLevel=0 AND type != 0xFFFFFFFF ORDER BY prio DESC,vkey DESC LIMIT 1) "\                                "UNION "\                                "(SELECT size,type,prio,anonLevel,expire,hash,vkey FROM gn080 FORCE INDEX(prio) WHERE (prio < ? AND vkey != ?)"\                                " AND anonLevel=0 AND type != 0xFFFFFFFF ORDER BY prio DESC,vkey DESC LIMIT 1) "\                                "ORDER BY prio DESC,vkey DESC LIMIT 1"#define SELECT_IT_EXPIRATION_TIME "(SELECT size,type,prio,anonLevel,expire,hash,vkey FROM gn080 FORCE INDEX(expire) WHERE (expire = ? AND vkey > ?) "\                                  "ORDER BY expire ASC,vkey ASC LIMIT 1) "\                                  "UNION "\                                  "(SELECT size,type,prio,anonLevel,expire,hash,vkey FROM gn080 FORCE INDEX(expire) WHERE (expire > ? AND vkey != ?) "\                                  "ORDER BY expire ASC,vkey ASC LIMIT 1)"\                                  "ORDER BY expire ASC,vkey ASC LIMIT 1"#define SELECT_IT_MIGRATION_ORDER "(SELECT size,type,prio,anonLevel,expire,hash,vkey FROM gn080 FORCE INDEX(expire) WHERE (expire = ? AND vkey < ?)"\                                  " AND expire > ? AND type!=3"\                                  " ORDER BY expire DESC,vkey DESC LIMIT 1) "\                                  "UNION "\                                  "(SELECT size,type,prio,anonLevel,expire,hash,vkey FROM gn080 FORCE INDEX(expire) WHERE (expire < ? AND vkey != ?)"\                                  " AND expire > ? AND type!=3"\                                  " ORDER BY expire DESC,vkey DESC LIMIT 1)"\                                  "ORDER BY expire DESC,vkey DESC LIMIT 1"  MYSQL_STMT *iter[4];} mysqlHandle;#define SELECT_SIZE "SELECT sum(size) FROM gn080"static mysqlHandle *dbh;/** * Close the database connection. */static inticlose (){#define PEND(h) if (h != NULL) { mysql_stmt_close(h); h = NULL; } else {}  if (dbh->dbf == NULL)    return GNUNET_SYSERR;  PEND (dbh->select_value);  PEND (dbh->delete_value);  PEND (dbh->insert_value);  PEND (dbh->insert_entry);  PEND (dbh->delete_entry_by_vkey);  PEND (dbh->select_entry_by_hash);  PEND (dbh->select_entry_by_hash_and_vhash);  PEND (dbh->select_entry_by_hash_and_type);  PEND (dbh->select_entry_by_hash_vhash_and_type);  PEND (dbh->count_entry_by_hash);  PEND (dbh->count_entry_by_hash_and_vhash);  PEND (dbh->count_entry_by_hash_and_type);  PEND (dbh->count_entry_by_hash_vhash_and_type);  PEND (dbh->update_entry);  PEND (dbh->iter[0]);  PEND (dbh->iter[1]);  PEND (dbh->iter[2]);  PEND (dbh->iter[3]);  mysql_close (dbh->dbf);  dbh->dbf = NULL;  dbh->valid = GNUNET_NO;  return GNUNET_OK;}/** * Initiate the database connection.  Uses dbh->cnffile for the * configuration, so that must be set already. * * @return GNUNET_OK on success */static intiopen (){  char *dbname;  my_bool reconnect = 0;  unsigned int timeout = 60;    /* in seconds */  if (dbh->cnffile == NULL)    return GNUNET_SYSERR;  dbh->dbf = mysql_init (NULL);  if (dbh->dbf == NULL)    return GNUNET_SYSERR;  mysql_options (dbh->dbf, MYSQL_READ_DEFAULT_FILE, dbh->cnffile);  mysql_options (dbh->dbf, MYSQL_READ_DEFAULT_GROUP, "client");  mysql_options (dbh->dbf, MYSQL_OPT_RECONNECT, &reconnect);  mysql_options (dbh->dbf,                 MYSQL_OPT_CONNECT_TIMEOUT, (const void *) &timeout);  mysql_options (dbh->dbf, MYSQL_OPT_READ_TIMEOUT, (const void *) &timeout);  mysql_options (dbh->dbf, MYSQL_OPT_WRITE_TIMEOUT, (const void *) &timeout);  dbname = NULL;  GNUNET_GC_get_configuration_value_string (coreAPI->cfg,                                            "MYSQL", "DATABASE", "gnunet",                                            &dbname);  GNUNET_GE_ASSERT (ectx, dbname != NULL);  mysql_real_connect (dbh->dbf, NULL, NULL, NULL, dbname, 0, NULL, 0);  GNUNET_free (dbname);  if (mysql_error (dbh->dbf)[0])    {      LOG_MYSQL (GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,                 "mysql_real_connect", dbh);      iclose ();      return GNUNET_SYSERR;    }  mysql_query (dbh->dbf,               "SET SESSION net_read_timeout=60, SESSION net_write_timeout=60");  if (mysql_error (dbh->dbf)[0])    {      LOG_MYSQL (GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK,                 "mysql_query", dbh);      iclose ();      return GNUNET_SYSERR;    }  /* MySQL 5.0.46 fixes a bug in MyISAM (presumably);     earlier versions have issues with INDEX over BINARY data,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -