/[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 553031 - (hide annotations)
Wed Jul 4 01:03:48 2007 UTC (2 years, 4 months ago) by fuankg
File MIME type: text/plain
File size: 27673 byte(s)
changed error message to use APU_DBD_DRIVER_FMT for correct driver name;
removed platform ifdefs.
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 fuankg 553031 "DBD: Can't load driver file " APU_DBD_DRIVER_FMT,
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 chrisd 539687 /* we don't have a driver-specific error code, so we'll just pass
706     * a "success" value and rely on the driver to ignore it
707     */
708     errmsg = apr_dbd_error(rec->driver, rec->handle, 0);
709 chrisd 491884 if (!errmsg) {
710     errmsg = "(unknown)";
711     }
712    
713     svr = ap_get_module_config(s->module_config, &dbd_module);
714     ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
715 chrisd 503931 "DBD [%s] Error: %s", svr->cfg->name, errmsg);
716 chrisd 491884 return rv;
717     }
718    
719 colm 349768 DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open(apr_pool_t *pool, server_rec *s)
720 niq 170729 {
721 chrisd 491729 svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
722 chrisd 503931 dbd_group_t *group = svr->group;
723     dbd_cfg_t *cfg = svr->cfg;
724 chrisd 491884 ap_dbd_t *rec = NULL;
725     #if APR_HAS_THREADS
726     apr_status_t rv;
727     #endif
728 niq 170729
729 niq 485311 /* If nothing is configured, we shouldn't be here */
730 chrisd 503931 if (cfg->name == no_dbdriver) {
731 chrisd 491884 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "DBD: not configured");
732 niq 485311 return NULL;
733     }
734    
735 chrisd 503931 if (!cfg->persist) {
736 niq 234017 /* Return a once-only connection */
737 chrisd 503931 group = apr_pcalloc(pool, sizeof(dbd_group_t));
738    
739     group->cfg = cfg;
740    
741     dbd_construct((void*) &rec, group, pool);
742 chrisd 491884 return rec;
743 niq 170729 }
744    
745 chrisd 491884 #if APR_HAS_THREADS
746 chrisd 503931 if (!group->reslist) {
747     if (dbd_setup_lock(s, group) != APR_SUCCESS) {
748 niq 170729 return NULL;
749     }
750     }
751 chrisd 491729
752 chrisd 503931 rv = apr_reslist_acquire(group->reslist, (void*) &rec);
753 niq 348026 if (rv != APR_SUCCESS) {
754 chrisd 491884 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
755     "Failed to acquire DBD connection from pool!");
756 niq 170729 return NULL;
757     }
758 chrisd 491729
759 chrisd 491884 if (dbd_check(pool, s, rec) != APR_SUCCESS) {
760 chrisd 503931 apr_reslist_invalidate(group->reslist, rec);
761 niq 170729 return NULL;
762     }
763     #else
764 chrisd 491729 /* If we have a persistent connection and it's good, we'll use it;
765     * since this is non-threaded, we can update without a mutex
766     */
767 chrisd 503931 rec = group->rec;
768     if (rec) {
769 chrisd 491884 if (dbd_check(pool, s, rec) != APR_SUCCESS) {
770 chrisd 496831 apr_pool_destroy(rec->pool);
771 chrisd 491884 rec = NULL;
772 niq 170729 }
773     }
774 chrisd 491729
775     /* We don't have a connection right now, so we'll open one */
776 chrisd 491884 if (!rec) {
777 chrisd 503931 dbd_construct((void*) &rec, group, group->pool);
778     group->rec = rec;
779 niq 170729 }
780 chrisd 491884 #endif
781 chrisd 491729
782 chrisd 491884 return rec;
783 niq 170729 }
784 chrisd 491729
785 niq 170729 #if APR_HAS_THREADS
786     typedef struct {
787 chrisd 491729 ap_dbd_t *rec;
788     apr_reslist_t *reslist;
789     } dbd_acquire_t;
790    
791     static apr_status_t dbd_release(void *data)
792 niq 170729 {
793 chrisd 491729 dbd_acquire_t *acq = data;
794     apr_reslist_release(acq->reslist, acq->rec);
795 niq 170729 return APR_SUCCESS;
796     }
797 chrisd 491729
798 colm 349768 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r)
799 niq 170729 {
800 chrisd 491729 dbd_acquire_t *acq;
801 chrisd 481509
802     while (!ap_is_initial_req(r)) {
803     if (r->prev) {
804     r = r->prev;
805     }
806     else if (r->main) {
807     r = r->main;
808     }
809     }
810    
811 chrisd 491729 acq = ap_get_module_config(r->request_config, &dbd_module);
812     if (!acq) {
813     acq = apr_palloc(r->pool, sizeof(dbd_acquire_t));
814     acq->rec = ap_dbd_open(r->pool, r->server);
815     if (acq->rec) {
816     svr_cfg *svr = ap_get_module_config(r->server->module_config,
817     &dbd_module);
818    
819     ap_set_module_config(r->request_config, &dbd_module, acq);
820 chrisd 503931 if (svr->cfg->persist) {
821     acq->reslist = svr->group->reslist;
822 chrisd 491729 apr_pool_cleanup_register(r->pool, acq, dbd_release,
823 niq 170729 apr_pool_cleanup_null);
824     }
825     }
826     }
827 chrisd 491729
828     return acq->rec;
829 niq 170729 }
830 chrisd 491729
831 colm 349768 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c)
832 niq 307439 {
833 chrisd 491729 dbd_acquire_t *acq = ap_get_module_config(c->conn_config, &dbd_module);
834    
835     if (!acq) {
836     acq = apr_palloc(c->pool, sizeof(dbd_acquire_t));
837     acq->rec = ap_dbd_open(c->pool, c->base_server);
838     if (acq->rec) {
839     svr_cfg *svr = ap_get_module_config(c->base_server->module_config,
840     &dbd_module);
841    
842     ap_set_module_config(c->conn_config, &dbd_module, acq);
843 chrisd 503931 if (svr->cfg->persist) {
844     acq->reslist = svr->group->reslist;
845 chrisd 491729 apr_pool_cleanup_register(c->pool, acq, dbd_release,
846 niq 307439 apr_pool_cleanup_null);
847     }
848     }
849     }
850 chrisd 491729
851     return acq->rec;
852 niq 307439 }
853 niq 170729 #else
854 colm 349768 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r)
855 niq 170729 {
856 chrisd 491729 ap_dbd_t *rec;
857 chrisd 481509
858     while (!ap_is_initial_req(r)) {
859     if (r->prev) {
860     r = r->prev;
861     }
862     else if (r->main) {
863     r = r->main;
864     }
865     }
866    
867 chrisd 491729 rec = ap_get_module_config(r->request_config, &dbd_module);
868     if (!rec) {
869     rec = ap_dbd_open(r->pool, r->server);
870     if (rec) {
871     ap_set_module_config(r->request_config, &dbd_module, rec);
872 niq 170729 }
873     }
874 chrisd 491729
875     return rec;
876 niq 170729 }
877 chrisd 491729
878 colm 349768 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c)
879 niq 307439 {
880 chrisd 491729 ap_dbd_t *rec = ap_get_module_config(c->conn_config, &dbd_module);
881    
882     if (!rec) {
883     rec = ap_dbd_open(c->pool, c->base_server);
884     if (rec) {
885     ap_set_module_config(c->conn_config, &dbd_module, rec);
886 niq 307439 }
887     }
888 chrisd 491729
889     return rec;
890 niq 307439 }
891 niq 170729 #endif
892    
893     static void dbd_hooks(apr_pool_t *pool)
894     {
895 chrisd 491729 ap_hook_pre_config(dbd_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
896     ap_hook_post_config(dbd_post_config, NULL, NULL, APR_HOOK_MIDDLE);
897 niq 348026 ap_hook_child_init((void*)dbd_setup_init, NULL, NULL, APR_HOOK_MIDDLE);
898 chrisd 491729
899     APR_REGISTER_OPTIONAL_FN(ap_dbd_prepare);
900 niq 170729 APR_REGISTER_OPTIONAL_FN(ap_dbd_open);
901     APR_REGISTER_OPTIONAL_FN(ap_dbd_close);
902     APR_REGISTER_OPTIONAL_FN(ap_dbd_acquire);
903 niq 307439 APR_REGISTER_OPTIONAL_FN(ap_dbd_cacquire);
904 chrisd 491729
905 niq 170729 apr_dbd_init(pool);
906     }
907    
908     module AP_MODULE_DECLARE_DATA dbd_module = {
909     STANDARD20_MODULE_STUFF,
910     NULL,
911     NULL,
912 chrisd 491729 create_dbd_config,
913     merge_dbd_config,
914 niq 170729 dbd_cmds,
915     dbd_hooks
916     };
917 chrisd 491729

Properties

Name Value
svn:eol-style native

apache@apache.org
ViewVC Help
Powered by ViewVC 1.1.2