diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/dbrw.h | 8 | ||||
-rw-r--r-- | src/mysql.c | 68 | ||||
-rw-r--r-- | src/sql.c | 11 | ||||
-rw-r--r-- | src/vmod_dbrw.c | 38 |
4 files changed, 81 insertions, 44 deletions
@@ -1,5 +1,5 @@ /* This file is part of vmod-dbrw - Copyright (C) 2013-2017 Sergey Poznyakoff + Copyright (C) 2013-2018 Sergey Poznyakoff Vmod-dbrw is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -43,6 +43,7 @@ struct dbrw_backend { int (*sql_free_result) (struct dbrw_connection *); const char *(*sql_get_column)(struct dbrw_connection *, unsigned, unsigned); + int (*sql_idle_timeout)(struct dbrw_connection *); }; enum { @@ -66,6 +67,7 @@ struct dbrw_config { int qdisp; int regflags; char status[HTTP_STATUS_LEN+1]; + int idle_timeout; VTAILQ_ENTRY(dbrw_config) list; }; @@ -77,7 +79,8 @@ struct dbrw_connection { struct dbrw_config *conf; /* Pointer to the configuration data */ regmatch_t *matches; /* Match map */ size_t matchsize; /* Total number of entries in match map */ - void *data; /* Backend-specific data */ + time_t timestamp; /* Last used at */ + void *data; /* Backend-specific data */ VTAILQ_ENTRY(dbrw_connection) list; }; @@ -105,6 +108,7 @@ unsigned sql_num_fields(struct dbrw_connection *pd); void sql_free_result(struct dbrw_connection *pd); void sql_destroy(struct dbrw_connection *pd); const char *sql_get_column(struct dbrw_connection *pd, unsigned row, unsigned col); +int sql_idle_timeout(struct dbrw_connection *conn); char *findparam(char **params, char *name); diff --git a/src/mysql.c b/src/mysql.c index d7406ca..d97200a 100644 --- a/src/mysql.c +++ b/src/mysql.c @@ -1,5 +1,5 @@ /* This file is part of vmod-dbrw - Copyright (C) 2013-2014 Sergey Poznyakoff + Copyright (C) 2013-2018 Sergey Poznyakoff Vmod-dbrw is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,7 +21,7 @@ struct vmod_mysql_data { - MYSQL *mysql; + MYSQL mysql; MYSQL_RES *result; char *buffer; size_t bufsize; @@ -33,12 +33,12 @@ check_errno(struct dbrw_connection *conn) { struct vmod_mysql_data *mp = conn->data; - switch (mysql_errno(mp->mysql)) { + switch (mysql_errno(&mp->mysql)) { case CR_SERVER_GONE_ERROR: case CR_SERVER_LOST: case ER_SERVER_SHUTDOWN: case ER_ABORTING_CONNECTION: - dbrw_error("query failed: %s", mysql_error(mp->mysql)); + dbrw_error("query failed: %s", mysql_error(&mp->mysql)); sql_disconnect(conn); if (conn->state == state_error) { conn->state = state_disabled; @@ -58,13 +58,13 @@ check_errno(struct dbrw_connection *conn) case ER_FIELD_SPECIFIED_TWICE: case ER_NO_SUCH_TABLE: case ER_NOT_ALLOWED_COMMAND: - dbrw_error("query failed: %s", mysql_error(mp->mysql)); + dbrw_error("query failed: %s", mysql_error(&mp->mysql)); dbrw_error("disabling MySQL connection"); sql_disconnect(conn); conn->state = state_disabled; break; default: - dbrw_error("query failed: %s", mysql_error(mp->mysql)); + dbrw_error("query failed: %s", mysql_error(&mp->mysql)); } } @@ -88,7 +88,6 @@ s_mysql_destroy(struct dbrw_connection *conn) { struct vmod_mysql_data *mp = conn->data; free(mp->buffer); - free(mp->mysql); free(mp); conn->data = NULL; } @@ -102,14 +101,7 @@ s_mysql_connect(struct dbrw_connection *conn) char *s; int port = 0; - mp->mysql = malloc(sizeof(MYSQL)); - if (!mp->mysql) { - dbrw_error("not enough memory"); - conn->state = state_disabled; - return -1; - } - - mysql_init(mp->mysql); + mysql_init(&mp->mysql); host = findparam(conn->conf->param, "server"); if (host && host[0] == '/') { @@ -123,17 +115,17 @@ s_mysql_connect(struct dbrw_connection *conn) s = findparam(conn->conf->param, "config"); if (s) - mysql_options(mp->mysql, MYSQL_READ_DEFAULT_FILE, s); + mysql_options(&mp->mysql, MYSQL_READ_DEFAULT_FILE, s); s = findparam(conn->conf->param, "group"); if (s) - mysql_options(mp->mysql, MYSQL_READ_DEFAULT_GROUP, s); + mysql_options(&mp->mysql, MYSQL_READ_DEFAULT_GROUP, s); s = findparam(conn->conf->param, "cacert"); if (s) - mysql_ssl_set(mp->mysql, NULL, NULL, s, NULL, NULL); + mysql_ssl_set(&mp->mysql, NULL, NULL, s, NULL, NULL); debug(conn->conf, 1, ("connecting to database")); - if (!mysql_real_connect(mp->mysql, + if (!mysql_real_connect(&mp->mysql, host, findparam(conn->conf->param, "user"), findparam(conn->conf->param, "password"), @@ -141,7 +133,7 @@ s_mysql_connect(struct dbrw_connection *conn) port, socket_name, CLIENT_MULTI_RESULTS)) { - dbrw_error("cannot connect: %s", mysql_error(mp->mysql)); + dbrw_error("cannot connect: %s", mysql_error(&mp->mysql)); return -1; } debug(conn->conf, 1, ("connected to database")); @@ -153,7 +145,7 @@ static int s_mysql_disconnect(struct dbrw_connection *conn) { struct vmod_mysql_data *mp = conn->data; - mysql_close(mp->mysql); + mysql_close(&mp->mysql); return 0; } @@ -166,8 +158,7 @@ s_mysql_query(struct dbrw_connection *conn, const char *query) MYSQL *mysql; for (i = 0; i < 10; i++) { - mysql = mp->mysql; - rc = mysql_query(mysql, query); + rc = mysql_query(&mp->mysql, query); if (rc) { check_errno(conn); if (conn->state != state_init) @@ -177,13 +168,13 @@ s_mysql_query(struct dbrw_connection *conn, const char *query) return -1; continue; } - mp->result = mysql_store_result(mp->mysql); + mp->result = mysql_store_result(&mp->mysql); if (mp->result) { conn->state = state_result; rc = 0; - } else if (mysql_field_count(mp->mysql)) { + } else if (mysql_field_count(&mp->mysql)) { dbrw_error("cannot store result: %s", - mysql_error(mp->mysql)); + mysql_error(&mp->mysql)); conn->state = state_error; rc = 1; } else @@ -267,7 +258,7 @@ s_mysql_escape (struct dbrw_connection *conn, const char *arg) mp->bufsize = size; } - mysql_real_escape_string(mp->mysql, mp->buffer, arg, len); + mysql_real_escape_string(&mp->mysql, mp->buffer, arg, len); p = strdup(mp->buffer); if (!p) @@ -275,6 +266,26 @@ s_mysql_escape (struct dbrw_connection *conn, const char *arg) return p; } +static int +s_mysql_idle_timeout(struct dbrw_connection *conn) +{ + const char *res; + int n; + if (sql_connect(conn) || conn->state != state_connected) + return -1; + if (sql_query(conn, + "SHOW VARIABLES WHERE Variable_name = 'wait_timeout'")) + return -1; + res = sql_get_column(conn, 0, 1); + if (res) + n = atoi(res); + else + n = -1; + sql_free_result(conn); + return n; +} + + struct dbrw_backend mysql_backend = { "mysql", s_mysql_init, @@ -286,5 +297,6 @@ struct dbrw_backend mysql_backend = { s_mysql_num_tuples, s_mysql_num_fields, s_mysql_free_result, - s_mysql_get_column + s_mysql_get_column, + s_mysql_idle_timeout }; @@ -1,5 +1,5 @@ /* This file is part of vmod-dbrw - Copyright (C) 2013-2014 Sergey Poznyakoff + Copyright (C) 2013-2018 Sergey Poznyakoff Vmod-dbrw is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -143,6 +143,7 @@ sql_query(struct dbrw_connection *conn, const char *input) return 1; } } while (conn->state != state_connected); + conn->timestamp = time(NULL); if (conn->conf->backend->sql_query(conn, input) == 0) return 0; return 1; @@ -185,3 +186,11 @@ sql_get_column(struct dbrw_connection *conn, unsigned row, unsigned col) return conn->conf->backend->sql_get_column(conn, row, col); } +int +sql_idle_timeout(struct dbrw_connection *conn) +{ + CONN_ASSERT_VAL(conn, -1); + if (!conn->conf->backend->sql_idle_timeout) + return -1; + return conn->conf->backend->sql_idle_timeout(conn); +} diff --git a/src/vmod_dbrw.c b/src/vmod_dbrw.c index b6fe70c..d6785d7 100644 --- a/src/vmod_dbrw.c +++ b/src/vmod_dbrw.c @@ -1,5 +1,5 @@ /* This file is part of vmod-dbrw - Copyright (C) 2013-2017 Sergey Poznyakoff + Copyright (C) 2013-2018 Sergey Poznyakoff Vmod-dbrw is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -76,8 +76,20 @@ dbrw_connection_get(struct dbrw_config *cfg) cp = NULL; } else VTAILQ_INSERT_HEAD(&connect_pool, cp, list); + } else if (cp->state == state_connected + && cfg->idle_timeout >= 0 + && cp->timestamp + cfg->idle_timeout < time(NULL)) { + sql_disconnect(cp); } + cp->busy = 1; + + if (cfg->idle_timeout == -2) { + cfg->idle_timeout = sql_idle_timeout(cp); + if (cfg->idle_timeout < -1) + cfg->idle_timeout = -1; + } + pthread_mutex_unlock(&connect_pool_mtx); return cp; } @@ -189,7 +201,7 @@ parse_flags(const char *arg, int *qdisp, int *flags, char status[]) strncpy(status, ws.ws_wordv[i] + 2, HTTP_STATUS_LEN); } else { - dbrw_error("unrecognized flag: %s", ws.ws_wordv[i]); + dbrw_error("unrecognized flag: %s", ws.ws_wordv[i]); rc = 1; } } @@ -200,14 +212,7 @@ parse_flags(const char *arg, int *qdisp, int *flags, char status[]) /* Configure the module. BACKEND - "mysql" or "pgsql" - PARAM - VAR=VALUE*: - db=S - port=N - socket=S - user=S - password=S - options=S - debug=N + PARAM - VAR=VALUE* QUERY - Query to obtain the redirection target */ VCL_VOID @@ -258,8 +263,13 @@ vmod_config(VRT_CTX, struct vmod_priv *priv, AN(conf->query); conf->backend = backend; - s = findparam(conf->param, "debug"); - conf->debug_level = s ? atoi(s) : 0; + if ((s = findparam(conf->param, "debug")) != NULL) + conf->debug_level = atoi(s); + + if ((s = findparam(conf->param, "timeout")) != NULL) + conf->idle_timeout = atoi(s); + else + conf->idle_timeout = -2; conf->qdisp = QDISP_NONE; conf->regflags = REG_EXTENDED; @@ -267,7 +277,9 @@ vmod_config(VRT_CTX, struct vmod_priv *priv, s = findparam(conf->param, "flags"); if (s) - parse_flags(s, &conf->qdisp, &conf->regflags, + parse_flags(s, + &conf->qdisp, + &conf->regflags, conf->status); AZ(pthread_mutex_lock(&config_pool_mtx)); |