📄 mod_dbd.c
字号:
apr_status_t rv; rv = apr_pool_create(&rec_pool, pool); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, cfg->server, "DBD: Failed to create memory pool"); return rv; } rec = apr_pcalloc(rec_pool, sizeof(ap_dbd_t)); rec->pool = rec_pool; /* The driver is loaded at config time now, so this just checks a hash. * If that changes, the driver DSO could be registered to unload against * our pool, which is probably not what we want. Error checking isn't * necessary now, but in case that changes in the future ... */ rv = apr_dbd_get_driver(rec->pool, cfg->name, &rec->driver); if (rv != APR_SUCCESS) { switch (rv) { case APR_ENOTIMPL: ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server, "DBD: driver for %s not available", cfg->name); break; case APR_EDSOOPEN: ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server, "DBD: can't find driver for %s", cfg->name); break; case APR_ESYMNOTFOUND: ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server, "DBD: driver for %s is invalid or corrupted", cfg->name); break; default: ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server, "DBD: mod_dbd not compatible with APR in get_driver"); break; } apr_pool_destroy(rec->pool); return rv; } 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", cfg->name); break; default: ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server, "DBD: mod_dbd not compatible with APR in open"); break; } apr_pool_destroy(rec->pool); return rv; } apr_pool_cleanup_register(rec->pool, rec, dbd_close, apr_pool_cleanup_null); /* we use a sub-pool for the prepared statements for each connection so * that they will be cleaned up first, before the connection is closed */ rv = apr_pool_create(&prepared_pool, rec->pool); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, cfg->server, "DBD: Failed to create memory pool"); apr_pool_destroy(rec->pool); return rv; } rv = dbd_prepared_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 prepare SQL statements: %s", (errmsg ? errmsg : "[???]")); apr_pool_destroy(rec->pool); return rv; } *data_ptr = rec; return APR_SUCCESS;}#if APR_HAS_THREADSstatic apr_status_t dbd_destroy(void *data){ dbd_group_t *group = data; group->destroyed = 1; return APR_SUCCESS;}static apr_status_t dbd_setup(server_rec *s, dbd_group_t *group){ dbd_cfg_t *cfg = group->cfg; apr_status_t rv; /* We create the reslist using a sub-pool of the pool passed to our * child_init hook. No other threads can be here because we're * either in the child_init phase or dbd_setup_lock() acquired our mutex. * No other threads will use this sub-pool after this, except via * reslist calls, which have an internal mutex. * * We need to short-circuit the cleanup registered internally by * apr_reslist_create(). We do this by registering dbd_destroy() * as a cleanup afterwards, so that it will run before the reslist's * internal cleanup. * * If we didn't do this, then we could free memory twice when the pool * was destroyed. When apr_pool_destroy() runs, it first destroys all * all the per-connection sub-pools created in dbd_construct(), and * then it runs the reslist's cleanup. The cleanup calls dbd_destruct() * on each resource, which would then attempt to destroy the sub-pools * a second time. */ rv = apr_reslist_create(&group->reslist, cfg->nmin, cfg->nkeep, cfg->nmax, apr_time_from_sec(cfg->exptime), dbd_construct, dbd_destruct, group, group->pool); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "DBD: failed to initialise"); return rv; } apr_pool_cleanup_register(group->pool, group, dbd_destroy, apr_pool_cleanup_null); return APR_SUCCESS;}#endifstatic apr_status_t dbd_setup_init(apr_pool_t *pool, server_rec *s){ dbd_group_t *group; apr_status_t rv = APR_SUCCESS; for (group = group_list; group; group = group->next) { apr_status_t rv2; rv2 = apr_pool_create(&group->pool, pool); if (rv2 != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv2, s, "DBD: Failed to create reslist cleanup memory pool"); return rv2; }#if APR_HAS_THREADS rv2 = dbd_setup(s, group); if (rv2 == APR_SUCCESS) { continue; } else if (rv == APR_SUCCESS) { rv = rv2; } /* we failed, so create a mutex so that subsequent competing callers * to ap_dbd_open can serialize themselves while they retry */ rv2 = apr_thread_mutex_create(&group->mutex, APR_THREAD_MUTEX_DEFAULT, pool); if (rv2 != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv2, s, "DBD: Failed to create thread mutex"); return rv2; }#endif } return rv;}#if APR_HAS_THREADSstatic apr_status_t dbd_setup_lock(server_rec *s, dbd_group_t *group){ apr_status_t rv = APR_SUCCESS, rv2; /* several threads could be here at the same time, all trying to * initialize the reslist because dbd_setup_init failed to do so */ if (!group->mutex) { /* we already logged an error when the mutex couldn't be created */ return APR_EGENERAL; } rv2 = apr_thread_mutex_lock(group->mutex); if (rv2 != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv2, s, "DBD: Failed to acquire thread mutex"); return rv2; } if (!group->reslist) { rv = dbd_setup(s, group); } rv2 = apr_thread_mutex_unlock(group->mutex); if (rv2 != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv2, s, "DBD: Failed to release thread mutex"); if (rv == APR_SUCCESS) { rv = rv2; } } return rv;}#endif/* Functions we export for modules to use: - 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){ svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module); if (!svr->cfg->persist) { apr_pool_destroy(rec->pool); }#if APR_HAS_THREADS else { apr_reslist_release(svr->group->reslist, rec); }#endif}static apr_status_t dbd_check(apr_pool_t *pool, server_rec *s, ap_dbd_t *rec){ svr_cfg *svr; apr_status_t rv = apr_dbd_check_conn(rec->driver, pool, rec->handle); const char *errmsg; if ((rv == APR_SUCCESS) || (rv == APR_ENOTIMPL)) { return APR_SUCCESS; } errmsg = apr_dbd_error(rec->driver, rec->handle, rv); if (!errmsg) { errmsg = "(unknown)"; } svr = ap_get_module_config(s->module_config, &dbd_module); ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "DBD [%s] Error: %s", svr->cfg->name, errmsg); return rv;}DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open(apr_pool_t *pool, server_rec *s){ svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module); dbd_group_t *group = svr->group; dbd_cfg_t *cfg = svr->cfg; 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"); return NULL; } if (!cfg->persist) { /* Return a once-only connection */ group = apr_pcalloc(pool, sizeof(dbd_group_t)); group->cfg = cfg; dbd_construct((void*) &rec, group, pool); return rec; }#if APR_HAS_THREADS if (!group->reslist) { if (dbd_setup_lock(s, group) != APR_SUCCESS) { return NULL; } } 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; } if (dbd_check(pool, s, rec) != APR_SUCCESS) { apr_reslist_invalidate(group->reslist, rec); return NULL; }#else /* If we have a persistent connection and it's good, we'll use it; * since this is non-threaded, we can update without a mutex */ rec = group->rec; if (rec) { if (dbd_check(pool, s, rec) != APR_SUCCESS) { apr_pool_destroy(rec->pool); rec = NULL; } } /* We don't have a connection right now, so we'll open one */ if (!rec) { dbd_construct((void*) &rec, group, group->pool); group->rec = rec; }#endif return rec;}#if APR_HAS_THREADStypedef struct { ap_dbd_t *rec; apr_reslist_t *reslist;} dbd_acquire_t;static apr_status_t dbd_release(void *data){ dbd_acquire_t *acq = data; apr_reslist_release(acq->reslist, acq->rec); return APR_SUCCESS;}DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r){ dbd_acquire_t *acq; while (!ap_is_initial_req(r)) { if (r->prev) { r = r->prev; } else if (r->main) { r = r->main; } } acq = ap_get_module_config(r->request_config, &dbd_module); if (!acq) { 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); } } } return acq->rec;}DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c){ dbd_acquire_t *acq = ap_get_module_config(c->conn_config, &dbd_module); if (!acq) { acq = apr_palloc(c->pool, sizeof(dbd_acquire_t)); acq->rec = ap_dbd_open(c->pool, c->base_server); if (acq->rec) { 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; apr_pool_cleanup_register(c->pool, acq, dbd_release, apr_pool_cleanup_null); } } } return acq->rec;}#elseDBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r){ ap_dbd_t *rec; while (!ap_is_initial_req(r)) { if (r->prev) { r = r->prev; } else if (r->main) { r = r->main; } } rec = ap_get_module_config(r->request_config, &dbd_module); if (!rec) { rec = ap_dbd_open(r->pool, r->server); if (rec) { ap_set_module_config(r->request_config, &dbd_module, rec); } } return rec;}DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c){ ap_dbd_t *rec = ap_get_module_config(c->conn_config, &dbd_module); if (!rec) { rec = ap_dbd_open(c->pool, c->base_server); if (rec) { ap_set_module_config(c->conn_config, &dbd_module, rec); } } return rec;}#endifstatic void dbd_hooks(apr_pool_t *pool){ ap_hook_pre_config(dbd_pre_config, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_post_config(dbd_post_config, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_child_init((void*)dbd_setup_init, NULL, NULL, APR_HOOK_MIDDLE); APR_REGISTER_OPTIONAL_FN(ap_dbd_prepare); APR_REGISTER_OPTIONAL_FN(ap_dbd_open); APR_REGISTER_OPTIONAL_FN(ap_dbd_close); APR_REGISTER_OPTIONAL_FN(ap_dbd_acquire); APR_REGISTER_OPTIONAL_FN(ap_dbd_cacquire); apr_dbd_init(pool);}module AP_MODULE_DECLARE_DATA dbd_module = { STANDARD20_MODULE_STUFF, NULL, NULL, create_dbd_config, merge_dbd_config, dbd_cmds, dbd_hooks};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -