/[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 689246 - (show annotations)
Tue Aug 26 21:40:29 2008 UTC (15 months ago) by niq
File MIME type: text/plain
File size: 27578 byte(s)
Fix typo in r689224 (thanks rpluem for spotting it)
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_NONSTD(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 const char *err = "";
468
469 rv = apr_pool_create(&rec_pool, pool);
470 if (rv != APR_SUCCESS) {
471 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, cfg->server,
472 "DBD: Failed to create memory pool");
473 return rv;
474 }
475
476 rec = apr_pcalloc(rec_pool, sizeof(ap_dbd_t));
477
478 rec->pool = rec_pool;
479
480 /* 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 rv = apr_dbd_get_driver(rec->pool, cfg->name, &rec->driver);
486 if (rv != APR_SUCCESS) {
487 switch (rv) {
488 case APR_ENOTIMPL:
489 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
490 "DBD: driver for %s not available", cfg->name);
491 break;
492 case APR_EDSOOPEN:
493 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
494 "DBD: can't find driver for %s", cfg->name);
495 break;
496 case APR_ESYMNOTFOUND:
497 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
498 "DBD: driver for %s is invalid or corrupted",
499 cfg->name);
500 break;
501 default:
502 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
503 "DBD: mod_dbd not compatible with APR in get_driver");
504 break;
505 }
506
507 apr_pool_destroy(rec->pool);
508 return rv;
509 }
510
511 rv = apr_dbd_open_ex(rec->driver, rec->pool, cfg->params, &rec->handle, &err);
512 if (rv != APR_SUCCESS) {
513 switch (rv) {
514 case APR_EGENERAL:
515 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
516 "DBD: Can't connect to %s: %s", cfg->name, err);
517 break;
518 default:
519 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
520 "DBD: mod_dbd not compatible with APR in open");
521 break;
522 }
523
524 apr_pool_destroy(rec->pool);
525 return rv;
526 }
527
528 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 if (rv != APR_SUCCESS) {
536 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, cfg->server,
537 "DBD: Failed to create memory pool");
538
539 apr_pool_destroy(rec->pool);
540 return rv;
541 }
542
543 rv = dbd_prepared_init(prepared_pool, cfg, rec);
544 if (rv != APR_SUCCESS) {
545 const char *errmsg = apr_dbd_error(rec->driver, rec->handle, rv);
546 ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
547 "DBD: failed to prepare SQL statements: %s",
548 (errmsg ? errmsg : "[???]"));
549
550 apr_pool_destroy(rec->pool);
551 return rv;
552 }
553
554 *data_ptr = rec;
555
556 return APR_SUCCESS;
557 }
558
559 #if APR_HAS_THREADS
560 static apr_status_t dbd_destroy(void *data)
561 {
562 dbd_group_t *group = data;
563
564 group->destroyed = 1;
565
566 return APR_SUCCESS;
567 }
568
569 static apr_status_t dbd_setup(server_rec *s, dbd_group_t *group)
570 {
571 dbd_cfg_t *cfg = group->cfg;
572 apr_status_t rv;
573
574 /* 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 */
592 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 if (rv != APR_SUCCESS) {
598 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
599 "DBD: failed to initialise");
600 return rv;
601 }
602
603 apr_pool_cleanup_register(group->pool, group, dbd_destroy,
604 apr_pool_cleanup_null);
605
606 return APR_SUCCESS;
607 }
608 #endif
609
610 static apr_status_t dbd_setup_init(apr_pool_t *pool, server_rec *s)
611 {
612 dbd_group_t *group;
613 apr_status_t rv = APR_SUCCESS;
614
615 for (group = group_list; group; group = group->next) {
616 apr_status_t rv2;
617
618 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
625 #if APR_HAS_THREADS
626 rv2 = dbd_setup(s, group);
627 if (rv2 == APR_SUCCESS) {
628 continue;
629 }
630 else if (rv == APR_SUCCESS) {
631 rv = rv2;
632 }
633
634 /* 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 }
646
647 return rv;
648 }
649
650 #if APR_HAS_THREADS
651 static apr_status_t dbd_setup_lock(server_rec *s, dbd_group_t *group)
652 {
653 apr_status_t rv = APR_SUCCESS, rv2;
654
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 if (!group->mutex) {
659 /* we already logged an error when the mutex couldn't be created */
660 return APR_EGENERAL;
661 }
662
663 rv2 = apr_thread_mutex_lock(group->mutex);
664 if (rv2 != APR_SUCCESS) {
665 ap_log_error(APLOG_MARK, APLOG_ERR, rv2, s,
666 "DBD: Failed to acquire thread mutex");
667 return rv2;
668 }
669
670 if (!group->reslist) {
671 rv = dbd_setup(s, group);
672 }
673
674 rv2 = apr_thread_mutex_unlock(group->mutex);
675 if (rv2 != APR_SUCCESS) {
676 ap_log_error(APLOG_MARK, APLOG_ERR, rv2, s,
677 "DBD: Failed to release thread mutex");
678 if (rv == APR_SUCCESS) {
679 rv = rv2;
680 }
681 }
682
683 return rv;
684 }
685 #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 DBD_DECLARE_NONSTD(void) ap_dbd_close(server_rec *s, ap_dbd_t *rec)
692 {
693 svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
694
695 if (!svr->cfg->persist) {
696 apr_pool_destroy(rec->pool);
697 }
698 #if APR_HAS_THREADS
699 else {
700 apr_reslist_release(svr->group->reslist, rec);
701 }
702 #endif
703 }
704
705 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
711 if ((rv == APR_SUCCESS) || (rv == APR_ENOTIMPL)) {
712 return APR_SUCCESS;
713 }
714
715 /* 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 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 "DBD [%s] Error: %s", svr->cfg->name, errmsg);
726 return rv;
727 }
728
729 DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open(apr_pool_t *pool, server_rec *s)
730 {
731 svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
732 dbd_group_t *group = svr->group;
733 dbd_cfg_t *cfg = svr->cfg;
734 ap_dbd_t *rec = NULL;
735 #if APR_HAS_THREADS
736 apr_status_t rv;
737 #endif
738
739 /* If nothing is configured, we shouldn't be here */
740 if (cfg->name == no_dbdriver) {
741 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "DBD: not configured");
742 return NULL;
743 }
744
745 if (!cfg->persist) {
746 /* Return a once-only connection */
747 group = apr_pcalloc(pool, sizeof(dbd_group_t));
748
749 group->cfg = cfg;
750
751 dbd_construct((void*) &rec, group, pool);
752 return rec;
753 }
754
755 #if APR_HAS_THREADS
756 if (!group->reslist) {
757 if (dbd_setup_lock(s, group) != APR_SUCCESS) {
758 return NULL;
759 }
760 }
761
762 rv = apr_reslist_acquire(group->reslist, (void*) &rec);
763 if (rv != APR_SUCCESS) {
764 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
765 "Failed to acquire DBD connection from pool!");
766 return NULL;
767 }
768
769 if (dbd_check(pool, s, rec) != APR_SUCCESS) {
770 apr_reslist_invalidate(group->reslist, rec);
771 return NULL;
772 }
773 #else
774 /* 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 rec = group->rec;
778 if (rec) {
779 if (dbd_check(pool, s, rec) != APR_SUCCESS) {
780 apr_pool_destroy(rec->pool);
781 rec = NULL;
782 }
783 }
784
785 /* We don't have a connection right now, so we'll open one */
786 if (!rec) {
787 dbd_construct((void*) &rec, group, group->pool);
788 group->rec = rec;
789 }
790 #endif
791
792 return rec;
793 }
794
795 #if APR_HAS_THREADS
796 typedef struct {
797 ap_dbd_t *rec;
798 apr_reslist_t *reslist;
799 } dbd_acquire_t;
800
801 static apr_status_t dbd_release(void *data)
802 {
803 dbd_acquire_t *acq = data;
804 apr_reslist_release(acq->reslist, acq->rec);
805 return APR_SUCCESS;
806 }
807
808 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r)
809 {
810 dbd_acquire_t *acq;
811
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 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 if (svr->cfg->persist) {
831 acq->reslist = svr->group->reslist;
832 apr_pool_cleanup_register(r->pool, acq, dbd_release,
833 apr_pool_cleanup_null);
834 }
835 }
836 }
837
838 return acq->rec;
839 }
840
841 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c)
842 {
843 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 if (svr->cfg->persist) {
854 acq->reslist = svr->group->reslist;
855 apr_pool_cleanup_register(c->pool, acq, dbd_release,
856 apr_pool_cleanup_null);
857 }
858 }
859 }
860
861 return acq->rec;
862 }
863 #else
864 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r)
865 {
866 ap_dbd_t *rec;
867
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 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 }
883 }
884
885 return rec;
886 }
887
888 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c)
889 {
890 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 }
897 }
898
899 return rec;
900 }
901 #endif
902
903 static void dbd_hooks(apr_pool_t *pool)
904 {
905 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 ap_hook_child_init((void*)dbd_setup_init, NULL, NULL, APR_HOOK_MIDDLE);
908
909 APR_REGISTER_OPTIONAL_FN(ap_dbd_prepare);
910 APR_REGISTER_OPTIONAL_FN(ap_dbd_open);
911 APR_REGISTER_OPTIONAL_FN(ap_dbd_close);
912 APR_REGISTER_OPTIONAL_FN(ap_dbd_acquire);
913 APR_REGISTER_OPTIONAL_FN(ap_dbd_cacquire);
914
915 apr_dbd_init(pool);
916 }
917
918 module AP_MODULE_DECLARE_DATA dbd_module = {
919 STANDARD20_MODULE_STUFF,
920 NULL,
921 NULL,
922 create_dbd_config,
923 merge_dbd_config,
924 dbd_cmds,
925 dbd_hooks
926 };
927

Properties

Name Value
svn:eol-style native

apache@apache.org
ViewVC Help
Powered by ViewVC 1.1.2