/[Apache-SVN]/httpd/httpd/trunk/modules/database/mod_dbd.c
ViewVC logotype

Contents of /httpd/httpd/trunk/modules/database/mod_dbd.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 503931 - (hide annotations)
Tue Feb 6 00:25:15 2007 UTC (2 years, 9 months ago) by chrisd
File MIME type: text/plain
File size: 27529 byte(s)
Introduce configuration groups to allow inheritance by virtual hosts of
database configurations from the main server.  The post_config hook function
determines the minimal set of distinct configurations necessary so that
database connection pools are shared between virtual hosts whenever possible.

The SQL statements which should be prepared for each database connection
are now stored in a hash for each virtual host during the configuration
phase, and these hashes are merged in the normal manner using
apr_hash_overlay() with that of the main server.  This allows for statements
to be de-registered by DBDPrepareSQL, if desired.  The post_config hook
function then compares the statements registered for each virtual host
when determining if a separate configuration group is required.  The
changes in r424798, r432560, r432562, and r466641, which still have problems
with configuration inheritance, are therefore no longer necessary.
1 fielding 420983 /* Licensed to the Apache Software Foundation (ASF) under one or more
2     * contributor license agreements. See the NOTICE file distributed with
3     * this work for additional information regarding copyright ownership.
4     * The ASF licenses this file to You under the Apache License, Version 2.0
5     * (the "License"); you may not use this file except in compliance with
6     * the License. You may obtain a copy of the License at
7 niq 170729 *
8     * http://www.apache.org/licenses/LICENSE-2.0
9     *
10     * Unless required by applicable law or agreed to in writing, software
11     * distributed under the License is distributed on an "AS IS" BASIS,
12     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     * See the License for the specific language governing permissions and
14     * limitations under the License.
15     */
16    
17     /* Overview of what this is and does:
18     * http://www.apache.org/~niq/dbd.html
19     * or
20     * http://apache.webthing.com/database/
21     */
22    
23 chrisd 491884 #include "apr_reslist.h"
24     #include "apr_strings.h"
25     #include "apr_hash.h"
26 chrisd 503931 #include "apr_tables.h"
27 chrisd 491884 #include "apr_lib.h"
28     #include "apr_dbd.h"
29 niq 170729
30 chrisd 491884 #define APR_WANT_MEMFUNC
31     #define APR_WANT_STRFUNC
32     #include "apr_want.h"
33    
34 niq 170729 #include "http_protocol.h"
35     #include "http_config.h"
36     #include "http_log.h"
37 rpluem 483630 #include "http_request.h"
38 niq 170729 #include "mod_dbd.h"
39 niq 290711
40 niq 170729 extern module AP_MODULE_DECLARE_DATA dbd_module;
41    
42     /************ svr cfg: manage db connection pool ****************/
43    
44 niq 348026 #define NMIN_SET 0x1
45     #define NKEEP_SET 0x2
46     #define NMAX_SET 0x4
47     #define EXPTIME_SET 0x8
48    
49 chrisd 491729 typedef struct {
50 chrisd 491884 server_rec *server;
51 niq 170729 const char *name;
52     const char *params;
53     int persist;
54     #if APR_HAS_THREADS
55     int nmin;
56     int nkeep;
57     int nmax;
58     int exptime;
59 chrisd 491884 int set;
60 chrisd 503931 #endif
61     apr_hash_t *queries;
62     } dbd_cfg_t;
63    
64     typedef struct dbd_group_t dbd_group_t;
65    
66     struct dbd_group_t {
67     dbd_cfg_t *cfg;
68     dbd_group_t *next;
69     apr_pool_t *pool;
70     #if APR_HAS_THREADS
71     apr_thread_mutex_t *mutex;
72     apr_reslist_t *reslist;
73     int destroyed;
74 niq 170729 #else
75 chrisd 491729 ap_dbd_t *rec;
76 niq 170729 #endif
77 chrisd 503931 };
78    
79     typedef struct {
80     dbd_cfg_t *cfg;
81     dbd_group_t *group;
82 niq 170729 } svr_cfg;
83    
84     typedef enum { cmd_name, cmd_params, cmd_persist,
85     cmd_min, cmd_keep, cmd_max, cmd_exp
86     } cmd_parts;
87    
88 chrisd 503931 static apr_pool_t *config_pool;
89     static dbd_group_t *group_list;
90 niq 424798
91 niq 413015 /* a default DBDriver value that'll generate meaningful error messages */
92     static const char *const no_dbdriver = "[DBDriver unset]";
93 niq 170729
94 chrisd 491729 /* A default nmin of >0 will help with generating meaningful
95     * startup error messages if the database is down.
96     */
97     #define DEFAULT_NMIN 1
98     #define DEFAULT_NKEEP 2
99     #define DEFAULT_NMAX 10
100     #define DEFAULT_EXPTIME 300
101    
102     static void *create_dbd_config(apr_pool_t *pool, server_rec *s)
103     {
104     svr_cfg *svr = apr_pcalloc(pool, sizeof(svr_cfg));
105 chrisd 503931 dbd_cfg_t *cfg = svr->cfg = apr_pcalloc(pool, sizeof(dbd_cfg_t));
106 chrisd 491729
107 chrisd 503931 cfg->server = s;
108     cfg->name = no_dbdriver; /* to generate meaningful error messages */
109     cfg->params = ""; /* don't risk segfault on misconfiguration */
110     cfg->persist = -1;
111 chrisd 491729 #if APR_HAS_THREADS
112 chrisd 503931 cfg->nmin = DEFAULT_NMIN;
113     cfg->nkeep = DEFAULT_NKEEP;
114     cfg->nmax = DEFAULT_NMAX;
115     cfg->exptime = DEFAULT_EXPTIME;
116 chrisd 491729 #endif
117 chrisd 503931 cfg->queries = apr_hash_make(pool);
118 chrisd 491729
119     return svr;
120     }
121    
122     static void *merge_dbd_config(apr_pool_t *pool, void *basev, void *addv)
123     {
124 chrisd 503931 dbd_cfg_t *base = ((svr_cfg*) basev)->cfg;
125     dbd_cfg_t *add = ((svr_cfg*) addv)->cfg;
126 chrisd 491729 svr_cfg *svr = apr_pcalloc(pool, sizeof(svr_cfg));
127 chrisd 503931 dbd_cfg_t *new = svr->cfg = apr_pcalloc(pool, sizeof(dbd_cfg_t));
128 chrisd 491729
129 chrisd 503931 new->server = add->server;
130     new->name = (add->name != no_dbdriver) ? add->name : base->name;
131     new->params = strcmp(add->params, "") ? add->params : base->params;
132     new->persist = (add->persist != -1) ? add->persist : base->persist;
133 chrisd 491729 #if APR_HAS_THREADS
134 chrisd 503931 new->nmin = (add->set&NMIN_SET) ? add->nmin : base->nmin;
135     new->nkeep = (add->set&NKEEP_SET) ? add->nkeep : base->nkeep;
136     new->nmax = (add->set&NMAX_SET) ? add->nmax : base->nmax;
137     new->exptime = (add->set&EXPTIME_SET) ? add->exptime : base->exptime;
138 chrisd 491729 #endif
139 chrisd 503931 new->queries = apr_hash_overlay(pool, add->queries, base->queries);
140 chrisd 491729
141     return svr;
142     }
143    
144 chrisd 492394 #define ISINT(val) do { \
145     const char *p; \
146     \
147     for (p = val; *p; ++p) { \
148     if (!apr_isdigit(*p)) { \
149     return "Argument must be numeric!"; \
150     } \
151     } \
152     } while (0)
153 chrisd 491729
154     static const char *dbd_param(cmd_parms *cmd, void *dconf, const char *val)
155 niq 170729 {
156 niq 231464 const apr_dbd_driver_t *driver = NULL;
157 chrisd 491729 svr_cfg *svr = ap_get_module_config(cmd->server->module_config,
158     &dbd_module);
159 chrisd 503931 dbd_cfg_t *cfg = svr->cfg;
160 niq 170729
161 niq 291100 switch ((long) cmd->info) {
162 niq 170729 case cmd_name:
163 chrisd 503931 cfg->name = val;
164 niq 170729 /* loading the driver involves once-only dlloading that is
165     * best done at server startup. This also guarantees that
166 niq 345040 * we won't return an error later.
167 niq 170729 */
168 chrisd 503931 switch (apr_dbd_get_driver(cmd->pool, cfg->name, &driver)) {
169 niq 170729 case APR_ENOTIMPL:
170 chrisd 503931 return apr_psprintf(cmd->pool, "DBD: No driver for %s", cfg->name);
171 niq 170729 case APR_EDSOOPEN:
172     return apr_psprintf(cmd->pool,
173     "DBD: Can't load driver file apr_dbd_%s.so",
174 chrisd 503931 cfg->name);
175 niq 170729 case APR_ESYMNOTFOUND:
176     return apr_psprintf(cmd->pool,
177     "DBD: Failed to load driver apr_dbd_%s_driver",
178 chrisd 503931 cfg->name);
179 niq 170729 }
180     break;
181     case cmd_params:
182 chrisd 503931 cfg->params = val;
183 niq 170729 break;
184     #if APR_HAS_THREADS
185     case cmd_min:
186     ISINT(val);
187 chrisd 503931 cfg->nmin = atoi(val);
188     cfg->set |= NMIN_SET;
189 niq 170729 break;
190     case cmd_keep:
191     ISINT(val);
192 chrisd 503931 cfg->nkeep = atoi(val);
193     cfg->set |= NKEEP_SET;
194 niq 170729 break;
195     case cmd_max:
196     ISINT(val);
197 chrisd 503931 cfg->nmax = atoi(val);
198     cfg->set |= NMAX_SET;
199 niq 170729 break;
200     case cmd_exp:
201     ISINT(val);
202 chrisd 503931 cfg->exptime = atoi(val);
203     cfg->set |= EXPTIME_SET;
204 niq 170729 break;
205     #endif
206     }
207 chrisd 491729
208 niq 170729 return NULL;
209     }
210 chrisd 491729
211     static const char *dbd_param_flag(cmd_parms *cmd, void *dconf, int flag)
212 niq 348026 {
213 chrisd 491729 svr_cfg *svr = ap_get_module_config(cmd->server->module_config,
214     &dbd_module);
215 niq 348026
216     switch ((long) cmd->info) {
217     case cmd_persist:
218 chrisd 503931 svr->cfg->persist = flag;
219 niq 348026 break;
220     }
221 chrisd 491729
222 niq 348026 return NULL;
223     }
224 chrisd 491729
225     static const char *dbd_prepare(cmd_parms *cmd, void *dconf, const char *query,
226 niq 234017 const char *label)
227     {
228 chrisd 503931 if (!label) {
229     label = query;
230     query = "";
231     }
232    
233 niq 234017 ap_dbd_prepare(cmd->server, query, label);
234 chrisd 491729
235 niq 170729 return NULL;
236     }
237 chrisd 491729
238 niq 170729 static const command_rec dbd_cmds[] = {
239     AP_INIT_TAKE1("DBDriver", dbd_param, (void*)cmd_name, RSRC_CONF,
240     "SQL Driver"),
241     AP_INIT_TAKE1("DBDParams", dbd_param, (void*)cmd_params, RSRC_CONF,
242     "SQL Driver Params"),
243 niq 348026 AP_INIT_FLAG("DBDPersist", dbd_param_flag, (void*)cmd_persist, RSRC_CONF,
244     "Use persistent connection/pool"),
245 chrisd 503931 AP_INIT_TAKE12("DBDPrepareSQL", dbd_prepare, NULL, RSRC_CONF,
246     "SQL statement to prepare (or nothing, to override "
247     "statement inherited from main server) and label"),
248 niq 170729 #if APR_HAS_THREADS
249     AP_INIT_TAKE1("DBDMin", dbd_param, (void*)cmd_min, RSRC_CONF,
250     "Minimum number of connections"),
251 niq 348026 /* XXX: note that mod_proxy calls this "smax" */
252 niq 170729 AP_INIT_TAKE1("DBDKeep", dbd_param, (void*)cmd_keep, RSRC_CONF,
253     "Maximum number of sustained connections"),
254     AP_INIT_TAKE1("DBDMax", dbd_param, (void*)cmd_max, RSRC_CONF,
255     "Maximum number of connections"),
256 niq 348026 /* XXX: note that mod_proxy calls this "ttl" (time to live) */
257 niq 170729 AP_INIT_TAKE1("DBDExptime", dbd_param, (void*)cmd_exp, RSRC_CONF,
258     "Keepalive time for idle connections"),
259     #endif
260     {NULL}
261     };
262 chrisd 491729
263     static int dbd_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
264     apr_pool_t *ptemp)
265     {
266 chrisd 503931 config_pool = pconf;
267     group_list = NULL;
268 chrisd 491729 return OK;
269 niq 348026 }
270 chrisd 491729
271     DBD_DECLARE_NONSTD(void) ap_dbd_prepare(server_rec *s, const char *query,
272     const char *label)
273 niq 170729 {
274 chrisd 503931 svr_cfg *svr;
275 chrisd 491729
276 chrisd 503931 svr = ap_get_module_config(s->module_config, &dbd_module);
277     if (!svr) {
278     /* some modules may call from within config directive handlers, and
279     * if these are called in a server context that contains no mod_dbd
280     * config directives, then we have to create our own server config
281     */
282     svr = create_dbd_config(config_pool, s);
283     ap_set_module_config(s->module_config, &dbd_module, svr);
284     }
285 chrisd 491729
286 chrisd 503931 if (apr_hash_get(svr->cfg->queries, label, APR_HASH_KEY_STRING)
287     && strcmp(query, "")) {
288     ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
289     "conflicting SQL statements with label %s", label);
290     }
291    
292     apr_hash_set(svr->cfg->queries, label, APR_HASH_KEY_STRING, query);
293 niq 170729 }
294 chrisd 491729
295 chrisd 503931 typedef struct {
296     const char *label, *query;
297     } dbd_query_t;
298    
299 chrisd 491729 static int dbd_post_config(apr_pool_t *pconf, apr_pool_t *plog,
300     apr_pool_t *ptemp, server_rec *s)
301     {
302     server_rec *sp;
303 chrisd 503931 apr_array_header_t *add_queries = apr_array_make(ptemp, 10,
304     sizeof(dbd_query_t));
305 chrisd 491729
306     for (sp = s; sp; sp = sp->next) {
307     svr_cfg *svr = ap_get_module_config(sp->module_config, &dbd_module);
308 chrisd 503931 dbd_cfg_t *cfg = svr->cfg;
309     apr_hash_index_t *hi_first = apr_hash_first(ptemp, cfg->queries);
310     dbd_group_t *group;
311 chrisd 491729
312 chrisd 503931 /* dbd_setup in 2.2.3 and under was causing spurious error messages
313     * when dbd isn't configured. We can stop that with a quick check here
314     * together with a similar check in ap_dbd_open (where being
315     * unconfigured is a genuine error that must be reported).
316     */
317     if (cfg->name == no_dbdriver || !cfg->persist) {
318     continue;
319     }
320    
321     for (group = group_list; group; group = group->next) {
322     dbd_cfg_t *group_cfg = group->cfg;
323     apr_hash_index_t *hi;
324     int group_ok = 1;
325    
326     if (strcmp(cfg->name, group_cfg->name)
327     || strcmp(cfg->params, group_cfg->params)) {
328     continue;
329     }
330    
331     #if APR_HAS_THREADS
332     if (cfg->nmin != group_cfg->nmin
333     || cfg->nkeep != group_cfg->nkeep
334     || cfg->nmax != group_cfg->nmax
335     || cfg->exptime != group_cfg->exptime) {
336     continue;
337     }
338     #endif
339    
340     add_queries->nelts = 0;
341    
342     for (hi = hi_first; hi; hi = apr_hash_next(hi)) {
343     const char *label, *query;
344     const char *group_query;
345    
346     apr_hash_this(hi, (void*) &label, NULL, (void*) &query);
347    
348     group_query = apr_hash_get(group_cfg->queries, label,
349     APR_HASH_KEY_STRING);
350    
351     if (!group_query) {
352     dbd_query_t *add_query = apr_array_push(add_queries);
353    
354     add_query->label = label;
355     add_query->query = query;
356     }
357     else if (strcmp(query, group_query)) {
358     group_ok = 0;
359     break;
360     }
361     }
362    
363     if (group_ok) {
364     int i;
365    
366     for (i = 0; i < add_queries->nelts; ++i) {
367     dbd_query_t *add_query = ((dbd_query_t*) add_queries->elts)
368     + i;
369    
370     apr_hash_set(group_cfg->queries, add_query->label,
371     APR_HASH_KEY_STRING, add_query->query);
372     }
373    
374     svr->group = group;
375     break;
376     }
377     }
378    
379     if (!svr->group) {
380     svr->group = group = apr_pcalloc(pconf, sizeof(dbd_group_t));
381    
382     group->cfg = cfg;
383    
384     group->next = group_list;
385     group_list = group;
386     }
387 chrisd 491729 }
388    
389     return OK;
390     }
391    
392 chrisd 503931 static apr_status_t dbd_prepared_init(apr_pool_t *pool, dbd_cfg_t *cfg,
393 chrisd 491729 ap_dbd_t *rec)
394 niq 170729 {
395 chrisd 503931 apr_hash_index_t *hi;
396 chrisd 491729 apr_status_t rv = APR_SUCCESS;
397 niq 170729
398 chrisd 491729 rec->prepared = apr_hash_make(pool);
399    
400 chrisd 503931 for (hi = apr_hash_first(pool, cfg->queries); hi;
401     hi = apr_hash_next(hi)) {
402     const char *label, *query;
403     apr_dbd_prepared_t *stmt;
404    
405     apr_hash_this(hi, (void*) &label, NULL, (void*) &query);
406    
407     if (!strcmp(query, "")) {
408     continue;
409     }
410    
411 niq 344140 stmt = NULL;
412 chrisd 503931 if (apr_dbd_prepare(rec->driver, pool, rec->handle, query,
413     label, &stmt)) {
414     rv = APR_EGENERAL;
415 niq 170729 }
416     else {
417 chrisd 503931 apr_hash_set(rec->prepared, label, APR_HASH_KEY_STRING, stmt);
418 niq 170729 }
419     }
420 chrisd 491729
421     return rv;
422 niq 170729 }
423 chrisd 491729
424     static apr_status_t dbd_close(void *data)
425     {
426     ap_dbd_t *rec = data;
427    
428 chrisd 496831 return apr_dbd_close(rec->driver, rec->handle);
429 chrisd 491729 }
430    
431     #if APR_HAS_THREADS
432     static apr_status_t dbd_destruct(void *data, void *params, apr_pool_t *pool)
433     {
434 chrisd 503931 dbd_group_t *group = params;
435 chrisd 496831
436 chrisd 503931 if (!group->destroyed) {
437 chrisd 496831 ap_dbd_t *rec = data;
438    
439     apr_pool_destroy(rec->pool);
440     }
441    
442     return APR_SUCCESS;
443 chrisd 491729 }
444     #endif
445    
446 niq 234017 /* an apr_reslist_constructor for SQL connections
447     * Also use this for opening in non-reslist modes, since it gives
448     * us all the error-handling in one place.
449     */
450 chrisd 491729 static apr_status_t dbd_construct(void **data_ptr,
451     void *params, apr_pool_t *pool)
452 niq 170729 {
453 chrisd 503931 dbd_group_t *group = params;
454     dbd_cfg_t *cfg = group->cfg;
455 chrisd 496831 apr_pool_t *rec_pool, *prepared_pool;
456     ap_dbd_t *rec;
457 niq 348026 apr_status_t rv;
458 niq 170729
459 chrisd 496831 rv = apr_pool_create(&rec_pool, pool);
460 niq 348026 if (rv != APR_SUCCESS) {
461 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, cfg->server,
462 chrisd 491884 "DBD: Failed to create memory pool");
463     return rv;
464 niq 348026 }
465    
466 chrisd 496831 rec = apr_pcalloc(rec_pool, sizeof(ap_dbd_t));
467    
468     rec->pool = rec_pool;
469    
470 chrisd 491729 /* The driver is loaded at config time now, so this just checks a hash.
471     * If that changes, the driver DSO could be registered to unload against
472     * our pool, which is probably not what we want. Error checking isn't
473     * necessary now, but in case that changes in the future ...
474     */
475 chrisd 503931 rv = apr_dbd_get_driver(rec->pool, cfg->name, &rec->driver);
476 chrisd 491729 if (rv != APR_SUCCESS) {
477     switch (rv) {
478     case APR_ENOTIMPL:
479 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
480     "DBD: driver for %s not available", cfg->name);
481 chrisd 491729 break;
482     case APR_EDSOOPEN:
483 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
484     "DBD: can't find driver for %s", cfg->name);
485 chrisd 491729 break;
486     case APR_ESYMNOTFOUND:
487 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
488 chrisd 491884 "DBD: driver for %s is invalid or corrupted",
489 chrisd 503931 cfg->name);
490 chrisd 491729 break;
491     default:
492 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
493 chrisd 491884 "DBD: mod_dbd not compatible with APR in get_driver");
494 chrisd 491729 break;
495     }
496    
497 chrisd 491884 apr_pool_destroy(rec->pool);
498 niq 234017 return rv;
499     }
500    
501 chrisd 503931 rv = apr_dbd_open(rec->driver, rec->pool, cfg->params, &rec->handle);
502 chrisd 491729 if (rv != APR_SUCCESS) {
503     switch (rv) {
504     case APR_EGENERAL:
505 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
506     "DBD: Can't connect to %s", cfg->name);
507 chrisd 491729 break;
508     default:
509 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
510 chrisd 491884 "DBD: mod_dbd not compatible with APR in open");
511 chrisd 491729 break;
512     }
513    
514 chrisd 491884 apr_pool_destroy(rec->pool);
515 niq 170729 return rv;
516     }
517 chrisd 491729
518 chrisd 496831 apr_pool_cleanup_register(rec->pool, rec, dbd_close,
519     apr_pool_cleanup_null);
520    
521     /* we use a sub-pool for the prepared statements for each connection so
522     * that they will be cleaned up first, before the connection is closed
523     */
524     rv = apr_pool_create(&prepared_pool, rec->pool);
525 niq 386321 if (rv != APR_SUCCESS) {
526 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, cfg->server,
527 chrisd 496831 "DBD: Failed to create memory pool");
528    
529     apr_pool_destroy(rec->pool);
530     return rv;
531     }
532    
533 chrisd 503931 rv = dbd_prepared_init(prepared_pool, cfg, rec);
534 chrisd 496831 if (rv != APR_SUCCESS) {
535 niq 424798 const char *errmsg = apr_dbd_error(rec->driver, rec->handle, rv);
536 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
537 chrisd 491884 "DBD: failed to prepare SQL statements: %s",
538     (errmsg ? errmsg : "[???]"));
539    
540     apr_pool_destroy(rec->pool);
541     return rv;
542 niq 386321 }
543 chrisd 491729
544 chrisd 491884 *data_ptr = rec;
545    
546     return APR_SUCCESS;
547 niq 170729 }
548 chrisd 491729
549 niq 234017 #if APR_HAS_THREADS
550 chrisd 496831 static apr_status_t dbd_destroy(void *data)
551 niq 170729 {
552 chrisd 503931 dbd_group_t *group = data;
553 chrisd 496831
554 chrisd 503931 group->destroyed = 1;
555 chrisd 496831
556     return APR_SUCCESS;
557     }
558    
559 chrisd 503931 static apr_status_t dbd_setup(server_rec *s, dbd_group_t *group)
560 chrisd 496831 {
561 chrisd 503931 dbd_cfg_t *cfg = group->cfg;
562 niq 348026 apr_status_t rv;
563    
564 chrisd 496831 /* We create the reslist using a sub-pool of the pool passed to our
565     * child_init hook. No other threads can be here because we're
566     * either in the child_init phase or dbd_setup_lock() acquired our mutex.
567     * No other threads will use this sub-pool after this, except via
568     * reslist calls, which have an internal mutex.
569     *
570     * We need to short-circuit the cleanup registered internally by
571     * apr_reslist_create(). We do this by registering dbd_destroy()
572     * as a cleanup afterwards, so that it will run before the reslist's
573     * internal cleanup.
574     *
575     * If we didn't do this, then we could free memory twice when the pool
576     * was destroyed. When apr_pool_destroy() runs, it first destroys all
577     * all the per-connection sub-pools created in dbd_construct(), and
578     * then it runs the reslist's cleanup. The cleanup calls dbd_destruct()
579     * on each resource, which would then attempt to destroy the sub-pools
580     * a second time.
581 niq 348026 */
582 chrisd 503931 rv = apr_reslist_create(&group->reslist,
583     cfg->nmin, cfg->nkeep, cfg->nmax,
584     apr_time_from_sec(cfg->exptime),
585     dbd_construct, dbd_destruct, group,
586     group->pool);
587 chrisd 491884 if (rv != APR_SUCCESS) {
588     ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
589     "DBD: failed to initialise");
590     return rv;
591 niq 170729 }
592 niq 348026
593 chrisd 503931 apr_pool_cleanup_register(group->pool, group, dbd_destroy,
594 chrisd 496831 apr_pool_cleanup_null);
595    
596 chrisd 491884 return APR_SUCCESS;
597 niq 170729 }
598 chrisd 496831 #endif
599 chrisd 491729
600 niq 348026 static apr_status_t dbd_setup_init(apr_pool_t *pool, server_rec *s)
601     {
602 chrisd 503931 dbd_group_t *group;
603     apr_status_t rv = APR_SUCCESS;
604 niq 170729
605 chrisd 503931 for (group = group_list; group; group = group->next) {
606     apr_status_t rv2;
607 niq 485311
608 chrisd 503931 rv2 = apr_pool_create(&group->pool, pool);
609     if (rv2 != APR_SUCCESS) {
610     ap_log_error(APLOG_MARK, APLOG_CRIT, rv2, s,
611     "DBD: Failed to create reslist cleanup memory pool");
612     return rv2;
613     }
614 niq 348026
615 chrisd 496831 #if APR_HAS_THREADS
616 chrisd 503931 rv2 = dbd_setup(s, group);
617     if (rv2 == APR_SUCCESS) {
618     continue;
619     }
620     else if (rv == APR_SUCCESS) {
621     rv = rv2;
622     }
623 niq 348026
624 chrisd 503931 /* we failed, so create a mutex so that subsequent competing callers
625     * to ap_dbd_open can serialize themselves while they retry
626     */
627     rv2 = apr_thread_mutex_create(&group->mutex,
628     APR_THREAD_MUTEX_DEFAULT, pool);
629     if (rv2 != APR_SUCCESS) {
630     ap_log_error(APLOG_MARK, APLOG_CRIT, rv2, s,
631     "DBD: Failed to create thread mutex");
632     return rv2;
633     }
634     #endif
635 niq 348026 }
636 chrisd 491729
637 niq 348026 return rv;
638     }
639 chrisd 491729
640 chrisd 496831 #if APR_HAS_THREADS
641 chrisd 503931 static apr_status_t dbd_setup_lock(server_rec *s, dbd_group_t *group)
642 niq 348026 {
643 chrisd 491729 apr_status_t rv = APR_SUCCESS, rv2;
644 niq 348026
645     /* several threads could be here at the same time, all trying to
646     * initialize the reslist because dbd_setup_init failed to do so
647     */
648 chrisd 503931 if (!group->mutex) {
649 niq 348026 /* we already logged an error when the mutex couldn't be created */
650     return APR_EGENERAL;
651     }
652    
653 chrisd 503931 rv2 = apr_thread_mutex_lock(group->mutex);
654 chrisd 491729 if (rv2 != APR_SUCCESS) {
655 chrisd 491884 ap_log_error(APLOG_MARK, APLOG_ERR, rv2, s,
656     "DBD: Failed to acquire thread mutex");
657 chrisd 491729 return rv2;
658 niq 348026 }
659    
660 chrisd 503931 if (!group->reslist) {
661     rv = dbd_setup(s, group);
662 niq 348026 }
663    
664 chrisd 503931 rv2 = apr_thread_mutex_unlock(group->mutex);
665 chrisd 491729 if (rv2 != APR_SUCCESS) {
666 chrisd 491884 ap_log_error(APLOG_MARK, APLOG_ERR, rv2, s,
667     "DBD: Failed to release thread mutex");
668 chrisd 491729 if (rv == APR_SUCCESS) {
669     rv = rv2;
670 niq 348026 }
671     }
672 chrisd 491729
673     return rv;
674 niq 348026 }
675 niq 170729 #endif
676    
677     /* Functions we export for modules to use:
678     - open acquires a connection from the pool (opens one if necessary)
679     - close releases it back in to the pool
680     */
681 chrisd 491729 DBD_DECLARE_NONSTD(void) ap_dbd_close(server_rec *s, ap_dbd_t *rec)
682 niq 345040 {
683     svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
684 chrisd 491729
685 chrisd 503931 if (!svr->cfg->persist) {
686 chrisd 496831 apr_pool_destroy(rec->pool);
687 niq 345040 }
688     #if APR_HAS_THREADS
689     else {
690 chrisd 503931 apr_reslist_release(svr->group->reslist, rec);
691 niq 345040 }
692     #endif
693     }
694 chrisd 491729
695 chrisd 491884 static apr_status_t dbd_check(apr_pool_t *pool, server_rec *s, ap_dbd_t *rec)
696     {
697     svr_cfg *svr;
698     apr_status_t rv = apr_dbd_check_conn(rec->driver, pool, rec->handle);
699     const char *errmsg;
700 chrisd 491729
701 chrisd 491884 if ((rv == APR_SUCCESS) || (rv == APR_ENOTIMPL)) {
702     return APR_SUCCESS;
703     }
704    
705     errmsg = apr_dbd_error(rec->driver, rec->handle, rv);
706     if (!errmsg) {
707     errmsg = "(unknown)";
708     }
709    
710     svr = ap_get_module_config(s->module_config, &dbd_module);
711     ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
712 chrisd 503931 "DBD [%s] Error: %s", svr->cfg->name, errmsg);
713 chrisd 491884 return rv;
714     }
715    
716 colm 349768 DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open(apr_pool_t *pool, server_rec *s)
717 niq 170729 {
718 chrisd 491729 svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
719 chrisd 503931 dbd_group_t *group = svr->group;
720     dbd_cfg_t *cfg = svr->cfg;
721 chrisd 491884 ap_dbd_t *rec = NULL;
722     #if APR_HAS_THREADS
723     apr_status_t rv;
724     #endif
725 niq 170729
726 niq 485311 /* If nothing is configured, we shouldn't be here */
727 chrisd 503931 if (cfg->name == no_dbdriver) {
728 chrisd 491884 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "DBD: not configured");
729 niq 485311 return NULL;
730     }
731    
732 chrisd 503931 if (!cfg->persist) {
733 niq 234017 /* Return a once-only connection */
734 chrisd 503931 group = apr_pcalloc(pool, sizeof(dbd_group_t));
735    
736     group->cfg = cfg;
737    
738     dbd_construct((void*) &rec, group, pool);
739 chrisd 491884 return rec;
740 niq 170729 }
741    
742 chrisd 491884 #if APR_HAS_THREADS
743 chrisd 503931 if (!group->reslist) {
744     if (dbd_setup_lock(s, group) != APR_SUCCESS) {
745 niq 170729 return NULL;
746     }
747     }
748 chrisd 491729
749 chrisd 503931 rv = apr_reslist_acquire(group->reslist, (void*) &rec);
750 niq 348026 if (rv != APR_SUCCESS) {
751 chrisd 491884 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
752     "Failed to acquire DBD connection from pool!");
753 niq 170729 return NULL;
754     }
755 chrisd 491729
756 chrisd 491884 if (dbd_check(pool, s, rec) != APR_SUCCESS) {
757 chrisd 503931 apr_reslist_invalidate(group->reslist, rec);
758 niq 170729 return NULL;
759     }
760     #else
761 chrisd 491729 /* If we have a persistent connection and it's good, we'll use it;
762     * since this is non-threaded, we can update without a mutex
763     */
764 chrisd 503931 rec = group->rec;
765     if (rec) {
766 chrisd 491884 if (dbd_check(pool, s, rec) != APR_SUCCESS) {
767 chrisd 496831 apr_pool_destroy(rec->pool);
768 chrisd 491884 rec = NULL;
769 niq 170729 }
770     }
771 chrisd 491729
772     /* We don't have a connection right now, so we'll open one */
773 chrisd 491884 if (!rec) {
774 chrisd 503931 dbd_construct((void*) &rec, group, group->pool);
775     group->rec = rec;
776 niq 170729 }
777 chrisd 491884 #endif
778 chrisd 491729
779 chrisd 491884 return rec;
780 niq 170729 }
781 chrisd 491729
782 niq 170729 #if APR_HAS_THREADS
783     typedef struct {
784 chrisd 491729 ap_dbd_t *rec;
785     apr_reslist_t *reslist;
786     } dbd_acquire_t;
787    
788     static apr_status_t dbd_release(void *data)
789 niq 170729 {
790 chrisd 491729 dbd_acquire_t *acq = data;
791     apr_reslist_release(acq->reslist, acq->rec);
792 niq 170729 return APR_SUCCESS;
793     }
794 chrisd 491729
795 colm 349768 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r)
796 niq 170729 {
797 chrisd 491729 dbd_acquire_t *acq;
798 chrisd 481509
799     while (!ap_is_initial_req(r)) {
800     if (r->prev) {
801     r = r->prev;
802     }
803     else if (r->main) {
804     r = r->main;
805     }
806     }
807    
808 chrisd 491729 acq = ap_get_module_config(r->request_config, &dbd_module);
809     if (!acq) {
810     acq = apr_palloc(r->pool, sizeof(dbd_acquire_t));
811     acq->rec = ap_dbd_open(r->pool, r->server);
812     if (acq->rec) {
813     svr_cfg *svr = ap_get_module_config(r->server->module_config,
814     &dbd_module);
815    
816     ap_set_module_config(r->request_config, &dbd_module, acq);
817 chrisd 503931 if (svr->cfg->persist) {
818     acq->reslist = svr->group->reslist;
819 chrisd 491729 apr_pool_cleanup_register(r->pool, acq, dbd_release,
820 niq 170729 apr_pool_cleanup_null);
821     }
822     }
823     }
824 chrisd 491729
825     return acq->rec;
826 niq 170729 }
827 chrisd 491729
828 colm 349768 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c)
829 niq 307439 {
830 chrisd 491729 dbd_acquire_t *acq = ap_get_module_config(c->conn_config, &dbd_module);
831    
832     if (!acq) {
833     acq = apr_palloc(c->pool, sizeof(dbd_acquire_t));
834     acq->rec = ap_dbd_open(c->pool, c->base_server);
835     if (acq->rec) {
836     svr_cfg *svr = ap_get_module_config(c->base_server->module_config,
837     &dbd_module);
838    
839     ap_set_module_config(c->conn_config, &dbd_module, acq);
840 chrisd 503931 if (svr->cfg->persist) {
841     acq->reslist = svr->group->reslist;
842 chrisd 491729 apr_pool_cleanup_register(c->pool, acq, dbd_release,
843 niq 307439 apr_pool_cleanup_null);
844     }
845     }
846     }
847 chrisd 491729
848     return acq->rec;
849 niq 307439 }
850 niq 170729 #else
851 colm 349768 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r)
852 niq 170729 {
853 chrisd 491729 ap_dbd_t *rec;
854 chrisd 481509
855     while (!ap_is_initial_req(r)) {
856     if (r->prev) {
857     r = r->prev;
858     }
859     else if (r->main) {
860     r = r->main;
861     }
862     }
863    
864 chrisd 491729 rec = ap_get_module_config(r->request_config, &dbd_module);
865     if (!rec) {
866     rec = ap_dbd_open(r->pool, r->server);
867     if (rec) {
868     ap_set_module_config(r->request_config, &dbd_module, rec);
869 niq 170729 }
870     }
871 chrisd 491729
872     return rec;
873 niq 170729 }
874 chrisd 491729
875 colm 349768 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c)
876 niq 307439 {
877 chrisd 491729 ap_dbd_t *rec = ap_get_module_config(c->conn_config, &dbd_module);
878    
879     if (!rec) {
880     rec = ap_dbd_open(c->pool, c->base_server);
881     if (rec) {
882     ap_set_module_config(c->conn_config, &dbd_module, rec);
883 niq 307439 }
884     }
885 chrisd 491729
886     return rec;
887 niq 307439 }
888 niq 170729 #endif
889    
890     static void dbd_hooks(apr_pool_t *pool)
891     {
892 chrisd 491729 ap_hook_pre_config(dbd_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
893     ap_hook_post_config(dbd_post_config, NULL, NULL, APR_HOOK_MIDDLE);
894 niq 348026 ap_hook_child_init((void*)dbd_setup_init, NULL, NULL, APR_HOOK_MIDDLE);
895 chrisd 491729
896     APR_REGISTER_OPTIONAL_FN(ap_dbd_prepare);
897 niq 170729 APR_REGISTER_OPTIONAL_FN(ap_dbd_open);
898     APR_REGISTER_OPTIONAL_FN(ap_dbd_close);
899     APR_REGISTER_OPTIONAL_FN(ap_dbd_acquire);
900 niq 307439 APR_REGISTER_OPTIONAL_FN(ap_dbd_cacquire);
901 chrisd 491729
902 niq 170729 apr_dbd_init(pool);
903     }
904    
905     module AP_MODULE_DECLARE_DATA dbd_module = {
906     STANDARD20_MODULE_STUFF,
907     NULL,
908     NULL,
909 chrisd 491729 create_dbd_config,
910     merge_dbd_config,
911 niq 170729 dbd_cmds,
912     dbd_hooks
913     };
914 chrisd 491729

Properties

Name Value
svn:eol-style native

apache@apache.org
ViewVC Help
Powered by ViewVC 1.1.2