On Thu, Feb 12, 2009 at 12:56 AM, Nick Kew <n...@webthing.com> wrote: > Sounds OK in principle for trunk. If you want to post a patch > against trunk, I'll try and find the time to review it.
Here I am again. The patch works well for us. Is there something else that I can do for now? -- Marko Kevac
diff -u trunk/mod_dbd.c mine/mod_dbd.c --- trunk/mod_dbd.c 2009-03-05 15:19:18.000000000 +0300 +++ mine/mod_dbd.c 2009-03-05 15:19:44.000000000 +0300 @@ -20,6 +20,8 @@ * http://apache.webthing.com/database/ */ +#define CORE_PRIVATE + #include "apr_reslist.h" #include "apr_strings.h" #include "apr_hash.h" @@ -46,8 +48,13 @@ #define NMAX_SET 0x4 #define EXPTIME_SET 0x8 +#define DEFAULT_POOL_COUNT 2 + +#define DBD_DEFAULT_POOL_NAME "dbd_default_pool" + typedef struct { server_rec *server; + const char *pool_name; const char *name; const char *params; int persist; @@ -59,6 +66,7 @@ int set; #endif apr_hash_t *queries; + apr_hash_t *init_queries; } dbd_cfg_t; typedef struct dbd_group_t dbd_group_t; @@ -77,8 +85,8 @@ }; typedef struct { - dbd_cfg_t *cfg; - dbd_group_t *group; + apr_hash_t *cfgs; + apr_hash_t *groups; } svr_cfg; typedef enum { cmd_name, cmd_params, cmd_persist, @@ -102,79 +110,145 @@ static void *create_dbd_config(apr_pool_t *pool, server_rec *s) { svr_cfg *svr = apr_pcalloc(pool, sizeof(svr_cfg)); - dbd_cfg_t *cfg = svr->cfg = apr_pcalloc(pool, sizeof(dbd_cfg_t)); - cfg->server = s; - cfg->name = no_dbdriver; /* to generate meaningful error messages */ - cfg->params = ""; /* don't risk segfault on misconfiguration */ - cfg->persist = -1; -#if APR_HAS_THREADS - cfg->nmin = DEFAULT_NMIN; - cfg->nkeep = DEFAULT_NKEEP; - cfg->nmax = DEFAULT_NMAX; - cfg->exptime = DEFAULT_EXPTIME; -#endif - cfg->queries = apr_hash_make(pool); + svr->cfgs = apr_hash_make(pool); + svr->groups = apr_hash_make(pool); return svr; } -static void *merge_dbd_config(apr_pool_t *pool, void *basev, void *addv) +DBD_DECLARE_NONSTD(void) ap_dbd_sql_init(server_rec *s, const char *pool_name, + const char *query, const char *label) { - dbd_cfg_t *base = ((svr_cfg*) basev)->cfg; - dbd_cfg_t *add = ((svr_cfg*) addv)->cfg; - svr_cfg *svr = apr_pcalloc(pool, sizeof(svr_cfg)); - dbd_cfg_t *new = svr->cfg = apr_pcalloc(pool, sizeof(dbd_cfg_t)); + svr_cfg *svr; + dbd_cfg_t *cfg = NULL; - new->server = add->server; - new->name = (add->name != no_dbdriver) ? add->name : base->name; - new->params = strcmp(add->params, "") ? add->params : base->params; - new->persist = (add->persist != -1) ? add->persist : base->persist; -#if APR_HAS_THREADS - new->nmin = (add->set&NMIN_SET) ? add->nmin : base->nmin; - new->nkeep = (add->set&NKEEP_SET) ? add->nkeep : base->nkeep; - new->nmax = (add->set&NMAX_SET) ? add->nmax : base->nmax; - new->exptime = (add->set&EXPTIME_SET) ? add->exptime : base->exptime; -#endif - new->queries = apr_hash_overlay(pool, add->queries, base->queries); + svr = ap_get_module_config(s->module_config, &dbd_module); + if (!svr) { + /* some modules may call from within config directive handlers, and + * if these are called in a server context that contains no mod_dbd + * config directives, then we have to create our own server config + */ + svr = create_dbd_config(config_pool, s); + ap_set_module_config(s->module_config, &dbd_module, svr); + } - return svr; + cfg = apr_hash_get(svr->cfgs, pool_name, APR_HASH_KEY_STRING); + if (NULL == cfg) { + ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, + "could not found dbd configuration for pool %s", pool_name); + return; + } + + if (apr_hash_get(cfg->init_queries, label, APR_HASH_KEY_STRING) + && strcmp(query, "")) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "conflicting SQL statements with label %s", label); + } + + apr_hash_set(cfg->init_queries, label, APR_HASH_KEY_STRING, query); +} + +static const char *dbd_pool(cmd_parms *cmd, void *mconfig, const char *arg) +{ + const char *errmsg = NULL; + const char *endp = ap_strrchr_c(arg, '>'); + + dbd_cfg_t *conf; + + ap_conf_vector_t *new_dir_conf = ap_create_per_dir_config(cmd->pool); + + const char *err = ap_check_cmd_context(cmd, + NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); + + if (err != NULL) { + return err; + } + + if (endp == NULL) { + return apr_pstrcat(cmd->pool, cmd->cmd->name, + "> directive missing closing '>'", NULL); + } + + arg = apr_pstrndup(cmd->pool, arg, endp - arg); + + /* initialize our config and fetch it */ + conf = ap_set_config_vectors(cmd->server, new_dir_conf, arg, + &dbd_module, cmd->pool); + + errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_dir_conf); + if (errmsg != NULL) + return errmsg; + + return NULL; } static const char *dbd_param(cmd_parms *cmd, void *dconf, const char *val) { const apr_dbd_driver_t *driver = NULL; svr_cfg *svr = ap_get_module_config(cmd->server->module_config, - &dbd_module); - dbd_cfg_t *cfg = svr->cfg; + &dbd_module); + dbd_cfg_t *cfg = NULL; - switch ((long) cmd->info) { - case cmd_name: - cfg->name = val; - /* loading the driver involves once-only dlloading that is - * best done at server startup. This also guarantees that - * we won't return an error later. + char *name = NULL; + char *word = NULL; + + if (cmd->directive->parent && + strncasecmp(cmd->directive->parent->directive, + "<DBDPool", 8) == 0) { + const char *pargs = cmd->directive->parent->args; + /* Directive inside <DBDPool section + * Parent directive arg is the dbd pool name. */ - switch (apr_dbd_get_driver(cmd->pool, cfg->name, &driver)) { - case APR_ENOTIMPL: - return apr_psprintf(cmd->pool, "DBD: No driver for %s", cfg->name); - case APR_EDSOOPEN: - return apr_psprintf(cmd->pool, + name = ap_getword_conf(cmd->pool, &pargs); + if ((word = ap_strchr(name, '>'))) + *word = '\0'; + } else { + name = DBD_DEFAULT_POOL_NAME; + } + + cfg = apr_hash_get(svr->cfgs, name, APR_HASH_KEY_STRING); + if (NULL == cfg) { + cfg = apr_palloc(cmd->pool, sizeof(*cfg)); + apr_hash_set(svr->cfgs, name, APR_HASH_KEY_STRING, cfg); + cfg->pool_name = name; + cfg->nmax = DEFAULT_NMAX; + cfg->nmin = DEFAULT_NMIN; + cfg->nkeep = DEFAULT_NKEEP; + cfg->exptime = DEFAULT_EXPTIME; + cfg->server = cmd->server; + cfg->queries = apr_hash_make(cmd->pool); + cfg->init_queries = apr_hash_make(cmd->pool); + } + + switch ((long) cmd->info) { + case cmd_name: + cfg->name = val; + /* loading the driver involves once-only dlloading that is + * best done at server startup. This also guarantees that + * we won't return an error later. + */ + switch (apr_dbd_get_driver(cmd->pool, cfg->name, &driver)) { + case APR_ENOTIMPL: + return apr_psprintf(cmd->pool, "DBD: No driver for %s", + cfg->name); + case APR_EDSOOPEN: + return apr_psprintf(cmd->pool, #ifdef NETWARE - "DBD: Can't load driver file dbd%s.nlm", + "DBD: Can't load driver file dbd%s.nlm", #else - "DBD: Can't load driver file apr_dbd_%s.so", + "DBD: Can't load driver file apr_dbd_%s.so", #endif - cfg->name); - case APR_ESYMNOTFOUND: - return apr_psprintf(cmd->pool, - "DBD: Failed to load driver apr_dbd_%s_driver", - cfg->name); - } - break; - case cmd_params: - cfg->params = val; - break; + cfg->name); + case APR_ESYMNOTFOUND: + return apr_psprintf(cmd->pool, + "DBD: Failed to load driver apr_dbd_%s_driver", + cfg->name); + } + break; + case cmd_params: + cfg->params = val; + break; } return NULL; @@ -185,9 +259,41 @@ { svr_cfg *svr = ap_get_module_config(cmd->server->module_config, &dbd_module); - dbd_cfg_t *cfg = svr->cfg; + dbd_cfg_t *cfg; + + char *name = NULL; + char *word = NULL; + const char *p; + if (cmd->directive->parent && + strncasecmp(cmd->directive->parent->directive, + "<DBDPool", 8) == 0) { + const char *pargs = cmd->directive->parent->args; + /* Directive inside <DBDPool section + * Parent directive arg is the dbd pool name. + */ + name = ap_getword_conf(cmd->pool, &pargs); + if ((word = ap_strchr(name, '>'))) + *word = '\0'; + } else { + name = DBD_DEFAULT_POOL_NAME; + } + + cfg = apr_hash_get(svr->cfgs, name, APR_HASH_KEY_STRING); + if (NULL == cfg) { + cfg = apr_palloc(cmd->pool, sizeof(*cfg)); + apr_hash_set(svr->cfgs, name, APR_HASH_KEY_STRING, cfg); + cfg->pool_name = name; + cfg->nmax = DEFAULT_NMAX; + cfg->nmin = DEFAULT_NMIN; + cfg->nkeep = DEFAULT_NKEEP; + cfg->exptime = DEFAULT_EXPTIME; + cfg->server = cmd->server; + cfg->queries = apr_hash_make(cmd->pool); + cfg->init_queries = apr_hash_make(cmd->pool); + } + for (p = val; *p; ++p) { if (!apr_isdigit(*p)) { return "Argument must be numeric!"; @@ -195,22 +301,22 @@ } switch ((long) cmd->info) { - case cmd_min: - cfg->nmin = atoi(val); - cfg->set |= NMIN_SET; - break; - case cmd_keep: - cfg->nkeep = atoi(val); - cfg->set |= NKEEP_SET; - break; - case cmd_max: - cfg->nmax = atoi(val); - cfg->set |= NMAX_SET; - break; - case cmd_exp: - cfg->exptime = atoi(val); - cfg->set |= EXPTIME_SET; - break; + case cmd_min: + cfg->nmin = atoi(val); + cfg->set |= NMIN_SET; + break; + case cmd_keep: + cfg->nkeep = atoi(val); + cfg->set |= NKEEP_SET; + break; + case cmd_max: + cfg->nmax = atoi(val); + cfg->set |= NMAX_SET; + break; + case cmd_exp: + cfg->exptime = atoi(val); + cfg->set |= EXPTIME_SET; + break; } return NULL; @@ -220,12 +326,37 @@ static const char *dbd_param_flag(cmd_parms *cmd, void *dconf, int flag) { svr_cfg *svr = ap_get_module_config(cmd->server->module_config, - &dbd_module); + &dbd_module); + dbd_cfg_t *cfg = NULL; + + char *word = NULL; + char *name = NULL; + + if (cmd->directive->parent && + strncasecmp(cmd->directive->parent->directive, + "<DBDPool", 8) == 0) { + const char *pargs = cmd->directive->parent->args; + /* Directive inside <DBDPool section + * Parent directive arg is the dbd pool name. + */ + name = ap_getword_conf(cmd->temp_pool, &pargs); + if ((word = ap_strchr(name, '>'))) + *word = '\0'; + } else { + return apr_psprintf(cmd->pool, + "DBD: %s should be inside <DBDPool >", cmd->cmd->name); + } + + cfg = apr_hash_get(svr->cfgs, name, APR_HASH_KEY_STRING); + if (NULL == cfg) { + cfg = apr_palloc(cmd->pool, sizeof(*cfg)); + apr_hash_set(svr->cfgs, name, APR_HASH_KEY_STRING, cfg); + } switch ((long) cmd->info) { - case cmd_persist: - svr->cfg->persist = flag; - break; + case cmd_persist: + cfg->persist = flag; + break; } return NULL; @@ -234,17 +365,68 @@ static const char *dbd_prepare(cmd_parms *cmd, void *dconf, const char *query, const char *label) { + char *word = NULL; + char *name = NULL; + + if (cmd->directive->parent && + strncasecmp(cmd->directive->parent->directive, + "<DBDPool", 8) == 0) { + const char *pargs = cmd->directive->parent->args; + /* Directive inside <DBDPool section + * Parent directive arg is the dbd pool name. + */ + name = ap_getword_conf(cmd->temp_pool, &pargs); + if ((word = ap_strchr(name, '>'))) + *word = '\0'; + } else { + return apr_psprintf(cmd->pool, + "DBD: %s should be inside <DBDPool >", cmd->cmd->name); + } + if (!label) { label = query; query = ""; } - ap_dbd_prepare(cmd->server, query, label); + ap_dbd_prepare_pool(cmd->server, name, query, label); + + return NULL; +} + +static const char *dbd_init_sql(cmd_parms *cmd, void *dconf, const char *query, + const char *label) +{ + char *word = NULL; + char *name = NULL; + + if (cmd->directive->parent && + strncasecmp(cmd->directive->parent->directive, + "<DBDPool", 8) == 0) { + const char *pargs = cmd->directive->parent->args; + /* Directive inside <DBDPool section + * Parent directive arg is the dbd pool name. + */ + name = ap_getword_conf(cmd->temp_pool, &pargs); + if ((word = ap_strchr(name, '>'))) + *word = '\0'; + } else { + return apr_psprintf(cmd->pool, + "DBD: %s should be inside <DBDPool >", cmd->cmd->name); + } + + if (!label) { + label = query; + query = ""; + } + + ap_dbd_sql_init(cmd->server, name, query, label); return NULL; } static const command_rec dbd_cmds[] = { + AP_INIT_RAW_ARGS("<DBDPool", dbd_pool, NULL, RSRC_CONF, + "Container for pool configuration"), AP_INIT_TAKE1("DBDriver", dbd_param, (void*)cmd_name, RSRC_CONF, "SQL Driver"), AP_INIT_TAKE1("DBDParams", dbd_param, (void*)cmd_params, RSRC_CONF, @@ -254,6 +436,8 @@ AP_INIT_TAKE12("DBDPrepareSQL", dbd_prepare, NULL, RSRC_CONF, "SQL statement to prepare (or nothing, to override " "statement inherited from main server) and label"), + AP_INIT_TAKE12("DBDInitSQL", dbd_init_sql, NULL, RSRC_CONF, + "SQL statement to be executed after connection is created"), #if APR_HAS_THREADS AP_INIT_TAKE1("DBDMin", dbd_param_int, (void*)cmd_min, RSRC_CONF, "Minimum number of connections"), @@ -277,10 +461,11 @@ return OK; } -DBD_DECLARE_NONSTD(void) ap_dbd_prepare(server_rec *s, const char *query, - const char *label) +DBD_DECLARE_NONSTD(void) ap_dbd_prepare_pool(server_rec *s, const char *pool_name, + const char *query, const char *label) { svr_cfg *svr; + dbd_cfg_t *cfg = NULL; svr = ap_get_module_config(s->module_config, &dbd_module); if (!svr) { @@ -292,13 +477,25 @@ ap_set_module_config(s->module_config, &dbd_module, svr); } - if (apr_hash_get(svr->cfg->queries, label, APR_HASH_KEY_STRING) + cfg = apr_hash_get(svr->cfgs, pool_name, APR_HASH_KEY_STRING); + if (NULL == cfg) { + ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, + "could not found dbd configuration for pool %s", pool_name); + return; + } + + if (apr_hash_get(cfg->queries, label, APR_HASH_KEY_STRING) && strcmp(query, "")) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, - "conflicting SQL statements with label %s", label); + "conflicting SQL statements with label %s", label); } - apr_hash_set(svr->cfg->queries, label, APR_HASH_KEY_STRING, query); + apr_hash_set(cfg->queries, label, APR_HASH_KEY_STRING, query); +} + +DBD_DECLARE_NONSTD(void) ap_dbd_prepare(server_rec *s, const char *query, const char *label) +{ + ap_dbd_prepare_pool(s, DBD_DEFAULT_POOL_NAME, query, label); } typedef struct { @@ -309,89 +506,46 @@ apr_pool_t *ptemp, server_rec *s) { server_rec *sp; - apr_array_header_t *add_queries = apr_array_make(ptemp, 10, - sizeof(dbd_query_t)); for (sp = s; sp; sp = sp->next) { svr_cfg *svr = ap_get_module_config(sp->module_config, &dbd_module); - dbd_cfg_t *cfg = svr->cfg; - apr_hash_index_t *hi_first = apr_hash_first(ptemp, cfg->queries); - dbd_group_t *group; - - /* dbd_setup in 2.2.3 and under was causing spurious error messages - * when dbd isn't configured. We can stop that with a quick check here - * together with a similar check in ap_dbd_open (where being - * unconfigured is a genuine error that must be reported). - */ - if (cfg->name == no_dbdriver || !cfg->persist) { - continue; - } + apr_hash_index_t *hi; - for (group = group_list; group; group = group->next) { - dbd_cfg_t *group_cfg = group->cfg; - apr_hash_index_t *hi; - int group_ok = 1; + for (hi = apr_hash_first(ptemp, svr->cfgs); + hi; hi = apr_hash_next(hi)) { + dbd_cfg_t *cfg; + dbd_group_t *group; - if (strcmp(cfg->name, group_cfg->name) - || strcmp(cfg->params, group_cfg->params)) { - continue; - } + apr_hash_this(hi, NULL, NULL, (void*)&cfg); -#if APR_HAS_THREADS - if (cfg->nmin != group_cfg->nmin - || cfg->nkeep != group_cfg->nkeep - || cfg->nmax != group_cfg->nmax - || cfg->exptime != group_cfg->exptime) { + if (!cfg->persist) { continue; } -#endif - - add_queries->nelts = 0; - - for (hi = hi_first; hi; hi = apr_hash_next(hi)) { - const char *label, *query; - const char *group_query; - - apr_hash_this(hi, (void*) &label, NULL, (void*) &query); - group_query = apr_hash_get(group_cfg->queries, label, - APR_HASH_KEY_STRING); + for (group = group_list; group; group = group->next) { + dbd_cfg_t *group_cfg = group->cfg; - if (!group_query) { - dbd_query_t *add_query = apr_array_push(add_queries); - - add_query->label = label; - add_query->query = query; - } - else if (strcmp(query, group_query)) { - group_ok = 0; - break; - } - } - - if (group_ok) { - int i; - - for (i = 0; i < add_queries->nelts; ++i) { - dbd_query_t *add_query = ((dbd_query_t*) add_queries->elts) - + i; - - apr_hash_set(group_cfg->queries, add_query->label, - APR_HASH_KEY_STRING, add_query->query); + if (strcmp(cfg->pool_name, group_cfg->pool_name)) { + continue; } - svr->group = group; + apr_hash_set(svr->groups, cfg->pool_name, + APR_HASH_KEY_STRING, group); break; } - } - if (!svr->group) { - svr->group = group = apr_pcalloc(pconf, sizeof(dbd_group_t)); + if (NULL == apr_hash_get(svr->groups, cfg->pool_name, + APR_HASH_KEY_STRING)) { + group = apr_pcalloc(pconf, sizeof(dbd_group_t)); + + group->cfg = cfg; - group->cfg = cfg; + group->next = group_list; + group_list = group; - group->next = group_list; - group_list = group; + apr_hash_set(svr->groups, cfg->pool_name, + APR_HASH_KEY_STRING, group); + } } } @@ -430,6 +584,33 @@ return rv; } +static apr_status_t dbd_init_sql_init(apr_pool_t *pool, dbd_cfg_t *cfg, + ap_dbd_t *rec) +{ + apr_hash_index_t *hi; + apr_status_t rv = APR_SUCCESS; + + for (hi = apr_hash_first(pool, cfg->init_queries); hi; + hi = apr_hash_next(hi)) { + int nrows; + const char *label, *query; + apr_dbd_prepared_t *stmt; + + apr_hash_this(hi, (void*) &label, NULL, (void*) &query); + + if (!strcmp(query, "")) { + continue; + } + + stmt = NULL; + if (apr_dbd_query(rec->driver, rec->handle, &nrows, query)) { + rv = APR_EGENERAL; + } + } + + return rv; +} + static apr_status_t dbd_close(void *data) { ap_dbd_t *rec = data; @@ -464,7 +645,6 @@ apr_pool_t *rec_pool, *prepared_pool; ap_dbd_t *rec; apr_status_t rv; - const char *err = ""; rv = apr_pool_create(&rec_pool, pool); if (rv != APR_SUCCESS) { @@ -508,12 +688,12 @@ return rv; } - rv = apr_dbd_open_ex(rec->driver, rec->pool, cfg->params, &rec->handle, &err); + rv = apr_dbd_open(rec->driver, rec->pool, cfg->params, &rec->handle); if (rv != APR_SUCCESS) { switch (rv) { case APR_EGENERAL: ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server, - "DBD: Can't connect to %s: %s", cfg->name, err); + "DBD: Can't connect to %s", cfg->name); break; default: ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server, @@ -551,6 +731,17 @@ return rv; } + rv = dbd_init_sql_init(prepared_pool, cfg, rec); + if (rv != APR_SUCCESS) { + const char *errmsg = apr_dbd_error(rec->driver, rec->handle, rv); + ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server, + "DBD: failed to execute init SQL statements: %s", + (errmsg ? errmsg : "[???]")); + + apr_pool_destroy(rec->pool); + return rv; + } + *data_ptr = rec; return APR_SUCCESS; @@ -649,11 +840,11 @@ static void dbd_child_init(apr_pool_t *p, server_rec *s) { - apr_status_t rv = dbd_setup_init(p, s); - if (rv) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, - "DBD: child init failed!"); - } + apr_status_t rv = dbd_setup_init(p, s); + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, + "DBD: child init failed!"); + } } #if APR_HAS_THREADS @@ -697,23 +888,34 @@ - open acquires a connection from the pool (opens one if necessary) - close releases it back in to the pool */ -DBD_DECLARE_NONSTD(void) ap_dbd_close(server_rec *s, ap_dbd_t *rec) +DBD_DECLARE_NONSTD(void) ap_dbd_close_pool(server_rec *s, ap_dbd_t *rec, + const char *pool_name) { + dbd_group_t *group = NULL; svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module); - if (!svr->cfg->persist) { + group = apr_hash_get(svr->groups, pool_name, APR_HASH_KEY_STRING); + + if (!group->cfg->persist) { apr_pool_destroy(rec->pool); } #if APR_HAS_THREADS else { - apr_reslist_release(svr->group->reslist, rec); + apr_reslist_release(group->reslist, rec); } #endif } -static apr_status_t dbd_check(apr_pool_t *pool, server_rec *s, ap_dbd_t *rec) +DBD_DECLARE_NONSTD(void) ap_dbd_close(server_rec *s, ap_dbd_t *rec) { - svr_cfg *svr; + return ap_dbd_close_pool(s, rec, DBD_DEFAULT_POOL_NAME); +} + +static apr_status_t dbd_check(apr_pool_t *pool, server_rec *s, ap_dbd_t *rec, + const char *pool_name) +{ + svr_cfg *svr = NULL; + dbd_group_t *group = NULL; apr_status_t rv = apr_dbd_check_conn(rec->driver, pool, rec->handle); const char *errmsg; @@ -730,26 +932,32 @@ } svr = ap_get_module_config(s->module_config, &dbd_module); + if (!svr) + return -1; + group = apr_hash_get(svr->groups, pool_name, APR_HASH_KEY_STRING); ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, - "DBD [%s] Error: %s", svr->cfg->name, errmsg); + "DBD [%s] Error: %s", group->cfg->name, errmsg); return rv; } -DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open(apr_pool_t *pool, server_rec *s) +DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open_pool(apr_pool_t *pool, server_rec *s, + const char *pool_name) { svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module); - dbd_group_t *group = svr->group; - dbd_cfg_t *cfg = svr->cfg; + dbd_group_t *group = NULL; + dbd_cfg_t *cfg = NULL; ap_dbd_t *rec = NULL; #if APR_HAS_THREADS apr_status_t rv; #endif - /* If nothing is configured, we shouldn't be here */ - if (cfg->name == no_dbdriver) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "DBD: not configured"); + group = apr_hash_get(svr->groups, pool_name, APR_HASH_KEY_STRING); + if (NULL == group) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "DBD: %s pool is not configured", pool_name); return NULL; } + cfg = group->cfg; if (!cfg->persist) { /* Return a once-only connection */ @@ -775,9 +983,18 @@ return NULL; } - if (dbd_check(pool, s, rec) != APR_SUCCESS) { + if (dbd_check(pool, s, rec, pool_name) != APR_SUCCESS) { apr_reslist_invalidate(group->reslist, rec); - return NULL; + + /* Problem is often connected with server timeout. + * So create new connection + */ + rv = apr_reslist_acquire(group->reslist, (void*) &rec); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Failed to acquire DBD connection from pool!"); + return NULL; + } } #else /* If we have a persistent connection and it's good, we'll use it; @@ -785,7 +1002,7 @@ */ rec = group->rec; if (rec) { - if (dbd_check(pool, s, rec) != APR_SUCCESS) { + if (dbd_check(pool, s, rec, pool_name) != APR_SUCCESS) { apr_pool_destroy(rec->pool); rec = NULL; } @@ -801,12 +1018,21 @@ return rec; } +DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open(apr_pool_t *pool, server_rec *s) +{ + return ap_dbd_open_pool(pool, s, DBD_DEFAULT_POOL_NAME); +} + #if APR_HAS_THREADS typedef struct { ap_dbd_t *rec; apr_reslist_t *reslist; } dbd_acquire_t; +typedef struct { + apr_hash_t *list; +} dbd_acquire_list_t; + static apr_status_t dbd_release(void *data) { dbd_acquire_t *acq = data; @@ -814,9 +1040,11 @@ return APR_SUCCESS; } -DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r) +DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire_pool(request_rec *r, + const char *pool_name) { - dbd_acquire_t *acq; + dbd_acquire_list_t *acq_list; + dbd_acquire_t *acq = NULL; while (!ap_is_initial_req(r)) { if (r->prev) { @@ -827,52 +1055,88 @@ } } - acq = ap_get_module_config(r->request_config, &dbd_module); + acq_list = ap_get_module_config(r->request_config, &dbd_module); + if (!acq_list) { + acq_list = apr_palloc(r->pool, sizeof(dbd_acquire_list_t)); + acq_list->list = apr_hash_make(r->pool); + ap_set_module_config(r->request_config, &dbd_module, acq_list); + } + + acq = apr_hash_get(acq_list->list, pool_name, + APR_HASH_KEY_STRING); if (!acq) { + dbd_group_t *group = NULL; + svr_cfg *svr = ap_get_module_config(r->server->module_config, + &dbd_module); + acq = apr_palloc(r->pool, sizeof(dbd_acquire_t)); - acq->rec = ap_dbd_open(r->pool, r->server); - if (acq->rec) { - svr_cfg *svr = ap_get_module_config(r->server->module_config, - &dbd_module); - ap_set_module_config(r->request_config, &dbd_module, acq); - if (svr->cfg->persist) { - acq->reslist = svr->group->reslist; - apr_pool_cleanup_register(r->pool, acq, dbd_release, - apr_pool_cleanup_null); - } + acq->rec = ap_dbd_open_pool(r->pool, r->server, pool_name); + if (!acq->rec) { + return NULL; + } + + apr_hash_set(acq_list->list, pool_name, APR_HASH_KEY_STRING, acq); + + group = apr_hash_get(svr->groups, pool_name, + APR_HASH_KEY_STRING); + if (group->cfg->persist) { + acq->reslist = group->reslist; + apr_pool_cleanup_register(r->pool, acq, dbd_release, + apr_pool_cleanup_null); } } return acq->rec; } -DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c) +DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire_pool(conn_rec *c, + const char *pool_name) { - dbd_acquire_t *acq = ap_get_module_config(c->conn_config, &dbd_module); + dbd_acquire_list_t *acq_list = + ap_get_module_config(c->conn_config, &dbd_module); + dbd_acquire_t *acq = NULL; - if (!acq) { + if (!acq_list) { + acq_list = apr_palloc(c->pool, sizeof(dbd_acquire_list_t)); acq = apr_palloc(c->pool, sizeof(dbd_acquire_t)); - acq->rec = ap_dbd_open(c->pool, c->base_server); + + apr_hash_set(acq_list->list, pool_name, APR_HASH_KEY_STRING, acq); + + acq->rec = ap_dbd_open_pool(c->pool, c->base_server, pool_name); if (acq->rec) { + dbd_group_t *group = NULL; svr_cfg *svr = ap_get_module_config(c->base_server->module_config, &dbd_module); ap_set_module_config(c->conn_config, &dbd_module, acq); - if (svr->cfg->persist) { - acq->reslist = svr->group->reslist; + group = apr_hash_get(svr->groups, pool_name, + APR_HASH_KEY_STRING); + if (group->cfg->persist) { + acq->reslist = group->reslist; apr_pool_cleanup_register(c->pool, acq, dbd_release, apr_pool_cleanup_null); } } } + if (NULL == acq) { + acq = apr_hash_get(acq_list->list, pool_name, + APR_HASH_KEY_STRING); + } + return acq->rec; } #else -DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r) +typedef struct { + apr_hash_t *list; +} dbd_acquire_list_t; + +DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire_pool(request_rec *r, + const char *pool_name) { - ap_dbd_t *rec; + dbd_acquire_list_t *rec_list; + ap_dbd_t *rec = NULL; while (!ap_is_initial_req(r)) { if (r->prev) { @@ -883,32 +1147,58 @@ } } - rec = ap_get_module_config(r->request_config, &dbd_module); - if (!rec) { - rec = ap_dbd_open(r->pool, r->server); + rec_list = ap_get_module_config(r->request_config, &dbd_module); + if (!rec_list) { + rec_list = apr_palloc(r->pool, sizeof(dbd_acquire_list_t)); + rec = ap_dbd_open_pool(r->pool, r->server, pool_name); if (rec) { - ap_set_module_config(r->request_config, &dbd_module, rec); + apr_hash_set(rec_list, pool_name, APR_HASH_KEY_STRING, + rec); + ap_set_module_config(r->request_config, &dbd_module, rec_list); } } + if (NULL == rec) { + rec = apr_hash_get(rec_list, pool_name, APR_HASH_KEY_STRING); + } + return rec; } -DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c) +DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire_pool(conn_rec *c, + const char *pool_name) { - ap_dbd_t *rec = ap_get_module_config(c->conn_config, &dbd_module); + dbd_acquire_list_t *rec_list = + ap_get_module_config(c->conn_config, &dbd_module); + ap_dbd_t *rec = NULL; - if (!rec) { - rec = ap_dbd_open(c->pool, c->base_server); + if (!rec_list) { + rec_list = apr_palloc(c->pool, sizeof(dbd_acquire_list_t)); + rec = ap_dbd_open_pool(c->pool, c->base_server, pool_name); if (rec) { ap_set_module_config(c->conn_config, &dbd_module, rec); + apr_hash_set(rec_list, pool_name, APR_HASH_KEY_STRING, rec); } } + if (NULL == rec) { + rec = apr_hash_get(rec_list, pool_name, APR_HASH_KEY_STRING); + } + return rec; } #endif +DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r) +{ + return ap_dbd_acquire_pool(r, DBD_DEFAULT_POOL_NAME); +} + +DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c) +{ + return ap_dbd_cacquire_pool(c, DBD_DEFAULT_POOL_NAME); +} + static void dbd_hooks(apr_pool_t *pool) { ap_hook_pre_config(dbd_pre_config, NULL, NULL, APR_HOOK_MIDDLE); @@ -916,10 +1206,15 @@ ap_hook_child_init(dbd_child_init, NULL, NULL, APR_HOOK_MIDDLE); APR_REGISTER_OPTIONAL_FN(ap_dbd_prepare); + APR_REGISTER_OPTIONAL_FN(ap_dbd_prepare_pool); APR_REGISTER_OPTIONAL_FN(ap_dbd_open); + APR_REGISTER_OPTIONAL_FN(ap_dbd_open_pool); APR_REGISTER_OPTIONAL_FN(ap_dbd_close); + APR_REGISTER_OPTIONAL_FN(ap_dbd_close_pool); APR_REGISTER_OPTIONAL_FN(ap_dbd_acquire); + APR_REGISTER_OPTIONAL_FN(ap_dbd_acquire_pool); APR_REGISTER_OPTIONAL_FN(ap_dbd_cacquire); + APR_REGISTER_OPTIONAL_FN(ap_dbd_cacquire_pool); apr_dbd_init(pool); } @@ -929,7 +1224,7 @@ NULL, NULL, create_dbd_config, - merge_dbd_config, + NULL, dbd_cmds, dbd_hooks }; diff -u trunk/mod_dbd.h mine/mod_dbd.h --- trunk/mod_dbd.h 2009-03-05 15:19:21.000000000 +0300 +++ mine/mod_dbd.h 2009-03-05 15:19:48.000000000 +0300 @@ -1,5 +1,4 @@ -/* Copyright 2003-5 WebThing Ltd - * Licensed to the Apache Software Foundation (ASF) under one or more +/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 @@ -69,34 +68,53 @@ /* acquire a connection that MUST be explicitly closed. * Returns NULL on error */ -DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open(apr_pool_t*, server_rec*); +DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open_pool(apr_pool_t *pool, server_rec *s, + const char *pool_name); +DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open(apr_pool_t *pool, server_rec *s); /* release a connection acquired with ap_dbd_open */ -DBD_DECLARE_NONSTD(void) ap_dbd_close(server_rec*, ap_dbd_t*); +DBD_DECLARE_NONSTD(void) ap_dbd_close_pool(server_rec *s, ap_dbd_t *dbd, + const char *pool_name); +DBD_DECLARE_NONSTD(void) ap_dbd_close(server_rec *s, ap_dbd_t *dbd); /* acquire a connection that will have the lifetime of a request * and MUST NOT be explicitly closed. Return NULL on error. * This is the preferred function for most applications. */ -DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_acquire(request_rec*); +DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_acquire_pool(request_rec *r, + const char *pool_name); +DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_acquire(request_rec *r); /* acquire a connection that will have the lifetime of a connection * and MUST NOT be explicitly closed. Return NULL on error. * This is the preferred function for most applications. */ -DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_cacquire(conn_rec*); +DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_cacquire_pool(conn_rec *c, + const char *pool_name); +DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_cacquire(conn_rec *c); /* Prepare a statement for use by a client module during * the server startup/configuration phase. Can't be called * after the server has created its children (use apr_dbd_*). */ -DBD_DECLARE_NONSTD(void) ap_dbd_prepare(server_rec*, const char*, const char*); +DBD_DECLARE_NONSTD(void) ap_dbd_prepare_pool(server_rec *s, const char *pool_name, + const char *query, const char *label); +DBD_DECLARE_NONSTD(void) ap_dbd_prepare(server_rec *s, const char *query, const char *label); /* Also export them as optional functions for modules that prefer it */ +APR_DECLARE_OPTIONAL_FN(ap_dbd_t*, ap_dbd_open_pool, (apr_pool_t*, server_rec*, const char*)); APR_DECLARE_OPTIONAL_FN(ap_dbd_t*, ap_dbd_open, (apr_pool_t*, server_rec*)); + +APR_DECLARE_OPTIONAL_FN(void, ap_dbd_close_pool, (server_rec*, ap_dbd_t*, const char*)); APR_DECLARE_OPTIONAL_FN(void, ap_dbd_close, (server_rec*, ap_dbd_t*)); + +APR_DECLARE_OPTIONAL_FN(ap_dbd_t*, ap_dbd_acquire_pool, (request_rec*, const char*)); APR_DECLARE_OPTIONAL_FN(ap_dbd_t*, ap_dbd_acquire, (request_rec*)); + +APR_DECLARE_OPTIONAL_FN(ap_dbd_t*, ap_dbd_cacquire_pool, (conn_rec*, const char*)); APR_DECLARE_OPTIONAL_FN(ap_dbd_t*, ap_dbd_cacquire, (conn_rec*)); + +APR_DECLARE_OPTIONAL_FN(void, ap_dbd_prepare_pool, (server_rec*, const char*, const char*, const char*)); APR_DECLARE_OPTIONAL_FN(void, ap_dbd_prepare, (server_rec*, const char*, const char*)); #endif