00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #ifdef HAVE_CONFIG_H
00011 #include "config.h"
00012 #endif
00013
00014 #include <stdio.h>
00015 #include <stdlib.h>
00016 #include <string.h>
00017 #include <errno.h>
00018 #include <pthread.h>
00019
00020 #include <fuse/fuse.h>
00021 #ifdef HAVE_MYSQL_MYSQL_H
00022 #include <mysql/mysql.h>
00023 #endif
00024 #ifdef HAVE_MYSQL_H
00025 #include <mysql.h>
00026 #endif
00027
00028 #include "query.h"
00029 #include "pool.h"
00030 #include "log.h"
00031
00032 struct mysqlfs_opt *opt;
00033
00035 struct pool_lifo {
00036 struct pool_lifo *next;
00037 void *conn;
00038 };
00039
00040
00041 struct pool_lifo *lifo_pool = NULL;
00042 struct pool_lifo *lifo_unused = NULL;
00043 static pthread_mutex_t lifo_mutex = PTHREAD_MUTEX_INITIALIZER;
00044 unsigned int lifo_unused_cnt = 0;
00045 unsigned int lifo_pool_cnt = 0;
00046
00047
00048
00049
00050
00051 static MYSQL *pool_open_mysql_connection()
00052 {
00053 MYSQL *mysql;
00054 my_bool reconnect = 1;
00055
00056 mysql = mysql_init(NULL);
00057 if (!mysql) {
00058 log_printf(LOG_ERROR, "%s(): %s\n", __func__, strerror(ENOMEM));
00059 return NULL;
00060 }
00061
00062 if (opt->mycnf_group)
00063 mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, opt->mycnf_group);
00064
00065 if (! mysql_real_connect(mysql, opt->host, opt->user,
00066 opt->passwd, opt->db,
00067 opt->port, opt->socket, 0)) {
00068 log_printf(LOG_ERROR, "ERROR: mysql_real_connect(): %s\n",
00069 mysql_error(mysql));
00070 mysql_close(mysql);
00071 return NULL;
00072 }
00073
00074
00075 mysql_options(mysql, MYSQL_OPT_RECONNECT, (char*)&reconnect);
00076
00077 return mysql;
00078 }
00079
00080 static void pool_close_mysql_connection(MYSQL *mysql)
00081 {
00082 if (mysql)
00083 mysql_close(mysql);
00084 }
00085
00086 static int pool_check_mysql_setup(MYSQL *mysql)
00087 {
00088 int ret = 0;
00089
00090
00091 unsigned long mysql_version;
00092 mysql_version = mysql_get_server_version(mysql);
00093 if (mysql_version < MYSQL_MIN_VERSION) {
00094 log_printf(LOG_ERROR, "Your server version is %s. "
00095 "Version %lu.%lu.%lu or higher is required.\n",
00096 mysql_get_server_info(mysql),
00097 MYSQL_MIN_VERSION/10000L,
00098 (MYSQL_MIN_VERSION%10000L)/100,
00099 MYSQL_MIN_VERSION%100L);
00100 ret = -ENOENT;
00101 goto out;
00102 }
00103
00104
00105 ret = query_inode_full(mysql, "/", NULL, 0, NULL, NULL, NULL);
00106 if (ret == -ENOENT)
00107 ret = query_mkdir(mysql, "/", 0755, 0);
00108 if (ret < 0)
00109 goto out;
00110
00111
00112 if (opt->fsck == 1) {
00113 ret = query_fsck(mysql);
00114 }
00115
00116 out:
00117 return ret;
00118 }
00119
00120
00121
00122
00123
00124 static inline int lifo_put(void *conn)
00125 {
00126 struct pool_lifo *ent;
00127
00128 log_printf(LOG_D_POOL, "%s() <= %p\n", __func__, conn);
00129 pthread_mutex_lock(&lifo_mutex);
00130 if (lifo_unused) {
00131 ent = lifo_unused;
00132 lifo_unused = ent->next;
00133 lifo_unused_cnt--;
00134 } else {
00135 ent = calloc(1, sizeof(struct pool_lifo));
00136 if (!ent) {
00137 pthread_mutex_unlock(&lifo_mutex);
00138 return -ENOMEM;
00139 }
00140 }
00141 ent->conn = conn;
00142 ent->next = lifo_pool;
00143 lifo_pool = ent;
00144 lifo_pool_cnt++;
00145 pthread_mutex_unlock(&lifo_mutex);
00146
00147 return 0;
00148 }
00149
00150 static inline void *lifo_get()
00151 {
00152 struct pool_lifo *ent;
00153 void *conn;
00154
00155 pthread_mutex_lock(&lifo_mutex);
00156 if (lifo_pool) {
00157 ent = lifo_pool;
00158 conn = ent->conn;
00159 lifo_pool = ent->next;
00160 lifo_pool_cnt--;
00161 ent->next = lifo_unused;
00162 ent->conn = NULL;
00163 lifo_unused = ent;
00164 lifo_unused_cnt++;
00165 } else
00166 conn = NULL;
00167 pthread_mutex_unlock(&lifo_mutex);
00168
00169 return conn;
00170 }
00171
00172 int pool_init(struct mysqlfs_opt *opt_arg)
00173 {
00174 int i, ret;
00175
00176 log_printf(LOG_D_POOL, "%s()\n", __func__);
00177 opt = opt_arg;
00178
00179 for (i = 0; i < opt->init_conns; i++) {
00180 void *conn = pool_open_mysql_connection();
00181 lifo_put(conn);
00182 }
00183
00184
00185
00186
00187 MYSQL *mysql = pool_get();
00188 if (!mysql) {
00189 log_printf(LOG_ERROR, "Failed to connect MySQL server.\n");
00190 return -1;
00191 }
00192
00193 ret = pool_check_mysql_setup(mysql);
00194
00195 pool_put(mysql);
00196
00197 return ret;
00198 }
00199
00200 void pool_cleanup()
00201 {
00202 void *conn;
00203 log_printf(LOG_D_POOL, "%s()...\n", __func__);
00204 while ((conn = lifo_get())) {
00205 log_printf(LOG_D_POOL, "%s(): closing conn=%p\n", __func__, conn);
00206 pool_close_mysql_connection(conn);
00207 }
00208 }
00209
00210 void *pool_get()
00211 {
00212 void *conn = lifo_get();
00213 if (!conn) {
00214 conn = pool_open_mysql_connection();
00215 log_printf(LOG_D_POOL, "%s(): Allocated new connection = %p\n", __func__, conn);
00216 } else
00217 log_printf(LOG_D_POOL, "%s(): Reused connection = %p\n", __func__, conn);
00218
00219 return conn;
00220 }
00221
00222 void pool_put(void *conn)
00223 {
00224 log_printf(LOG_D_POOL, "%s(%p)\n", __func__, conn);
00225
00226
00227
00228
00229 if (lifo_pool_cnt >= opt->max_idling_conns)
00230 pool_close_mysql_connection(conn);
00231 else
00232 if (lifo_put(conn) < 0)
00233 pool_close_mysql_connection(conn);
00234 }