/[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 664080 - (show annotations)
Fri Jun 6 18:56:13 2008 UTC (17 months, 3 weeks ago) by wrowe
File MIME type: text/plain
File size: 27478 byte(s)
No.

_NONSTD refers to type fn (arg, arg, ...) incomplete declarations
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 static const char *dbd_param(cmd_parms *cmd, void *dconf, const char *val)
145 {
146 const apr_dbd_driver_t *driver = NULL;
147 svr_cfg *svr = ap_get_module_config(cmd->server->module_config,
148 &dbd_module);
149 dbd_cfg_t *cfg = svr->cfg;
150
151 switch ((long) cmd->info) {
152 case cmd_name:
153 cfg->name = val;
154 /* loading the driver involves once-only dlloading that is
155 * best done at server startup. This also guarantees that
156 * we won't return an error later.
157 */
158 switch (apr_dbd_get_driver(cmd->pool, cfg->name, &driver)) {
159 case APR_ENOTIMPL:
160 return apr_psprintf(cmd->pool, "DBD: No driver for %s", cfg->name);
161 case APR_EDSOOPEN:
162 return apr_psprintf(cmd->pool,
163 #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 cfg->name);
169 case APR_ESYMNOTFOUND:
170 return apr_psprintf(cmd->pool,
171 "DBD: Failed to load driver apr_dbd_%s_driver",
172 cfg->name);
173 }
174 break;
175 case cmd_params:
176 cfg->params = val;
177 break;
178 }
179
180 return NULL;
181 }
182
183 #if APR_HAS_THREADS
184 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 case cmd_min:
199 cfg->nmin = atoi(val);
200 cfg->set |= NMIN_SET;
201 break;
202 case cmd_keep:
203 cfg->nkeep = atoi(val);
204 cfg->set |= NKEEP_SET;
205 break;
206 case cmd_max:
207 cfg->nmax = atoi(val);
208 cfg->set |= NMAX_SET;
209 break;
210 case cmd_exp:
211 cfg->exptime = atoi(val);
212 cfg->set |= EXPTIME_SET;
213 break;
214 }
215
216 return NULL;
217 }
218 #endif
219
220 static const char *dbd_param_flag(cmd_parms *cmd, void *dconf, int flag)
221 {
222 svr_cfg *svr = ap_get_module_config(cmd->server->module_config,
223 &dbd_module);
224
225 switch ((long) cmd->info) {
226 case cmd_persist:
227 svr->cfg->persist = flag;
228 break;
229 }
230
231 return NULL;
232 }
233
234 static const char *dbd_prepare(cmd_parms *cmd, void *dconf, const char *query,
235 const char *label)
236 {
237 if (!label) {
238 label = query;
239 query = "";
240 }
241
242 ap_dbd_prepare(cmd->server, query, label);
243
244 return NULL;
245 }
246
247 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 AP_INIT_FLAG("DBDPersist", dbd_param_flag, (void*)cmd_persist, RSRC_CONF,
253 "Use persistent connection/pool"),
254 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 #if APR_HAS_THREADS
258 AP_INIT_TAKE1("DBDMin", dbd_param_int, (void*)cmd_min, RSRC_CONF,
259 "Minimum number of connections"),
260 /* XXX: note that mod_proxy calls this "smax" */
261 AP_INIT_TAKE1("DBDKeep", dbd_param_int, (void*)cmd_keep, RSRC_CONF,
262 "Maximum number of sustained connections"),
263 AP_INIT_TAKE1("DBDMax", dbd_param_int, (void*)cmd_max, RSRC_CONF,
264 "Maximum number of connections"),
265 /* XXX: note that mod_proxy calls this "ttl" (time to live) */
266 AP_INIT_TAKE1("DBDExptime", dbd_param_int, (void*)cmd_exp, RSRC_CONF,
267 "Keepalive time for idle connections"),
268 #endif
269 {NULL}
270 };
271
272 static int dbd_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
273 apr_pool_t *ptemp)
274 {
275 config_pool = pconf;
276 group_list = NULL;
277 return OK;
278 }
279
280 DBD_DECLARE(void) ap_dbd_prepare(server_rec *s, const char *query,
281 const char *label)
282 {
283 svr_cfg *svr;
284
285 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
295 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 }
303
304 typedef struct {
305 const char *label, *query;
306 } dbd_query_t;
307
308 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 apr_array_header_t *add_queries = apr_array_make(ptemp, 10,
313 sizeof(dbd_query_t));
314
315 for (sp = s; sp; sp = sp->next) {
316 svr_cfg *svr = ap_get_module_config(sp->module_config, &dbd_module);
317 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
321 /* 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 }
397
398 return OK;
399 }
400
401 static apr_status_t dbd_prepared_init(apr_pool_t *pool, dbd_cfg_t *cfg,
402 ap_dbd_t *rec)
403 {
404 apr_hash_index_t *hi;
405 apr_status_t rv = APR_SUCCESS;
406
407 rec->prepared = apr_hash_make(pool);
408
409 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 stmt = NULL;
421 if (apr_dbd_prepare(rec->driver, pool, rec->handle, query,
422 label, &stmt)) {
423 rv = APR_EGENERAL;
424 }
425 else {
426 apr_hash_set(rec->prepared, label, APR_HASH_KEY_STRING, stmt);
427 }
428 }
429
430 return rv;
431 }
432
433 static apr_status_t dbd_close(void *data)
434 {
435 ap_dbd_t *rec = data;
436
437 return apr_dbd_close(rec->driver, rec->handle);
438 }
439
440 #if APR_HAS_THREADS
441 static apr_status_t dbd_destruct(void *data, void *params, apr_pool_t *pool)
442 {
443 dbd_group_t *group = params;
444
445 if (!group->destroyed) {
446 ap_dbd_t *rec = data;
447
448 apr_pool_destroy(rec->pool);
449 }
450
451 return APR_SUCCESS;
452 }
453 #endif
454
455 /* 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 static apr_status_t dbd_construct(void **data_ptr,
460 void *params, apr_pool_t *pool)
461 {
462 dbd_group_t *group = params;
463 dbd_cfg_t *cfg = group->cfg;
464 apr_pool_t *rec_pool, *prepared_pool;
465 ap_dbd_t *rec;
466 apr_status_t rv;
467
468 rv = apr_pool_create(&rec_pool, pool);
469 if (rv != APR_SUCCESS) {
470 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, cfg->server,
471 "DBD: Failed to create memory pool");
472 return rv;
473 }
474
475 rec = apr_pcalloc(rec_pool, sizeof(ap_dbd_t));
476
477 rec->pool = rec_pool;
478
479 /* The driver is loaded at config time now, so this just checks a hash.
480 * If that changes, the driver DSO could be registered to unload against
481 * our pool, which is probably not what we want. Error checking isn't
482 * necessary now, but in case that changes in the future ...
483 */
484 rv = apr_dbd_get_driver(rec->pool, cfg->name, &rec->driver);
485 if (rv != APR_SUCCESS) {
486 switch (rv) {
487 case APR_ENOTIMPL:
488 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
489 "DBD: driver for %s not available", cfg->name);
490 break;
491 case APR_EDSOOPEN:
492 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
493 "DBD: can't find driver for %s", cfg->name);
494 break;
495 case APR_ESYMNOTFOUND:
496 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
497 "DBD: driver for %s is invalid or corrupted",
498 cfg->name);
499 break;
500 default:
501 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
502 "DBD: mod_dbd not compatible with APR in get_driver");
503 break;
504 }
505
506 apr_pool_destroy(rec->pool);
507 return rv;
508 }
509
510 rv = apr_dbd_open(rec->driver, rec->pool, cfg->params, &rec->handle);
511 if (rv != APR_SUCCESS) {
512 switch (rv) {
513 case APR_EGENERAL:
514 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
515 "DBD: Can't connect to %s", cfg->name);
516 break;
517 default:
518 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
519 "DBD: mod_dbd not compatible with APR in open");
520 break;
521 }
522
523 apr_pool_destroy(rec->pool);
524 return rv;
525 }
526
527 apr_pool_cleanup_register(rec->pool, rec, dbd_close,
528 apr_pool_cleanup_null);
529
530 /* we use a sub-pool for the prepared statements for each connection so
531 * that they will be cleaned up first, before the connection is closed
532 */
533 rv = apr_pool_create(&prepared_pool, rec->pool);
534 if (rv != APR_SUCCESS) {
535 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, cfg->server,
536 "DBD: Failed to create memory pool");
537
538 apr_pool_destroy(rec->pool);
539 return rv;
540 }
541
542 rv = dbd_prepared_init(prepared_pool, cfg, rec);
543 if (rv != APR_SUCCESS) {
544 const char *errmsg = apr_dbd_error(rec->driver, rec->handle, rv);
545 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
546 "DBD: failed to prepare SQL statements: %s",
547 (errmsg ? errmsg : "[???]"));
548
549 apr_pool_destroy(rec->pool);
550 return rv;
551 }
552
553 *data_ptr = rec;
554
555 return APR_SUCCESS;
556 }
557
558 #if APR_HAS_THREADS
559 static apr_status_t dbd_destroy(void *data)
560 {
561 dbd_group_t *group = data;
562
563 group->destroyed = 1;
564
565 return APR_SUCCESS;
566 }
567
568 static apr_status_t dbd_setup(server_rec *s, dbd_group_t *group)
569 {
570 dbd_cfg_t *cfg = group->cfg;
571 apr_status_t rv;
572
573 /* We create the reslist using a sub-pool of the pool passed to our
574 * child_init hook. No other threads can be here because we're
575 * either in the child_init phase or dbd_setup_lock() acquired our mutex.
576 * No other threads will use this sub-pool after this, except via
577 * reslist calls, which have an internal mutex.
578 *
579 * We need to short-circuit the cleanup registered internally by
580 * apr_reslist_create(). We do this by registering dbd_destroy()
581 * as a cleanup afterwards, so that it will run before the reslist's
582 * internal cleanup.
583 *
584 * If we didn't do this, then we could free memory twice when the pool
585 * was destroyed. When apr_pool_destroy() runs, it first destroys all
586 * all the per-connection sub-pools created in dbd_construct(), and
587 * then it runs the reslist's cleanup. The cleanup calls dbd_destruct()
588 * on each resource, which would then attempt to destroy the sub-pools
589 * a second time.
590 */
591 rv = apr_reslist_create(&group->reslist,
592 cfg->nmin, cfg->nkeep, cfg->nmax,
593 apr_time_from_sec(cfg->exptime),
594 dbd_construct, dbd_destruct, group,
595 group->pool);
596 if (rv != APR_SUCCESS) {
597 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
598 "DBD: failed to initialise");
599 return rv;
600 }
601
602 apr_pool_cleanup_register(group->pool, group, dbd_destroy,
603 apr_pool_cleanup_null);
604
605 return APR_SUCCESS;
606 }
607 #endif
608
609 static apr_status_t dbd_setup_init(apr_pool_t *pool, server_rec *s)
610 {
611 dbd_group_t *group;
612 apr_status_t rv = APR_SUCCESS;
613
614 for (group = group_list; group; group = group->next) {
615 apr_status_t rv2;
616
617 rv2 = apr_pool_create(&group->pool, pool);
618 if (rv2 != APR_SUCCESS) {
619 ap_log_error(APLOG_MARK, APLOG_CRIT, rv2, s,
620 "DBD: Failed to create reslist cleanup memory pool");
621 return rv2;
622 }
623
624 #if APR_HAS_THREADS
625 rv2 = dbd_setup(s, group);
626 if (rv2 == APR_SUCCESS) {
627 continue;
628 }
629 else if (rv == APR_SUCCESS) {
630 rv = rv2;
631 }
632
633 /* we failed, so create a mutex so that subsequent competing callers
634 * to ap_dbd_open can serialize themselves while they retry
635 */
636 rv2 = apr_thread_mutex_create(&group->mutex,
637 APR_THREAD_MUTEX_DEFAULT, pool);
638 if (rv2 != APR_SUCCESS) {
639 ap_log_error(APLOG_MARK, APLOG_CRIT, rv2, s,
640 "DBD: Failed to create thread mutex");
641 return rv2;
642 }
643 #endif
644 }
645
646 return rv;
647 }
648
649 #if APR_HAS_THREADS
650 static apr_status_t dbd_setup_lock(server_rec *s, dbd_group_t *group)
651 {
652 apr_status_t rv = APR_SUCCESS, rv2;
653
654 /* several threads could be here at the same time, all trying to
655 * initialize the reslist because dbd_setup_init failed to do so
656 */
657 if (!group->mutex) {
658 /* we already logged an error when the mutex couldn't be created */
659 return APR_EGENERAL;
660 }
661
662 rv2 = apr_thread_mutex_lock(group->mutex);
663 if (rv2 != APR_SUCCESS) {
664 ap_log_error(APLOG_MARK, APLOG_ERR, rv2, s,
665 "DBD: Failed to acquire thread mutex");
666 return rv2;
667 }
668
669 if (!group->reslist) {
670 rv = dbd_setup(s, group);
671 }
672
673 rv2 = apr_thread_mutex_unlock(group->mutex);
674 if (rv2 != APR_SUCCESS) {
675 ap_log_error(APLOG_MARK, APLOG_ERR, rv2, s,
676 "DBD: Failed to release thread mutex");
677 if (rv == APR_SUCCESS) {
678 rv = rv2;
679 }
680 }
681
682 return rv;
683 }
684 #endif
685
686 /* Functions we export for modules to use:
687 - open acquires a connection from the pool (opens one if necessary)
688 - close releases it back in to the pool
689 */
690 DBD_DECLARE(void) ap_dbd_close(server_rec *s, ap_dbd_t *rec)
691 {
692 svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
693
694 if (!svr->cfg->persist) {
695 apr_pool_destroy(rec->pool);
696 }
697 #if APR_HAS_THREADS
698 else {
699 apr_reslist_release(svr->group->reslist, rec);
700 }
701 #endif
702 }
703
704 static apr_status_t dbd_check(apr_pool_t *pool, server_rec *s, ap_dbd_t *rec)
705 {
706 svr_cfg *svr;
707 apr_status_t rv = apr_dbd_check_conn(rec->driver, pool, rec->handle);
708 const char *errmsg;
709
710 if ((rv == APR_SUCCESS) || (rv == APR_ENOTIMPL)) {
711 return APR_SUCCESS;
712 }
713
714 /* we don't have a driver-specific error code, so we'll just pass
715 * a "success" value and rely on the driver to ignore it
716 */
717 errmsg = apr_dbd_error(rec->driver, rec->handle, 0);
718 if (!errmsg) {
719 errmsg = "(unknown)";
720 }
721
722 svr = ap_get_module_config(s->module_config, &dbd_module);
723 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
724 "DBD [%s] Error: %s", svr->cfg->name, errmsg);
725 return rv;
726 }
727
728 DBD_DECLARE(ap_dbd_t*) ap_dbd_open(apr_pool_t *pool, server_rec *s)
729 {
730 svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
731 dbd_group_t *group = svr->group;
732 dbd_cfg_t *cfg = svr->cfg;
733 ap_dbd_t *rec = NULL;
734 #if APR_HAS_THREADS
735 apr_status_t rv;
736 #endif
737
738 /* If nothing is configured, we shouldn't be here */
739 if (cfg->name == no_dbdriver) {
740 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "DBD: not configured");
741 return NULL;
742 }
743
744 if (!cfg->persist) {
745 /* Return a once-only connection */
746 group = apr_pcalloc(pool, sizeof(dbd_group_t));
747
748 group->cfg = cfg;
749
750 dbd_construct((void*) &rec, group, pool);
751 return rec;
752 }
753
754 #if APR_HAS_THREADS
755 if (!group->reslist) {
756 if (dbd_setup_lock(s, group) != APR_SUCCESS) {
757 return NULL;
758 }
759 }
760
761 rv = apr_reslist_acquire(group->reslist, (void*) &rec);
762 if (rv != APR_SUCCESS) {
763 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
764 "Failed to acquire DBD connection from pool!");
765 return NULL;
766 }
767
768 if (dbd_check(pool, s, rec) != APR_SUCCESS) {
769 apr_reslist_invalidate(group->reslist, rec);
770 return NULL;
771 }
772 #else
773 /* If we have a persistent connection and it's good, we'll use it;
774 * since this is non-threaded, we can update without a mutex
775 */
776 rec = group->rec;
777 if (rec) {
778 if (dbd_check(pool, s, rec) != APR_SUCCESS) {
779 apr_pool_destroy(rec->pool);
780 rec = NULL;
781 }
782 }
783
784 /* We don't have a connection right now, so we'll open one */
785 if (!rec) {
786 dbd_construct((void*) &rec, group, group->pool);
787 group->rec = rec;
788 }
789 #endif
790
791 return rec;
792 }
793
794 #if APR_HAS_THREADS
795 typedef struct {
796 ap_dbd_t *rec;
797 apr_reslist_t *reslist;
798 } dbd_acquire_t;
799
800 static apr_status_t dbd_release(void *data)
801 {
802 dbd_acquire_t *acq = data;
803 apr_reslist_release(acq->reslist, acq->rec);
804 return APR_SUCCESS;
805 }
806
807 DBD_DECLARE(ap_dbd_t *) ap_dbd_acquire(request_rec *r)
808 {
809 dbd_acquire_t *acq;
810
811 while (!ap_is_initial_req(r)) {
812 if (r->prev) {
813 r = r->prev;
814 }
815 else if (r->main) {
816 r = r->main;
817 }
818 }
819
820 acq = ap_get_module_config(r->request_config, &dbd_module);
821 if (!acq) {
822 acq = apr_palloc(r->pool, sizeof(dbd_acquire_t));
823 acq->rec = ap_dbd_open(r->pool, r->server);
824 if (acq->rec) {
825 svr_cfg *svr = ap_get_module_config(r->server->module_config,
826 &dbd_module);
827
828 ap_set_module_config(r->request_config, &dbd_module, acq);
829 if (svr->cfg->persist) {
830 acq->reslist = svr->group->reslist;
831 apr_pool_cleanup_register(r->pool, acq, dbd_release,
832 apr_pool_cleanup_null);
833 }
834 }
835 }
836
837 return acq->rec;
838 }
839
840 DBD_DECLARE(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c)
841 {
842 dbd_acquire_t *acq = ap_get_module_config(c->conn_config, &dbd_module);
843
844 if (!acq) {
845 acq = apr_palloc(c->pool, sizeof(dbd_acquire_t));
846 acq->rec = ap_dbd_open(c->pool, c->base_server);
847 if (acq->rec) {
848 svr_cfg *svr = ap_get_module_config(c->base_server->module_config,
849 &dbd_module);
850
851 ap_set_module_config(c->conn_config, &dbd_module, acq);
852 if (svr->cfg->persist) {
853 acq->reslist = svr->group->reslist;
854 apr_pool_cleanup_register(c->pool, acq, dbd_release,
855 apr_pool_cleanup_null);
856 }
857 }
858 }
859
860 return acq->rec;
861 }
862 #else
863 DBD_DECLARE(ap_dbd_t *) ap_dbd_acquire(request_rec *r)
864 {
865 ap_dbd_t *rec;
866
867 while (!ap_is_initial_req(r)) {
868 if (r->prev) {
869 r = r->prev;
870 }
871 else if (r->main) {
872 r = r->main;
873 }
874 }
875
876 rec = ap_get_module_config(r->request_config, &dbd_module);
877 if (!rec) {
878 rec = ap_dbd_open(r->pool, r->server);
879 if (rec) {
880 ap_set_module_config(r->request_config, &dbd_module, rec);
881 }
882 }
883
884 return rec;
885 }
886
887 DBD_DECLARE(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c)
888 {
889 ap_dbd_t *rec = ap_get_module_config(c->conn_config, &dbd_module);
890
891 if (!rec) {
892 rec = ap_dbd_open(c->pool, c->base_server);
893 if (rec) {
894 ap_set_module_config(c->conn_config, &dbd_module, rec);
895 }
896 }
897
898 return rec;
899 }
900 #endif
901
902 static void dbd_hooks(apr_pool_t *pool)
903 {
904 ap_hook_pre_config(dbd_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
905 ap_hook_post_config(dbd_post_config, NULL, NULL, APR_HOOK_MIDDLE);
906 ap_hook_child_init((void*)dbd_setup_init, NULL, NULL, APR_HOOK_MIDDLE);
907
908 APR_REGISTER_OPTIONAL_FN(ap_dbd_prepare);
909 APR_REGISTER_OPTIONAL_FN(ap_dbd_open);
910 APR_REGISTER_OPTIONAL_FN(ap_dbd_close);
911 APR_REGISTER_OPTIONAL_FN(ap_dbd_acquire);
912 APR_REGISTER_OPTIONAL_FN(ap_dbd_cacquire);
913
914 apr_dbd_init(pool);
915 }
916
917 module AP_MODULE_DECLARE_DATA dbd_module = {
918 STANDARD20_MODULE_STUFF,
919 NULL,
920 NULL,
921 create_dbd_config,
922 merge_dbd_config,
923 dbd_cmds,
924 dbd_hooks
925 };
926

Properties

Name Value
svn:eol-style native

apache@apache.org
ViewVC Help
Powered by ViewVC 1.1.2