diff options
Diffstat (limited to 'daemon/mysql.c')
-rw-r--r-- | daemon/mysql.c | 127 |
1 files changed, 89 insertions, 38 deletions
diff --git a/daemon/mysql.c b/daemon/mysql.c index 0ed8f35..1a75374 100644 --- a/daemon/mysql.c +++ b/daemon/mysql.c @@ -26,7 +26,7 @@ typedef struct mysql_context /* Base Handler ------------------------------------------------------ */ bd_context_t bd; - /* Settings ---------------------------------------------------------- */ + /* Readonly Settings ------------------------------------------------- */ const char* host; /* The connection host or path */ unsigned int port; /* The connection port */ const char* user; /* The pgsql user name */ @@ -41,7 +41,7 @@ typedef struct mysql_context int mysql_timeout; /* Maximum amount of time to dedicate to a query */ int use_unix_socket; - /* Context ----------------------------------------------------------- */ + /* Require Locking --------------------------------------------------- */ MYSQL** pool; /* Pool of available connections */ int pool_mark; /* Amount of connections allocated */ } @@ -73,6 +73,11 @@ static const mysql_context_t mysql_defaults = 0 /* pool_mark */ }; +/* mysql_real_connect is not always thread-safe :( */ +static pthread_mutex_t g_mysql_mutex; +static pthread_mutexattr_t g_mysql_mutexattr; + + /* ------------------------------------------------------------------------------- * Internal Functions @@ -235,27 +240,40 @@ static MYSQL* get_mysql_connection(const ha_request_t* rq, mysql_context_t* ctx) { MYSQL* my; MYSQL* r; - int i; + int i, create = 1; ASSERT(ctx); - for(i = 0; i < ctx->mysql_max; i++) - { - /* An open connection in the pool */ - if(ctx->pool[i]) + /* + * Note that below there maybe a race condition between the two locks + * but this will only allow a few extra connections to open at best + * and as such really isn't a big issue. + */ + + ha_lock(&g_mysql_mutex); + + for(i = 0; i < ctx->mysql_max; i++) { - ha_messagex(rq, LOG_DEBUG, "using cached mysql connection"); - my = ctx->pool[i]; - ctx->pool[i] = NULL; - return my; + /* An open connection in the pool */ + if(ctx->pool[i]) + { + ha_messagex(rq, LOG_DEBUG, "using cached mysql connection"); + my = ctx->pool[i]; + ctx->pool[i] = NULL; + } } - } - if(ctx->pool_mark >= ctx->mysql_max) - { - ha_messagex(rq, LOG_ERR, "too many open mysql connections"); - return NULL; - } + + if(my == NULL && ctx->pool_mark >= ctx->mysql_max) + { + ha_messagex(rq, LOG_ERR, "too many open mysql connections"); + create = 0; + } + + ha_unlock(&g_mysql_mutex); + + if(my != NULL || create == 0) + return my; my = mysql_init(NULL); if(!my) @@ -269,29 +287,39 @@ static MYSQL* get_mysql_connection(const ha_request_t* rq, mysql_context_t* ctx) mysql_options(my, MYSQL_OPT_WRITE_TIMEOUT, (char*)&(ctx->mysql_timeout)); */ /* Apparently mysql_real_connect is not thread safe :( */ - ha_lock(NULL); + ha_lock(&g_mysql_mutex); + r = mysql_real_connect(my, ctx->use_unix_socket ? NULL : ctx->host, ctx->user, ctx->password, ctx->database, ctx->port, ctx->use_unix_socket ? ctx->host : NULL, 0); - ha_unlock(NULL); - if(!r) - { - ha_messagex(rq, LOG_ERR, "error opening mysql connection: %s", mysql_error(my)); - mysql_close(my); - return NULL; - } + if(!r) + { + ha_messagex(rq, LOG_ERR, "error opening mysql connection: %s", mysql_error(my)); + mysql_close(my); + my = NULL; + } + else + { + ctx->pool_mark++; + ha_messagex(rq, LOG_DEBUG, "opened new mysql connection (total %d)", ctx->pool_mark); + } + + ha_unlock(&g_mysql_mutex); - ctx->pool_mark++; - ha_messagex(rq, LOG_DEBUG, "opened new mysql connection (total %d)", ctx->pool_mark); return my; } static void discard_mysql_connection(const ha_request_t* rq, mysql_context_t* ctx, MYSQL* my) { mysql_close(my); - ctx->pool_mark--; - ha_messagex(rq, LOG_DEBUG, "discarding mysql connection (total %d)", ctx->pool_mark); + + ha_lock(&g_mysql_mutex); + + ctx->pool_mark--; + ha_messagex(rq, LOG_DEBUG, "discarding mysql connection (total %d)", ctx->pool_mark); + + ha_unlock(&g_mysql_mutex); } static void save_mysql_connection(const ha_request_t* rq, mysql_context_t* ctx, MYSQL* my) @@ -322,17 +350,21 @@ static void save_mysql_connection(const ha_request_t* rq, mysql_context_t* ctx, /* Make sure it's worth saving */ default: - for(i = 0; i < ctx->mysql_max; i++) - { - /* An open connection in the pool */ - if(!ctx->pool[i]) + ha_lock(&g_mysql_mutex); + + for(i = 0; i < ctx->mysql_max; i++) { - ha_messagex(rq, LOG_DEBUG, "caching mysql connection for later use"); - ctx->pool[i] = my; - my = NULL; - break; + /* An open connection in the pool */ + if(!ctx->pool[i]) + { + ha_messagex(rq, LOG_DEBUG, "caching mysql connection for later use"); + ctx->pool[i] = my; + my = NULL; + break; + } } - } + + ha_unlock(&g_mysql_mutex); break; }; @@ -701,6 +733,19 @@ int mysql_initialize(ha_context_t* context) ha_messagex(NULL, LOG_INFO, "initialized mysql handler"); } + /* Global Initialization */ + else + { + /* Create the smblib mutex */ + if(pthread_mutexattr_init(&g_mysql_mutexattr) != 0 || + pthread_mutexattr_settype(&g_mysql_mutexattr, HA_MUTEX_TYPE) || + pthread_mutex_init(&g_mysql_mutex, &g_mysql_mutexattr) != 0) + { + ha_messagex(NULL, LOG_CRIT, "threading problem. can't create mutex"); + return HA_CRITERROR; + } + } + return HA_OK; } @@ -727,6 +772,12 @@ void mysql_destroy(ha_context_t* context) free(ctx->pool); } } + else + { + /* Close the mutex */ + pthread_mutex_destroy(&g_mysql_mutex); + pthread_mutexattr_destroy(&g_mysql_mutexattr); + } bd_destroy(context); ha_messagex(NULL, LOG_INFO, "uninitialized mysql handler"); |