/[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 - (show 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 /* 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 *
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 #include "apr_reslist.h"
24 #include "apr_strings.h"
25 #include "apr_hash.h"
26 #include "apr_tables.h"
27 #include "apr_lib.h"
28 #include "apr_dbd.h"
29
30 #define APR_WANT_MEMFUNC
31 #define APR_WANT_STRFUNC
32 #include "apr_want.h"
33
34 #include "http_protocol.h"
35 #include "http_config.h"
36 #include "http_log.h"
37 #include "http_request.h"
38 #include "mod_dbd.h"
39
40 extern module AP_MODULE_DECLARE_DATA dbd_module;
41
42 /************ svr cfg: manage db connection pool ****************/
43
44 #define NMIN_SET 0x1
45 #define NKEEP_SET 0x2
46 #define NMAX_SET 0x4
47 #define EXPTIME_SET 0x8
48
49 typedef struct {
50 server_rec *server;
51 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 int set;
60 #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 #else
75 ap_dbd_t *rec;
76 #endif
77 };
78
79 typedef struct {
80 dbd_cfg_t *cfg;
81 dbd_group_t *group;
82 } 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 static apr_pool_t *config_pool;
89 static dbd_group_t *group_list;
90
91 /* a default DBDriver value that'll generate meaningful error messages */
92 static const char *const no_dbdriver = "[DBDriver unset]";
93
94 /* 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 dbd_cfg_t *cfg = svr->cfg = apr_pcalloc(pool, sizeof(dbd_cfg_t));
106
107 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 #if APR_HAS_THREADS
112 cfg->nmin = DEFAULT_NMIN;
113 cfg->nkeep = DEFAULT_NKEEP;
114 cfg->nmax = DEFAULT_NMAX;
115 cfg->exptime = DEFAULT_EXPTIME;
116 #endif
117 cfg->queries = apr_hash_make(pool);
118
119 return svr;
120 }
121
122 static void *merge_dbd_config(apr_pool_t *pool, void *basev, void *addv)
123 {
124 dbd_cfg_t *base = ((svr_cfg*) basev)->cfg;
125 dbd_cfg_t *add = ((svr_cfg*) addv)->cfg;
126 svr_cfg *svr = apr_pcalloc(pool, sizeof(svr_cfg));
127 dbd_cfg_t *new = svr->cfg = apr_pcalloc(pool, sizeof(dbd_cfg_t));
128
129 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 #if APR_HAS_THREADS
134 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 #endif
139 new->queries = apr_hash_overlay(pool, add->queries, base->queries);
140
141 return svr;
142 }
143
144 #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
154 static const char *dbd_param(cmd_parms *cmd, void *dconf, const char *val)
155 {
156 const apr_dbd_driver_t *driver = NULL;
157 svr_cfg *svr = ap_get_module_config(cmd->server->module_config,
158 &dbd_module);
159 dbd_cfg_t *cfg = svr->cfg;
160
161 switch ((long) cmd->info) {
162 case cmd_name:
163 cfg->name = val;
164 /* loading the driver involves once-only dlloading that is
165 * best done at server startup. This also guarantees that
166 * we won't return an error later.
167 */
168 switch (apr_dbd_get_driver(cmd->pool, cfg->name, &driver)) {
169 case APR_ENOTIMPL:
170 return apr_psprintf(cmd->pool, "DBD: No driver for %s", cfg->name);
171 case APR_EDSOOPEN:
172 return apr_psprintf(cmd->pool,
173 "DBD: Can't load driver file apr_dbd_%s.so",
174 cfg->name);
175 case APR_ESYMNOTFOUND:
176 return apr_psprintf(cmd->pool,
177 "DBD: Failed to load driver apr_dbd_%s_driver",
178 cfg->name);
179 }
180 break;
181 case cmd_params:
182 cfg->params = val;
183 break;
184 #if APR_HAS_THREADS
185 case cmd_min:
186 ISINT(val);
187 cfg->nmin = atoi(val);
188 cfg->set |= NMIN_SET;
189 break;
190 case cmd_keep:
191 ISINT(val);
192 cfg->nkeep = atoi(val);
193 cfg->set |= NKEEP_SET;
194 break;
195 case cmd_max:
196 ISINT(val);
197 cfg->nmax = atoi(val);
198 cfg->set |= NMAX_SET;
199 break;
200 case cmd_exp:
201 ISINT(val);
202 cfg->exptime = atoi(val);
203 cfg->set |= EXPTIME_SET;
204 break;
205 #endif
206 }
207
208 return NULL;
209 }
210
211 static const char *dbd_param_flag(cmd_parms *cmd, void *dconf, int flag)
212 {
213 svr_cfg *svr = ap_get_module_config(cmd->server->module_config,
214 &dbd_module);
215
216 switch ((long) cmd->info) {
217 case cmd_persist:
218 svr->cfg->persist = flag;
219 break;
220 }
221
222 return NULL;
223 }
224
225 static const char *dbd_prepare(cmd_parms *cmd, void *dconf, const char *query,
226 const char *label)
227 {
228 if (!label) {
229 label = query;
230 query = "";
231 }
232
233 ap_dbd_prepare(cmd->server, query, label);
234
235 return NULL;
236 }
237
238 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 AP_INIT_FLAG("DBDPersist", dbd_param_flag, (void*)cmd_persist, RSRC_CONF,
244 "Use persistent connection/pool"),
245 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 #if APR_HAS_THREADS
249 AP_INIT_TAKE1("DBDMin", dbd_param, (void*)cmd_min, RSRC_CONF,
250 "Minimum number of connections"),
251 /* XXX: note that mod_proxy calls this "smax" */
252 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 /* XXX: note that mod_proxy calls this "ttl" (time to live) */
257 AP_INIT_TAKE1("DBDExptime", dbd_param, (void*)cmd_exp, RSRC_CONF,
258 "Keepalive time for idle connections"),
259 #endif
260 {NULL}
261 };
262
263 static int dbd_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
264 apr_pool_t *ptemp)
265 {
266 config_pool = pconf;
267 group_list = NULL;
268 return OK;
269 }
270
271 DBD_DECLARE_NONSTD(void) ap_dbd_prepare(server_rec *s, const char *query,
272 const char *label)
273 {
274 svr_cfg *svr;
275
276 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
286 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 }
294
295 typedef struct {
296 const char *label, *query;
297 } dbd_query_t;
298
299 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 apr_array_header_t *add_queries = apr_array_make(ptemp, 10,
304 sizeof(dbd_query_t));
305
306 for (sp = s; sp; sp = sp->next) {
307 svr_cfg *svr = ap_get_module_config(sp->module_config, &dbd_module);
308 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
312 /* 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 }
388
389 return OK;
390 }
391
392 static apr_status_t dbd_prepared_init(apr_pool_t *pool, dbd_cfg_t *cfg,
393 ap_dbd_t *rec)
394 {
395 apr_hash_index_t *hi;
396 apr_status_t rv = APR_SUCCESS;
397
398 rec->prepared = apr_hash_make(pool);
399
400 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 stmt = NULL;
412 if (apr_dbd_prepare(rec->driver, pool, rec->handle, query,
413 label, &stmt)) {
414 rv = APR_EGENERAL;
415 }
416 else {
417 apr_hash_set(rec->prepared, label, APR_HASH_KEY_STRING, stmt);
418 }
419 }
420
421 return rv;
422 }
423
424 static apr_status_t dbd_close(void *data)
425 {
426 ap_dbd_t *rec = data;
427
428 return apr_dbd_close(rec->driver, rec->handle);
429 }
430
431 #if APR_HAS_THREADS
432 static apr_status_t dbd_destruct(void *data, void *params, apr_pool_t *pool)
433 {
434 dbd_group_t *group = params;
435
436 if (!group->destroyed) {
437 ap_dbd_t *rec = data;
438
439 apr_pool_destroy(rec->pool);
440 }
441
442 return APR_SUCCESS;
443 }
444 #endif
445
446 /* 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 static apr_status_t dbd_construct(void **data_ptr,
451 void *params, apr_pool_t *pool)
452 {
453 dbd_group_t *group = params;
454 dbd_cfg_t *cfg = group->cfg;
455 apr_pool_t *rec_pool, *prepared_pool;
456 ap_dbd_t *rec;
457 apr_status_t rv;
458
459 rv = apr_pool_create(&rec_pool, pool);
460 if (rv != APR_SUCCESS) {
461 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, cfg->server,
462 "DBD: Failed to create memory pool");
463 return rv;
464 }
465
466 rec = apr_pcalloc(rec_pool, sizeof(ap_dbd_t));
467
468 rec->pool = rec_pool;
469
470 /* 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 rv = apr_dbd_get_driver(rec->pool, cfg->name, &rec->driver);
476 if (rv != APR_SUCCESS) {
477 switch (rv) {
478 case APR_ENOTIMPL:
479 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
480 "DBD: driver for %s not available", cfg->name);
481 break;
482 case APR_EDSOOPEN:
483 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
484 "DBD: can't find driver for %s", cfg->name);
485 break;
486 case APR_ESYMNOTFOUND:
487 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
488 "DBD: driver for %s is invalid or corrupted",
489 cfg->name);
490 break;
491 default:
492 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
493 "DBD: mod_dbd not compatible with APR in get_driver");
494 break;
495 }
496
497 apr_pool_destroy(rec->pool);
498 return rv;
499 }
500
501 rv = apr_dbd_open(rec->driver, rec->pool, cfg->params, &rec->handle);
502 if (rv != APR_SUCCESS) {
503 switch (rv) {
504 case APR_EGENERAL:
505 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
506 "DBD: Can't connect to %s", cfg->name);
507 break;
508 default:
509 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
510 "DBD: mod_dbd not compatible with APR in open");
511 break;
512 }
513
514 apr_pool_destroy(rec->pool);
515 return rv;
516 }
517
518 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 if (rv != APR_SUCCESS) {
526 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, cfg->server,
527 "DBD: Failed to create memory pool");
528
529 apr_pool_destroy(rec->pool);
530 return rv;
531 }
532
533 rv = dbd_prepared_init(prepared_pool, cfg, rec);
534 if (rv != APR_SUCCESS) {
535 const char *errmsg = apr_dbd_error(rec->driver, rec->handle, rv);
536 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
537 "DBD: failed to prepare SQL statements: %s",
538 (errmsg ? errmsg : "[???]"));
539
540 apr_pool_destroy(rec->pool);
541 return rv;
542 }
543
544 *data_ptr = rec;
545
546 return APR_SUCCESS;
547 }
548
549 #if APR_HAS_THREADS
550 static apr_status_t dbd_destroy(void *data)
551 {
552 dbd_group_t *group = data;
553
554 group->destroyed = 1;
555
556 return APR_SUCCESS;
557 }
558
559 static apr_status_t dbd_setup(server_rec *s, dbd_group_t *group)
560 {
561 dbd_cfg_t *cfg = group->cfg;
562 apr_status_t rv;
563
564 /* 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 */
582 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 if (rv != APR_SUCCESS) {
588 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
589 "DBD: failed to initialise");
590 return rv;
591 }
592
593 apr_pool_cleanup_register(group->pool, group, dbd_destroy,
594 apr_pool_cleanup_null);
595
596 return APR_SUCCESS;
597 }
598 #endif
599
600 static apr_status_t dbd_setup_init(apr_pool_t *pool, server_rec *s)
601 {
602 dbd_group_t *group;
603 apr_status_t rv = APR_SUCCESS;
604
605 for (group = group_list; group; group = group->next) {
606 apr_status_t rv2;
607
608 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
615 #if APR_HAS_THREADS
616 rv2 = dbd_setup(s, group);
617 if (rv2 == APR_SUCCESS) {
618 continue;
619 }
620 else if (rv == APR_SUCCESS) {
621 rv = rv2;
622 }
623
624 /* 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 }
636
637 return rv;
638 }
639
640 #if APR_HAS_THREADS
641 static apr_status_t dbd_setup_lock(server_rec *s, dbd_group_t *group)
642 {
643 apr_status_t rv = APR_SUCCESS, rv2;
644
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 if (!group->mutex) {
649 /* we already logged an error when the mutex couldn't be created */
650 return APR_EGENERAL;
651 }
652
653 rv2 = apr_thread_mutex_lock(group->mutex);
654 if (rv2 != APR_SUCCESS) {
655 ap_log_error(APLOG_MARK, APLOG_ERR, rv2, s,
656 "DBD: Failed to acquire thread mutex");
657 return rv2;
658 }
659
660 if (!group->reslist) {
661 rv = dbd_setup(s, group);
662 }
663
664 rv2 = apr_thread_mutex_unlock(group->mutex);
665 if (rv2 != APR_SUCCESS) {
666 ap_log_error(APLOG_MARK, APLOG_ERR, rv2, s,
667 "DBD: Failed to release thread mutex");
668 if (rv == APR_SUCCESS) {
669 rv = rv2;
670 }
671 }
672
673 return rv;
674 }
675 #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 DBD_DECLARE_NONSTD(void) ap_dbd_close(server_rec *s, ap_dbd_t *rec)
682 {
683 svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
684
685 if (!svr->cfg->persist) {
686 apr_pool_destroy(rec->pool);
687 }
688 #if APR_HAS_THREADS
689 else {
690 apr_reslist_release(svr->group->reslist, rec);
691 }
692 #endif
693 }
694
695 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
701 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 "DBD [%s] Error: %s", svr->cfg->name, errmsg);
713 return rv;
714 }
715
716 DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open(apr_pool_t *pool, server_rec *s)
717 {
718 svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
719 dbd_group_t *group = svr->group;
720 dbd_cfg_t *cfg = svr->cfg;
721 ap_dbd_t *rec = NULL;
722 #if APR_HAS_THREADS
723 apr_status_t rv;
724 #endif
725
726 /* If nothing is configured, we shouldn't be here */
727 if (cfg->name == no_dbdriver) {
728 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "DBD: not configured");
729 return NULL;
730 }
731
732 if (!cfg->persist) {
733 /* Return a once-only connection */
734 group = apr_pcalloc(pool, sizeof(dbd_group_t));
735
736 group->cfg = cfg;
737
738 dbd_construct((void*) &rec, group, pool);
739 return rec;
740 }
741
742 #if APR_HAS_THREADS
743 if (!group->reslist) {
744 if (dbd_setup_lock(s, group) != APR_SUCCESS) {
745 return NULL;
746 }
747 }
748
749 rv = apr_reslist_acquire(group->reslist, (void*) &rec);
750 if (rv != APR_SUCCESS) {
751 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
752 "Failed to acquire DBD connection from pool!");
753 return NULL;
754 }
755
756 if (dbd_check(pool, s, rec) != APR_SUCCESS) {
757 apr_reslist_invalidate(group->reslist, rec);
758 return NULL;
759 }
760 #else
761 /* 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 rec = group->rec;
765 if (rec) {
766 if (dbd_check(pool, s, rec) != APR_SUCCESS) {
767 apr_pool_destroy(rec->pool);
768 rec = NULL;
769 }
770 }
771
772 /* We don't have a connection right now, so we'll open one */
773 if (!rec) {
774 dbd_construct((void*) &rec, group, group->pool);
775 group->rec = rec;
776 }
777 #endif
778
779 return rec;
780 }
781
782 #if APR_HAS_THREADS
783 typedef struct {
784 ap_dbd_t *rec;
785 apr_reslist_t *reslist;
786 } dbd_acquire_t;
787
788 static apr_status_t dbd_release(void *data)
789 {
790 dbd_acquire_t *acq = data;
791 apr_reslist_release(acq->reslist, acq->rec);
792 return APR_SUCCESS;
793 }
794
795 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r)
796 {
797 dbd_acquire_t *acq;
798
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 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 if (svr->cfg->persist) {
818 acq->reslist = svr->group->reslist;
819 apr_pool_cleanup_register(r->pool, acq, dbd_release,
820 apr_pool_cleanup_null);
821 }
822 }
823 }
824
825 return acq->rec;
826 }
827
828 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c)
829 {
830 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 if (svr->cfg->persist) {
841 acq->reslist = svr->group->reslist;
842 apr_pool_cleanup_register(c->pool, acq, dbd_release,
843 apr_pool_cleanup_null);
844 }
845 }
846 }
847
848 return acq->rec;
849 }
850 #else
851 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r)
852 {
853 ap_dbd_t *rec;
854
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 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 }
870 }
871
872 return rec;
873 }
874
875 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c)
876 {
877 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 }
884 }
885
886 return rec;
887 }
888 #endif
889
890 static void dbd_hooks(apr_pool_t *pool)
891 {
892 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 ap_hook_child_init((void*)dbd_setup_init, NULL, NULL, APR_HOOK_MIDDLE);
895
896 APR_REGISTER_OPTIONAL_FN(ap_dbd_prepare);
897 APR_REGISTER_OPTIONAL_FN(ap_dbd_open);
898 APR_REGISTER_OPTIONAL_FN(ap_dbd_close);
899 APR_REGISTER_OPTIONAL_FN(ap_dbd_acquire);
900 APR_REGISTER_OPTIONAL_FN(ap_dbd_cacquire);
901
902 apr_dbd_init(pool);
903 }
904
905 module AP_MODULE_DECLARE_DATA dbd_module = {
906 STANDARD20_MODULE_STUFF,
907 NULL,
908 NULL,
909 create_dbd_config,
910 merge_dbd_config,
911 dbd_cmds,
912 dbd_hooks
913 };
914

Properties

Name Value
svn:eol-style native

apache@apache.org
ViewVC Help
Powered by ViewVC 1.1.2