/[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 689224 - (hide annotations)
Tue Aug 26 21:03:46 2008 UTC (15 months ago) by niq
File MIME type: text/plain
File size: 27579 byte(s)
Try to get a meaningful error message when dbd_open fails
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     static const char *dbd_param(cmd_parms *cmd, void *dconf, const char *val)
145 niq 170729 {
146 niq 231464 const apr_dbd_driver_t *driver = NULL;
147 chrisd 491729 svr_cfg *svr = ap_get_module_config(cmd->server->module_config,
148     &dbd_module);
149 chrisd 503931 dbd_cfg_t *cfg = svr->cfg;
150 niq 170729
151 niq 291100 switch ((long) cmd->info) {
152 niq 170729 case cmd_name:
153 chrisd 503931 cfg->name = val;
154 niq 170729 /* loading the driver involves once-only dlloading that is
155     * best done at server startup. This also guarantees that
156 niq 345040 * we won't return an error later.
157 niq 170729 */
158 chrisd 503931 switch (apr_dbd_get_driver(cmd->pool, cfg->name, &driver)) {
159 niq 170729 case APR_ENOTIMPL:
160 chrisd 503931 return apr_psprintf(cmd->pool, "DBD: No driver for %s", cfg->name);
161 niq 170729 case APR_EDSOOPEN:
162     return apr_psprintf(cmd->pool,
163 fuankg 553563 #ifdef NETWARE
164     "DBD: Can't load driver file dbd%s.nlm",
165     #else
166     "DBD: Can't load driver file apr_dbd_%s.so",
167     #endif
168 chrisd 503931 cfg->name);
169 niq 170729 case APR_ESYMNOTFOUND:
170     return apr_psprintf(cmd->pool,
171     "DBD: Failed to load driver apr_dbd_%s_driver",
172 chrisd 503931 cfg->name);
173 niq 170729 }
174     break;
175     case cmd_params:
176 chrisd 503931 cfg->params = val;
177 niq 170729 break;
178 chrisd 646453 }
179    
180     return NULL;
181     }
182    
183 niq 170729 #if APR_HAS_THREADS
184 chrisd 646453 static const char *dbd_param_int(cmd_parms *cmd, void *dconf, const char *val)
185     {
186     svr_cfg *svr = ap_get_module_config(cmd->server->module_config,
187     &dbd_module);
188     dbd_cfg_t *cfg = svr->cfg;
189     const char *p;
190    
191     for (p = val; *p; ++p) {
192     if (!apr_isdigit(*p)) {
193     return "Argument must be numeric!";
194     }
195     }
196    
197     switch ((long) cmd->info) {
198 niq 170729 case cmd_min:
199 chrisd 503931 cfg->nmin = atoi(val);
200     cfg->set |= NMIN_SET;
201 niq 170729 break;
202     case cmd_keep:
203 chrisd 503931 cfg->nkeep = atoi(val);
204     cfg->set |= NKEEP_SET;
205 niq 170729 break;
206     case cmd_max:
207 chrisd 503931 cfg->nmax = atoi(val);
208     cfg->set |= NMAX_SET;
209 niq 170729 break;
210     case cmd_exp:
211 chrisd 503931 cfg->exptime = atoi(val);
212     cfg->set |= EXPTIME_SET;
213 niq 170729 break;
214     }
215 chrisd 491729
216 niq 170729 return NULL;
217     }
218 chrisd 646453 #endif
219 chrisd 491729
220     static const char *dbd_param_flag(cmd_parms *cmd, void *dconf, int flag)
221 niq 348026 {
222 chrisd 491729 svr_cfg *svr = ap_get_module_config(cmd->server->module_config,
223     &dbd_module);
224 niq 348026
225     switch ((long) cmd->info) {
226     case cmd_persist:
227 chrisd 503931 svr->cfg->persist = flag;
228 niq 348026 break;
229     }
230 chrisd 491729
231 niq 348026 return NULL;
232     }
233 chrisd 491729
234     static const char *dbd_prepare(cmd_parms *cmd, void *dconf, const char *query,
235 niq 234017 const char *label)
236     {
237 chrisd 503931 if (!label) {
238     label = query;
239     query = "";
240     }
241    
242 niq 234017 ap_dbd_prepare(cmd->server, query, label);
243 chrisd 491729
244 niq 170729 return NULL;
245     }
246 chrisd 491729
247 niq 170729 static const command_rec dbd_cmds[] = {
248     AP_INIT_TAKE1("DBDriver", dbd_param, (void*)cmd_name, RSRC_CONF,
249     "SQL Driver"),
250     AP_INIT_TAKE1("DBDParams", dbd_param, (void*)cmd_params, RSRC_CONF,
251     "SQL Driver Params"),
252 niq 348026 AP_INIT_FLAG("DBDPersist", dbd_param_flag, (void*)cmd_persist, RSRC_CONF,
253     "Use persistent connection/pool"),
254 chrisd 503931 AP_INIT_TAKE12("DBDPrepareSQL", dbd_prepare, NULL, RSRC_CONF,
255     "SQL statement to prepare (or nothing, to override "
256     "statement inherited from main server) and label"),
257 niq 170729 #if APR_HAS_THREADS
258 chrisd 646453 AP_INIT_TAKE1("DBDMin", dbd_param_int, (void*)cmd_min, RSRC_CONF,
259 niq 170729 "Minimum number of connections"),
260 niq 348026 /* XXX: note that mod_proxy calls this "smax" */
261 chrisd 646453 AP_INIT_TAKE1("DBDKeep", dbd_param_int, (void*)cmd_keep, RSRC_CONF,
262 niq 170729 "Maximum number of sustained connections"),
263 chrisd 646453 AP_INIT_TAKE1("DBDMax", dbd_param_int, (void*)cmd_max, RSRC_CONF,
264 niq 170729 "Maximum number of connections"),
265 niq 348026 /* XXX: note that mod_proxy calls this "ttl" (time to live) */
266 chrisd 646453 AP_INIT_TAKE1("DBDExptime", dbd_param_int, (void*)cmd_exp, RSRC_CONF,
267 niq 170729 "Keepalive time for idle connections"),
268     #endif
269     {NULL}
270     };
271 chrisd 491729
272     static int dbd_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
273     apr_pool_t *ptemp)
274     {
275 chrisd 503931 config_pool = pconf;
276     group_list = NULL;
277 chrisd 491729 return OK;
278 niq 348026 }
279 chrisd 491729
280 wrowe 664160 DBD_DECLARE_NONSTD(void) ap_dbd_prepare(server_rec *s, const char *query,
281     const char *label)
282 niq 170729 {
283 chrisd 503931 svr_cfg *svr;
284 chrisd 491729
285 chrisd 503931 svr = ap_get_module_config(s->module_config, &dbd_module);
286     if (!svr) {
287     /* some modules may call from within config directive handlers, and
288     * if these are called in a server context that contains no mod_dbd
289     * config directives, then we have to create our own server config
290     */
291     svr = create_dbd_config(config_pool, s);
292     ap_set_module_config(s->module_config, &dbd_module, svr);
293     }
294 chrisd 491729
295 chrisd 503931 if (apr_hash_get(svr->cfg->queries, label, APR_HASH_KEY_STRING)
296     && strcmp(query, "")) {
297     ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
298     "conflicting SQL statements with label %s", label);
299     }
300    
301     apr_hash_set(svr->cfg->queries, label, APR_HASH_KEY_STRING, query);
302 niq 170729 }
303 chrisd 491729
304 chrisd 503931 typedef struct {
305     const char *label, *query;
306     } dbd_query_t;
307    
308 chrisd 491729 static int dbd_post_config(apr_pool_t *pconf, apr_pool_t *plog,
309     apr_pool_t *ptemp, server_rec *s)
310     {
311     server_rec *sp;
312 chrisd 503931 apr_array_header_t *add_queries = apr_array_make(ptemp, 10,
313     sizeof(dbd_query_t));
314 chrisd 491729
315     for (sp = s; sp; sp = sp->next) {
316     svr_cfg *svr = ap_get_module_config(sp->module_config, &dbd_module);
317 chrisd 503931 dbd_cfg_t *cfg = svr->cfg;
318     apr_hash_index_t *hi_first = apr_hash_first(ptemp, cfg->queries);
319     dbd_group_t *group;
320 chrisd 491729
321 chrisd 503931 /* dbd_setup in 2.2.3 and under was causing spurious error messages
322     * when dbd isn't configured. We can stop that with a quick check here
323     * together with a similar check in ap_dbd_open (where being
324     * unconfigured is a genuine error that must be reported).
325     */
326     if (cfg->name == no_dbdriver || !cfg->persist) {
327     continue;
328     }
329    
330     for (group = group_list; group; group = group->next) {
331     dbd_cfg_t *group_cfg = group->cfg;
332     apr_hash_index_t *hi;
333     int group_ok = 1;
334    
335     if (strcmp(cfg->name, group_cfg->name)
336     || strcmp(cfg->params, group_cfg->params)) {
337     continue;
338     }
339    
340     #if APR_HAS_THREADS
341     if (cfg->nmin != group_cfg->nmin
342     || cfg->nkeep != group_cfg->nkeep
343     || cfg->nmax != group_cfg->nmax
344     || cfg->exptime != group_cfg->exptime) {
345     continue;
346     }
347     #endif
348    
349     add_queries->nelts = 0;
350    
351     for (hi = hi_first; hi; hi = apr_hash_next(hi)) {
352     const char *label, *query;
353     const char *group_query;
354    
355     apr_hash_this(hi, (void*) &label, NULL, (void*) &query);
356    
357     group_query = apr_hash_get(group_cfg->queries, label,
358     APR_HASH_KEY_STRING);
359    
360     if (!group_query) {
361     dbd_query_t *add_query = apr_array_push(add_queries);
362    
363     add_query->label = label;
364     add_query->query = query;
365     }
366     else if (strcmp(query, group_query)) {
367     group_ok = 0;
368     break;
369     }
370     }
371    
372     if (group_ok) {
373     int i;
374    
375     for (i = 0; i < add_queries->nelts; ++i) {
376     dbd_query_t *add_query = ((dbd_query_t*) add_queries->elts)
377     + i;
378    
379     apr_hash_set(group_cfg->queries, add_query->label,
380     APR_HASH_KEY_STRING, add_query->query);
381     }
382    
383     svr->group = group;
384     break;
385     }
386     }
387    
388     if (!svr->group) {
389     svr->group = group = apr_pcalloc(pconf, sizeof(dbd_group_t));
390    
391     group->cfg = cfg;
392    
393     group->next = group_list;
394     group_list = group;
395     }
396 chrisd 491729 }
397    
398     return OK;
399     }
400    
401 chrisd 503931 static apr_status_t dbd_prepared_init(apr_pool_t *pool, dbd_cfg_t *cfg,
402 chrisd 491729 ap_dbd_t *rec)
403 niq 170729 {
404 chrisd 503931 apr_hash_index_t *hi;
405 chrisd 491729 apr_status_t rv = APR_SUCCESS;
406 niq 170729
407 chrisd 491729 rec->prepared = apr_hash_make(pool);
408    
409 chrisd 503931 for (hi = apr_hash_first(pool, cfg->queries); hi;
410     hi = apr_hash_next(hi)) {
411     const char *label, *query;
412     apr_dbd_prepared_t *stmt;
413    
414     apr_hash_this(hi, (void*) &label, NULL, (void*) &query);
415    
416     if (!strcmp(query, "")) {
417     continue;
418     }
419    
420 niq 344140 stmt = NULL;
421 chrisd 503931 if (apr_dbd_prepare(rec->driver, pool, rec->handle, query,
422     label, &stmt)) {
423     rv = APR_EGENERAL;
424 niq 170729 }
425     else {
426 chrisd 503931 apr_hash_set(rec->prepared, label, APR_HASH_KEY_STRING, stmt);
427 niq 170729 }
428     }
429 chrisd 491729
430     return rv;
431 niq 170729 }
432 chrisd 491729
433     static apr_status_t dbd_close(void *data)
434     {
435     ap_dbd_t *rec = data;
436    
437 chrisd 496831 return apr_dbd_close(rec->driver, rec->handle);
438 chrisd 491729 }
439    
440     #if APR_HAS_THREADS
441     static apr_status_t dbd_destruct(void *data, void *params, apr_pool_t *pool)
442     {
443 chrisd 503931 dbd_group_t *group = params;
444 chrisd 496831
445 chrisd 503931 if (!group->destroyed) {
446 chrisd 496831 ap_dbd_t *rec = data;
447    
448     apr_pool_destroy(rec->pool);
449     }
450    
451     return APR_SUCCESS;
452 chrisd 491729 }
453     #endif
454    
455 niq 234017 /* an apr_reslist_constructor for SQL connections
456     * Also use this for opening in non-reslist modes, since it gives
457     * us all the error-handling in one place.
458     */
459 chrisd 491729 static apr_status_t dbd_construct(void **data_ptr,
460     void *params, apr_pool_t *pool)
461 niq 170729 {
462 chrisd 503931 dbd_group_t *group = params;
463     dbd_cfg_t *cfg = group->cfg;
464 chrisd 496831 apr_pool_t *rec_pool, *prepared_pool;
465     ap_dbd_t *rec;
466 niq 348026 apr_status_t rv;
467 niq 689224 const char *err = "";
468 niq 170729
469 chrisd 496831 rv = apr_pool_create(&rec_pool, pool);
470 niq 348026 if (rv != APR_SUCCESS) {
471 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, cfg->server,
472 chrisd 491884 "DBD: Failed to create memory pool");
473     return rv;
474 niq 348026 }
475    
476 chrisd 496831 rec = apr_pcalloc(rec_pool, sizeof(ap_dbd_t));
477    
478     rec->pool = rec_pool;
479    
480 chrisd 491729 /* The driver is loaded at config time now, so this just checks a hash.
481     * If that changes, the driver DSO could be registered to unload against
482     * our pool, which is probably not what we want. Error checking isn't
483     * necessary now, but in case that changes in the future ...
484     */
485 chrisd 503931 rv = apr_dbd_get_driver(rec->pool, cfg->name, &rec->driver);
486 chrisd 491729 if (rv != APR_SUCCESS) {
487     switch (rv) {
488     case APR_ENOTIMPL:
489 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
490     "DBD: driver for %s not available", cfg->name);
491 chrisd 491729 break;
492     case APR_EDSOOPEN:
493 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
494     "DBD: can't find driver for %s", cfg->name);
495 chrisd 491729 break;
496     case APR_ESYMNOTFOUND:
497 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
498 chrisd 491884 "DBD: driver for %s is invalid or corrupted",
499 chrisd 503931 cfg->name);
500 chrisd 491729 break;
501     default:
502 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
503 chrisd 491884 "DBD: mod_dbd not compatible with APR in get_driver");
504 chrisd 491729 break;
505     }
506    
507 chrisd 491884 apr_pool_destroy(rec->pool);
508 niq 234017 return rv;
509     }
510    
511 niq 689224 rv = apr_dbd_open_ex(rec->driver, rec->pool, cfg->params, &rec->handle, &err);
512 chrisd 491729 if (rv != APR_SUCCESS) {
513     switch (rv) {
514     case APR_EGENERAL:
515 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
516 niq 689224 "DBD: Can't connect to %s: %s", cfg->name, &err);
517 chrisd 491729 break;
518     default:
519 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
520 chrisd 491884 "DBD: mod_dbd not compatible with APR in open");
521 chrisd 491729 break;
522     }
523    
524 chrisd 491884 apr_pool_destroy(rec->pool);
525 niq 170729 return rv;
526     }
527 chrisd 491729
528 chrisd 496831 apr_pool_cleanup_register(rec->pool, rec, dbd_close,
529     apr_pool_cleanup_null);
530    
531     /* we use a sub-pool for the prepared statements for each connection so
532     * that they will be cleaned up first, before the connection is closed
533     */
534     rv = apr_pool_create(&prepared_pool, rec->pool);
535 niq 386321 if (rv != APR_SUCCESS) {
536 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, cfg->server,
537 chrisd 496831 "DBD: Failed to create memory pool");
538    
539     apr_pool_destroy(rec->pool);
540     return rv;
541     }
542    
543 chrisd 503931 rv = dbd_prepared_init(prepared_pool, cfg, rec);
544 chrisd 496831 if (rv != APR_SUCCESS) {
545 niq 424798 const char *errmsg = apr_dbd_error(rec->driver, rec->handle, rv);
546 chrisd 503931 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
547 chrisd 491884 "DBD: failed to prepare SQL statements: %s",
548     (errmsg ? errmsg : "[???]"));
549    
550     apr_pool_destroy(rec->pool);
551     return rv;
552 niq 386321 }
553 chrisd 491729
554 chrisd 491884 *data_ptr = rec;
555    
556     return APR_SUCCESS;
557 niq 170729 }
558 chrisd 491729
559 niq 234017 #if APR_HAS_THREADS
560 chrisd 496831 static apr_status_t dbd_destroy(void *data)
561 niq 170729 {
562 chrisd 503931 dbd_group_t *group = data;
563 chrisd 496831
564 chrisd 503931 group->destroyed = 1;
565 chrisd 496831
566     return APR_SUCCESS;
567     }
568    
569 chrisd 503931 static apr_status_t dbd_setup(server_rec *s, dbd_group_t *group)
570 chrisd 496831 {
571 chrisd 503931 dbd_cfg_t *cfg = group->cfg;
572 niq 348026 apr_status_t rv;
573    
574 chrisd 496831 /* We create the reslist using a sub-pool of the pool passed to our
575     * child_init hook. No other threads can be here because we're
576     * either in the child_init phase or dbd_setup_lock() acquired our mutex.
577     * No other threads will use this sub-pool after this, except via
578     * reslist calls, which have an internal mutex.
579     *
580     * We need to short-circuit the cleanup registered internally by
581     * apr_reslist_create(). We do this by registering dbd_destroy()
582     * as a cleanup afterwards, so that it will run before the reslist's
583     * internal cleanup.
584     *
585     * If we didn't do this, then we could free memory twice when the pool
586     * was destroyed. When apr_pool_destroy() runs, it first destroys all
587     * all the per-connection sub-pools created in dbd_construct(), and
588     * then it runs the reslist's cleanup. The cleanup calls dbd_destruct()
589     * on each resource, which would then attempt to destroy the sub-pools
590     * a second time.
591 niq 348026 */
592 chrisd 503931 rv = apr_reslist_create(&group->reslist,
593     cfg->nmin, cfg->nkeep, cfg->nmax,
594     apr_time_from_sec(cfg->exptime),
595     dbd_construct, dbd_destruct, group,
596     group->pool);
597 chrisd 491884 if (rv != APR_SUCCESS) {
598     ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
599     "DBD: failed to initialise");
600     return rv;
601 niq 170729 }
602 niq 348026
603 chrisd 503931 apr_pool_cleanup_register(group->pool, group, dbd_destroy,
604 chrisd 496831 apr_pool_cleanup_null);
605    
606 chrisd 491884 return APR_SUCCESS;
607 niq 170729 }
608 chrisd 496831 #endif
609 chrisd 491729
610 niq 348026 static apr_status_t dbd_setup_init(apr_pool_t *pool, server_rec *s)
611     {
612 chrisd 503931 dbd_group_t *group;
613     apr_status_t rv = APR_SUCCESS;
614 niq 170729
615 chrisd 503931 for (group = group_list; group; group = group->next) {
616     apr_status_t rv2;
617 niq 485311
618 chrisd 503931 rv2 = apr_pool_create(&group->pool, pool);
619     if (rv2 != APR_SUCCESS) {
620     ap_log_error(APLOG_MARK, APLOG_CRIT, rv2, s,
621     "DBD: Failed to create reslist cleanup memory pool");
622     return rv2;
623     }
624 niq 348026
625 chrisd 496831 #if APR_HAS_THREADS
626 chrisd 503931 rv2 = dbd_setup(s, group);
627     if (rv2 == APR_SUCCESS) {
628     continue;
629     }
630     else if (rv == APR_SUCCESS) {
631     rv = rv2;
632     }
633 niq 348026
634 chrisd 503931 /* we failed, so create a mutex so that subsequent competing callers
635     * to ap_dbd_open can serialize themselves while they retry
636     */
637     rv2 = apr_thread_mutex_create(&group->mutex,
638     APR_THREAD_MUTEX_DEFAULT, pool);
639     if (rv2 != APR_SUCCESS) {
640     ap_log_error(APLOG_MARK, APLOG_CRIT, rv2, s,
641     "DBD: Failed to create thread mutex");
642     return rv2;
643     }
644     #endif
645 niq 348026 }
646 chrisd 491729
647 niq 348026 return rv;
648     }
649 chrisd 491729
650 chrisd 496831 #if APR_HAS_THREADS
651 chrisd 503931 static apr_status_t dbd_setup_lock(server_rec *s, dbd_group_t *group)
652 niq 348026 {
653 chrisd 491729 apr_status_t rv = APR_SUCCESS, rv2;
654 niq 348026
655     /* several threads could be here at the same time, all trying to
656     * initialize the reslist because dbd_setup_init failed to do so
657     */
658 chrisd 503931 if (!group->mutex) {
659 niq 348026 /* we already logged an error when the mutex couldn't be created */
660     return APR_EGENERAL;
661     }
662    
663 chrisd 503931 rv2 = apr_thread_mutex_lock(group->mutex);
664 chrisd 491729 if (rv2 != APR_SUCCESS) {
665 chrisd 491884 ap_log_error(APLOG_MARK, APLOG_ERR, rv2, s,
666     "DBD: Failed to acquire thread mutex");
667 chrisd 491729 return rv2;
668 niq 348026 }
669    
670 chrisd 503931 if (!group->reslist) {
671     rv = dbd_setup(s, group);
672 niq 348026 }
673    
674 chrisd 503931 rv2 = apr_thread_mutex_unlock(group->mutex);
675 chrisd 491729 if (rv2 != APR_SUCCESS) {
676 chrisd 491884 ap_log_error(APLOG_MARK, APLOG_ERR, rv2, s,
677     "DBD: Failed to release thread mutex");
678 chrisd 491729 if (rv == APR_SUCCESS) {
679     rv = rv2;
680 niq 348026 }
681     }
682 chrisd 491729
683     return rv;
684 niq 348026 }
685 niq 170729 #endif
686    
687     /* Functions we export for modules to use:
688     - open acquires a connection from the pool (opens one if necessary)
689     - close releases it back in to the pool
690     */
691 wrowe 664160 DBD_DECLARE_NONSTD(void) ap_dbd_close(server_rec *s, ap_dbd_t *rec)
692 niq 345040 {
693     svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
694 chrisd 491729
695 chrisd 503931 if (!svr->cfg->persist) {
696 chrisd 496831 apr_pool_destroy(rec->pool);
697 niq 345040 }
698     #if APR_HAS_THREADS
699     else {
700 chrisd 503931 apr_reslist_release(svr->group->reslist, rec);
701 niq 345040 }
702     #endif
703     }
704 chrisd 491729
705 chrisd 491884 static apr_status_t dbd_check(apr_pool_t *pool, server_rec *s, ap_dbd_t *rec)
706     {
707     svr_cfg *svr;
708     apr_status_t rv = apr_dbd_check_conn(rec->driver, pool, rec->handle);
709     const char *errmsg;
710 chrisd 491729
711 chrisd 491884 if ((rv == APR_SUCCESS) || (rv == APR_ENOTIMPL)) {
712     return APR_SUCCESS;
713     }
714    
715 chrisd 539687 /* we don't have a driver-specific error code, so we'll just pass
716     * a "success" value and rely on the driver to ignore it
717     */
718     errmsg = apr_dbd_error(rec->driver, rec->handle, 0);
719 chrisd 491884 if (!errmsg) {
720     errmsg = "(unknown)";
721     }
722    
723     svr = ap_get_module_config(s->module_config, &dbd_module);
724     ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
725 chrisd 503931 "DBD [%s] Error: %s", svr->cfg->name, errmsg);
726 chrisd 491884 return rv;
727     }
728    
729 wrowe 664160 DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open(apr_pool_t *pool, server_rec *s)
730 niq 170729 {
731 chrisd 491729 svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
732 chrisd 503931 dbd_group_t *group = svr->group;
733     dbd_cfg_t *cfg = svr->cfg;
734 chrisd 491884 ap_dbd_t *rec = NULL;
735     #if APR_HAS_THREADS
736     apr_status_t rv;
737     #endif
738 niq 170729
739 niq 485311 /* If nothing is configured, we shouldn't be here */
740 chrisd 503931 if (cfg->name == no_dbdriver) {
741 chrisd 491884 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "DBD: not configured");
742 niq 485311 return NULL;
743     }
744    
745 chrisd 503931 if (!cfg->persist) {
746 niq 234017 /* Return a once-only connection */
747 chrisd 503931 group = apr_pcalloc(pool, sizeof(dbd_group_t));
748    
749     group->cfg = cfg;
750    
751     dbd_construct((void*) &rec, group, pool);
752 chrisd 491884 return rec;
753 niq 170729 }
754    
755 chrisd 491884 #if APR_HAS_THREADS
756 chrisd 503931 if (!group->reslist) {
757     if (dbd_setup_lock(s, group) != APR_SUCCESS) {
758 niq 170729 return NULL;
759     }
760     }
761 chrisd 491729
762 chrisd 503931 rv = apr_reslist_acquire(group->reslist, (void*) &rec);
763 niq 348026 if (rv != APR_SUCCESS) {
764 chrisd 491884 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
765     "Failed to acquire DBD connection from pool!");
766 niq 170729 return NULL;
767     }
768 chrisd 491729
769 chrisd 491884 if (dbd_check(pool, s, rec) != APR_SUCCESS) {
770 chrisd 503931 apr_reslist_invalidate(group->reslist, rec);
771 niq 170729 return NULL;
772     }
773     #else
774 chrisd 491729 /* If we have a persistent connection and it's good, we'll use it;
775     * since this is non-threaded, we can update without a mutex
776     */
777 chrisd 503931 rec = group->rec;
778     if (rec) {
779 chrisd 491884 if (dbd_check(pool, s, rec) != APR_SUCCESS) {
780 chrisd 496831 apr_pool_destroy(rec->pool);
781 chrisd 491884 rec = NULL;
782 niq 170729 }
783     }
784 chrisd 491729
785     /* We don't have a connection right now, so we'll open one */
786 chrisd 491884 if (!rec) {
787 chrisd 503931 dbd_construct((void*) &rec, group, group->pool);
788     group->rec = rec;
789 niq 170729 }
790 chrisd 491884 #endif
791 chrisd 491729
792 chrisd 491884 return rec;
793 niq 170729 }
794 chrisd 491729
795 niq 170729 #if APR_HAS_THREADS
796     typedef struct {
797 chrisd 491729 ap_dbd_t *rec;
798     apr_reslist_t *reslist;
799     } dbd_acquire_t;
800    
801     static apr_status_t dbd_release(void *data)
802 niq 170729 {
803 chrisd 491729 dbd_acquire_t *acq = data;
804     apr_reslist_release(acq->reslist, acq->rec);
805 niq 170729 return APR_SUCCESS;
806     }
807 chrisd 491729
808 wrowe 664160 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r)
809 niq 170729 {
810 chrisd 491729 dbd_acquire_t *acq;
811 chrisd 481509
812     while (!ap_is_initial_req(r)) {
813     if (r->prev) {
814     r = r->prev;
815     }
816     else if (r->main) {
817     r = r->main;
818     }
819     }
820    
821 chrisd 491729 acq = ap_get_module_config(r->request_config, &dbd_module);
822     if (!acq) {
823     acq = apr_palloc(r->pool, sizeof(dbd_acquire_t));
824     acq->rec = ap_dbd_open(r->pool, r->server);
825     if (acq->rec) {
826     svr_cfg *svr = ap_get_module_config(r->server->module_config,
827     &dbd_module);
828    
829     ap_set_module_config(r->request_config, &dbd_module, acq);
830 chrisd 503931 if (svr->cfg->persist) {
831     acq->reslist = svr->group->reslist;
832 chrisd 491729 apr_pool_cleanup_register(r->pool, acq, dbd_release,
833 niq 170729 apr_pool_cleanup_null);
834     }
835     }
836     }
837 chrisd 491729
838     return acq->rec;
839 niq 170729 }
840 chrisd 491729
841 wrowe 664160 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c)
842 niq 307439 {
843 chrisd 491729 dbd_acquire_t *acq = ap_get_module_config(c->conn_config, &dbd_module);
844    
845     if (!acq) {
846     acq = apr_palloc(c->pool, sizeof(dbd_acquire_t));
847     acq->rec = ap_dbd_open(c->pool, c->base_server);
848     if (acq->rec) {
849     svr_cfg *svr = ap_get_module_config(c->base_server->module_config,
850     &dbd_module);
851    
852     ap_set_module_config(c->conn_config, &dbd_module, acq);
853 chrisd 503931 if (svr->cfg->persist) {
854     acq->reslist = svr->group->reslist;
855 chrisd 491729 apr_pool_cleanup_register(c->pool, acq, dbd_release,
856 niq 307439 apr_pool_cleanup_null);
857     }
858     }
859     }
860 chrisd 491729
861     return acq->rec;
862 niq 307439 }
863 niq 170729 #else
864 wrowe 664160 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r)
865 niq 170729 {
866 chrisd 491729 ap_dbd_t *rec;
867 chrisd 481509
868     while (!ap_is_initial_req(r)) {
869     if (r->prev) {
870     r = r->prev;
871     }
872     else if (r->main) {
873     r = r->main;
874     }
875     }
876    
877 chrisd 491729 rec = ap_get_module_config(r->request_config, &dbd_module);
878     if (!rec) {
879     rec = ap_dbd_open(r->pool, r->server);
880     if (rec) {
881     ap_set_module_config(r->request_config, &dbd_module, rec);
882 niq 170729 }
883     }
884 chrisd 491729
885     return rec;
886 niq 170729 }
887 chrisd 491729
888 wrowe 664160 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c)
889 niq 307439 {
890 chrisd 491729 ap_dbd_t *rec = ap_get_module_config(c->conn_config, &dbd_module);
891    
892     if (!rec) {
893     rec = ap_dbd_open(c->pool, c->base_server);
894     if (rec) {
895     ap_set_module_config(c->conn_config, &dbd_module, rec);
896 niq 307439 }
897     }
898 chrisd 491729
899     return rec;
900 niq 307439 }
901 niq 170729 #endif
902    
903     static void dbd_hooks(apr_pool_t *pool)
904     {
905 chrisd 491729 ap_hook_pre_config(dbd_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
906     ap_hook_post_config(dbd_post_config, NULL, NULL, APR_HOOK_MIDDLE);
907 niq 348026 ap_hook_child_init((void*)dbd_setup_init, NULL, NULL, APR_HOOK_MIDDLE);
908 chrisd 491729
909     APR_REGISTER_OPTIONAL_FN(ap_dbd_prepare);
910 niq 170729 APR_REGISTER_OPTIONAL_FN(ap_dbd_open);
911     APR_REGISTER_OPTIONAL_FN(ap_dbd_close);
912     APR_REGISTER_OPTIONAL_FN(ap_dbd_acquire);
913 niq 307439 APR_REGISTER_OPTIONAL_FN(ap_dbd_cacquire);
914 chrisd 491729
915 niq 170729 apr_dbd_init(pool);
916     }
917    
918     module AP_MODULE_DECLARE_DATA dbd_module = {
919     STANDARD20_MODULE_STUFF,
920     NULL,
921     NULL,
922 chrisd 491729 create_dbd_config,
923     merge_dbd_config,
924 niq 170729 dbd_cmds,
925     dbd_hooks
926     };
927 chrisd 491729

Properties

Name Value
svn:eol-style native

apache@apache.org
ViewVC Help
Powered by ViewVC 1.1.2