/[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 496831 - (show annotations)
Tue Jan 16 19:36:26 2007 UTC (2 years, 10 months ago) by chrisd
File MIME type: text/plain
File size: 23593 byte(s)
We now create memory sub-pools for each DB connection and close DB
connections in a pool cleanup function.  This simplifies the ap_dbd_acquire()
and ap_dbd_cacquire() functions, and also stops us from leaking ap_dbd_t
structures when using reslists.

We ensure that prepared statements are destroyed before their DB connection
is closed, in case any drivers would have problems cleaning up prepared
statements after the DB connection is closed.

The combination of reslists and memory pool cleanup functions was causing
segfaults when child processes exited, as reported in PR 39985.  To prevent
this, we register dbd_destroy() as a cleanup that will execute prior to
the internal cleanup function registered by apr_reslist_create().  When the
reslist's memory pool is destroyed, dbd_destroy() informs dbd_destruct() not
to do anything when subsequently called by the reslist's internal cleanup
function.

We avoid the use of s->process->pool (the global pool) since it isn't
destroyed by exiting child processes in most multi-process MPMs.
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_lib.h"
27 #include "apr_dbd.h"
28
29 #define APR_WANT_MEMFUNC
30 #define APR_WANT_STRFUNC
31 #include "apr_want.h"
32
33 #include "http_protocol.h"
34 #include "http_config.h"
35 #include "http_log.h"
36 #include "http_request.h"
37 #include "mod_dbd.h"
38
39 extern module AP_MODULE_DECLARE_DATA dbd_module;
40
41 /************ svr cfg: manage db connection pool ****************/
42
43 #define NMIN_SET 0x1
44 #define NKEEP_SET 0x2
45 #define NMAX_SET 0x4
46 #define EXPTIME_SET 0x8
47
48 typedef struct dbd_prepared dbd_prepared;
49
50 struct dbd_prepared {
51 const char *label;
52 const char *query;
53 dbd_prepared *next;
54 };
55
56 typedef struct {
57 server_rec *server;
58 const char *name;
59 const char *params;
60 int persist;
61 dbd_prepared *prepared;
62 apr_pool_t *pool;
63 #if APR_HAS_THREADS
64 apr_thread_mutex_t *mutex;
65 apr_reslist_t *reslist;
66 int destroyed;
67 int nmin;
68 int nkeep;
69 int nmax;
70 int exptime;
71 int set;
72 #else
73 ap_dbd_t *rec;
74 #endif
75 } svr_cfg;
76
77 typedef enum { cmd_name, cmd_params, cmd_persist,
78 cmd_min, cmd_keep, cmd_max, cmd_exp
79 } cmd_parts;
80
81 static apr_hash_t *dbd_prepared_defns;
82
83 /* a default DBDriver value that'll generate meaningful error messages */
84 static const char *const no_dbdriver = "[DBDriver unset]";
85
86 /* A default nmin of >0 will help with generating meaningful
87 * startup error messages if the database is down.
88 */
89 #define DEFAULT_NMIN 1
90 #define DEFAULT_NKEEP 2
91 #define DEFAULT_NMAX 10
92 #define DEFAULT_EXPTIME 300
93
94 static void *create_dbd_config(apr_pool_t *pool, server_rec *s)
95 {
96 svr_cfg *svr = apr_pcalloc(pool, sizeof(svr_cfg));
97
98 svr->server = s;
99 svr->name = no_dbdriver; /* to generate meaningful error messages */
100 svr->params = ""; /* don't risk segfault on misconfiguration */
101 svr->persist = -1;
102 #if APR_HAS_THREADS
103 svr->nmin = DEFAULT_NMIN;
104 svr->nkeep = DEFAULT_NKEEP;
105 svr->nmax = DEFAULT_NMAX;
106 svr->exptime = DEFAULT_EXPTIME;
107 #endif
108
109 return svr;
110 }
111
112 static void *merge_dbd_config(apr_pool_t *pool, void *basev, void *addv)
113 {
114 svr_cfg *base = (svr_cfg*) basev;
115 svr_cfg *add = (svr_cfg*) addv;
116 svr_cfg *svr = apr_pcalloc(pool, sizeof(svr_cfg));
117
118 svr->server = add->server;
119 svr->name = (add->name != no_dbdriver) ? add->name : base->name;
120 svr->params = strcmp(add->params, "") ? add->params : base->params;
121 svr->persist = (add->persist != -1) ? add->persist : base->persist;
122 #if APR_HAS_THREADS
123 svr->nmin = (add->set&NMIN_SET) ? add->nmin : base->nmin;
124 svr->nkeep = (add->set&NKEEP_SET) ? add->nkeep : base->nkeep;
125 svr->nmax = (add->set&NMAX_SET) ? add->nmax : base->nmax;
126 svr->exptime = (add->set&EXPTIME_SET) ? add->exptime : base->exptime;
127 #endif
128
129 return svr;
130 }
131
132 #define ISINT(val) do { \
133 const char *p; \
134 \
135 for (p = val; *p; ++p) { \
136 if (!apr_isdigit(*p)) { \
137 return "Argument must be numeric!"; \
138 } \
139 } \
140 } while (0)
141
142 static const char *dbd_param(cmd_parms *cmd, void *dconf, const char *val)
143 {
144 const apr_dbd_driver_t *driver = NULL;
145 svr_cfg *svr = ap_get_module_config(cmd->server->module_config,
146 &dbd_module);
147
148 switch ((long) cmd->info) {
149 case cmd_name:
150 svr->name = val;
151 /* loading the driver involves once-only dlloading that is
152 * best done at server startup. This also guarantees that
153 * we won't return an error later.
154 */
155 switch (apr_dbd_get_driver(cmd->pool, svr->name, &driver)) {
156 case APR_ENOTIMPL:
157 return apr_psprintf(cmd->pool, "DBD: No driver for %s", svr->name);
158 case APR_EDSOOPEN:
159 return apr_psprintf(cmd->pool,
160 "DBD: Can't load driver file apr_dbd_%s.so",
161 svr->name);
162 case APR_ESYMNOTFOUND:
163 return apr_psprintf(cmd->pool,
164 "DBD: Failed to load driver apr_dbd_%s_driver",
165 svr->name);
166 }
167 break;
168 case cmd_params:
169 svr->params = val;
170 break;
171 #if APR_HAS_THREADS
172 case cmd_min:
173 ISINT(val);
174 svr->nmin = atoi(val);
175 svr->set |= NMIN_SET;
176 break;
177 case cmd_keep:
178 ISINT(val);
179 svr->nkeep = atoi(val);
180 svr->set |= NKEEP_SET;
181 break;
182 case cmd_max:
183 ISINT(val);
184 svr->nmax = atoi(val);
185 svr->set |= NMAX_SET;
186 break;
187 case cmd_exp:
188 ISINT(val);
189 svr->exptime = atoi(val);
190 svr->set |= EXPTIME_SET;
191 break;
192 #endif
193 }
194
195 return NULL;
196 }
197
198 static const char *dbd_param_flag(cmd_parms *cmd, void *dconf, int flag)
199 {
200 svr_cfg *svr = ap_get_module_config(cmd->server->module_config,
201 &dbd_module);
202
203 switch ((long) cmd->info) {
204 case cmd_persist:
205 svr->persist = flag;
206 break;
207 }
208
209 return NULL;
210 }
211
212 static const char *dbd_prepare(cmd_parms *cmd, void *dconf, const char *query,
213 const char *label)
214 {
215 ap_dbd_prepare(cmd->server, query, label);
216
217 return NULL;
218 }
219
220 static const command_rec dbd_cmds[] = {
221 AP_INIT_TAKE1("DBDriver", dbd_param, (void*)cmd_name, RSRC_CONF,
222 "SQL Driver"),
223 AP_INIT_TAKE1("DBDParams", dbd_param, (void*)cmd_params, RSRC_CONF,
224 "SQL Driver Params"),
225 AP_INIT_FLAG("DBDPersist", dbd_param_flag, (void*)cmd_persist, RSRC_CONF,
226 "Use persistent connection/pool"),
227 AP_INIT_TAKE2("DBDPrepareSQL", dbd_prepare, NULL, RSRC_CONF,
228 "SQL statement to prepare and label"),
229 #if APR_HAS_THREADS
230 AP_INIT_TAKE1("DBDMin", dbd_param, (void*)cmd_min, RSRC_CONF,
231 "Minimum number of connections"),
232 /* XXX: note that mod_proxy calls this "smax" */
233 AP_INIT_TAKE1("DBDKeep", dbd_param, (void*)cmd_keep, RSRC_CONF,
234 "Maximum number of sustained connections"),
235 AP_INIT_TAKE1("DBDMax", dbd_param, (void*)cmd_max, RSRC_CONF,
236 "Maximum number of connections"),
237 /* XXX: note that mod_proxy calls this "ttl" (time to live) */
238 AP_INIT_TAKE1("DBDExptime", dbd_param, (void*)cmd_exp, RSRC_CONF,
239 "Keepalive time for idle connections"),
240 #endif
241 {NULL}
242 };
243
244 static int dbd_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
245 apr_pool_t *ptemp)
246 {
247 dbd_prepared_defns = apr_hash_make(ptemp);
248 return OK;
249 }
250
251 DBD_DECLARE_NONSTD(void) ap_dbd_prepare(server_rec *s, const char *query,
252 const char *label)
253 {
254 dbd_prepared *prepared = apr_pcalloc(s->process->pool,
255 sizeof(dbd_prepared));
256 const char *key = apr_psprintf(s->process->pool, "%pp", s);
257
258 prepared->label = label;
259 prepared->query = query;
260 prepared->next = apr_hash_get(dbd_prepared_defns, key, APR_HASH_KEY_STRING);
261
262 apr_hash_set(dbd_prepared_defns, key, APR_HASH_KEY_STRING, prepared);
263 }
264
265 static int dbd_post_config(apr_pool_t *pconf, apr_pool_t *plog,
266 apr_pool_t *ptemp, server_rec *s)
267 {
268 server_rec *sp;
269
270 for (sp = s; sp; sp = sp->next) {
271 svr_cfg *svr = ap_get_module_config(sp->module_config, &dbd_module);
272 const char *key = apr_psprintf(ptemp, "%pp", s);
273
274 svr->prepared = apr_hash_get(dbd_prepared_defns, key,
275 APR_HASH_KEY_STRING);
276 }
277
278 return OK;
279 }
280
281 static apr_status_t dbd_prepared_init(apr_pool_t *pool, svr_cfg *svr,
282 ap_dbd_t *rec)
283 {
284 dbd_prepared *p;
285 apr_status_t rv = APR_SUCCESS;
286 apr_dbd_prepared_t *stmt;
287
288 rec->prepared = apr_hash_make(pool);
289
290 for (p = svr->prepared; p; p = p->next) {
291 stmt = NULL;
292 if (apr_dbd_prepare(rec->driver, pool, rec->handle, p->query,
293 p->label, &stmt) == 0) {
294 apr_hash_set(rec->prepared, p->label, APR_HASH_KEY_STRING, stmt);
295 }
296 else {
297 rv = APR_EGENERAL;
298 }
299 }
300
301 return rv;
302 }
303
304 static apr_status_t dbd_close(void *data)
305 {
306 ap_dbd_t *rec = data;
307
308 return apr_dbd_close(rec->driver, rec->handle);
309 }
310
311 #if APR_HAS_THREADS
312 static apr_status_t dbd_destruct(void *data, void *params, apr_pool_t *pool)
313 {
314 svr_cfg *svr = params;
315
316 if (!svr->destroyed) {
317 ap_dbd_t *rec = data;
318
319 apr_pool_destroy(rec->pool);
320 }
321
322 return APR_SUCCESS;
323 }
324 #endif
325
326 /* an apr_reslist_constructor for SQL connections
327 * Also use this for opening in non-reslist modes, since it gives
328 * us all the error-handling in one place.
329 */
330 static apr_status_t dbd_construct(void **data_ptr,
331 void *params, apr_pool_t *pool)
332 {
333 svr_cfg *svr = params;
334 apr_pool_t *rec_pool, *prepared_pool;
335 ap_dbd_t *rec;
336 apr_status_t rv;
337
338 rv = apr_pool_create(&rec_pool, pool);
339 if (rv != APR_SUCCESS) {
340 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, svr->server,
341 "DBD: Failed to create memory pool");
342 return rv;
343 }
344
345 rec = apr_pcalloc(rec_pool, sizeof(ap_dbd_t));
346
347 rec->pool = rec_pool;
348
349 /* The driver is loaded at config time now, so this just checks a hash.
350 * If that changes, the driver DSO could be registered to unload against
351 * our pool, which is probably not what we want. Error checking isn't
352 * necessary now, but in case that changes in the future ...
353 */
354 rv = apr_dbd_get_driver(rec->pool, svr->name, &rec->driver);
355 if (rv != APR_SUCCESS) {
356 switch (rv) {
357 case APR_ENOTIMPL:
358 ap_log_error(APLOG_MARK, APLOG_ERR, rv, svr->server,
359 "DBD: driver for %s not available", svr->name);
360 break;
361 case APR_EDSOOPEN:
362 ap_log_error(APLOG_MARK, APLOG_ERR, rv, svr->server,
363 "DBD: can't find driver for %s", svr->name);
364 break;
365 case APR_ESYMNOTFOUND:
366 ap_log_error(APLOG_MARK, APLOG_ERR, rv, svr->server,
367 "DBD: driver for %s is invalid or corrupted",
368 svr->name);
369 break;
370 default:
371 ap_log_error(APLOG_MARK, APLOG_ERR, rv, svr->server,
372 "DBD: mod_dbd not compatible with APR in get_driver");
373 break;
374 }
375
376 apr_pool_destroy(rec->pool);
377 return rv;
378 }
379
380 rv = apr_dbd_open(rec->driver, rec->pool, svr->params, &rec->handle);
381 if (rv != APR_SUCCESS) {
382 switch (rv) {
383 case APR_EGENERAL:
384 ap_log_error(APLOG_MARK, APLOG_ERR, rv, svr->server,
385 "DBD: Can't connect to %s", svr->name);
386 break;
387 default:
388 ap_log_error(APLOG_MARK, APLOG_ERR, rv, svr->server,
389 "DBD: mod_dbd not compatible with APR in open");
390 break;
391 }
392
393 apr_pool_destroy(rec->pool);
394 return rv;
395 }
396
397 apr_pool_cleanup_register(rec->pool, rec, dbd_close,
398 apr_pool_cleanup_null);
399
400 /* we use a sub-pool for the prepared statements for each connection so
401 * that they will be cleaned up first, before the connection is closed
402 */
403 rv = apr_pool_create(&prepared_pool, rec->pool);
404 if (rv != APR_SUCCESS) {
405 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, svr->server,
406 "DBD: Failed to create memory pool");
407
408 apr_pool_destroy(rec->pool);
409 return rv;
410 }
411
412 rv = dbd_prepared_init(prepared_pool, svr, rec);
413 if (rv != APR_SUCCESS) {
414 const char *errmsg = apr_dbd_error(rec->driver, rec->handle, rv);
415 ap_log_error(APLOG_MARK, APLOG_ERR, rv, svr->server,
416 "DBD: failed to prepare SQL statements: %s",
417 (errmsg ? errmsg : "[???]"));
418
419 apr_pool_destroy(rec->pool);
420 return rv;
421 }
422
423 *data_ptr = rec;
424
425 return APR_SUCCESS;
426 }
427
428 #if APR_HAS_THREADS
429 static apr_status_t dbd_destroy(void *data)
430 {
431 svr_cfg *svr = data;
432
433 svr->destroyed = 1;
434
435 return APR_SUCCESS;
436 }
437
438 static apr_status_t dbd_setup(server_rec *s, svr_cfg *svr)
439 {
440 apr_status_t rv;
441
442 /* We create the reslist using a sub-pool of the pool passed to our
443 * child_init hook. No other threads can be here because we're
444 * either in the child_init phase or dbd_setup_lock() acquired our mutex.
445 * No other threads will use this sub-pool after this, except via
446 * reslist calls, which have an internal mutex.
447 *
448 * We need to short-circuit the cleanup registered internally by
449 * apr_reslist_create(). We do this by registering dbd_destroy()
450 * as a cleanup afterwards, so that it will run before the reslist's
451 * internal cleanup.
452 *
453 * If we didn't do this, then we could free memory twice when the pool
454 * was destroyed. When apr_pool_destroy() runs, it first destroys all
455 * all the per-connection sub-pools created in dbd_construct(), and
456 * then it runs the reslist's cleanup. The cleanup calls dbd_destruct()
457 * on each resource, which would then attempt to destroy the sub-pools
458 * a second time.
459 */
460 rv = apr_reslist_create(&svr->reslist,
461 svr->nmin, svr->nkeep, svr->nmax,
462 apr_time_from_sec(svr->exptime),
463 dbd_construct, dbd_destruct, svr,
464 svr->pool);
465 if (rv != APR_SUCCESS) {
466 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
467 "DBD: failed to initialise");
468 return rv;
469 }
470
471 apr_pool_cleanup_register(svr->pool, svr, dbd_destroy,
472 apr_pool_cleanup_null);
473
474 return APR_SUCCESS;
475 }
476 #endif
477
478 static apr_status_t dbd_setup_init(apr_pool_t *pool, server_rec *s)
479 {
480 svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
481 apr_status_t rv;
482
483 /* dbd_setup in 2.2.3 and under was causing spurious error messages
484 * when dbd isn't configured. We can stop that with a quick check here
485 * together with a similar check in ap_dbd_open (where being
486 * unconfigured is a genuine error that must be reported).
487 */
488 if (svr->name == no_dbdriver) {
489 return APR_SUCCESS;
490 }
491
492 if (!svr->persist) {
493 return APR_SUCCESS;
494 }
495
496 rv = apr_pool_create(&svr->pool, pool);
497 if (rv != APR_SUCCESS) {
498 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
499 "DBD: Failed to create reslist cleanup memory pool");
500 return rv;
501 }
502
503 #if APR_HAS_THREADS
504 rv = dbd_setup(s, svr);
505 if (rv == APR_SUCCESS) {
506 return rv;
507 }
508
509 /* we failed, so create a mutex so that subsequent competing callers
510 * to ap_dbd_open can serialize themselves while they retry
511 */
512 rv = apr_thread_mutex_create(&svr->mutex,
513 APR_THREAD_MUTEX_DEFAULT, pool);
514 if (rv != APR_SUCCESS) {
515 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
516 "DBD: Failed to create thread mutex");
517 }
518 #endif
519
520 return rv;
521 }
522
523 #if APR_HAS_THREADS
524 static apr_status_t dbd_setup_lock(server_rec *s, svr_cfg *svr)
525 {
526 apr_status_t rv = APR_SUCCESS, rv2;
527
528 /* several threads could be here at the same time, all trying to
529 * initialize the reslist because dbd_setup_init failed to do so
530 */
531 if (!svr->mutex) {
532 /* we already logged an error when the mutex couldn't be created */
533 return APR_EGENERAL;
534 }
535
536 rv2 = apr_thread_mutex_lock(svr->mutex);
537 if (rv2 != APR_SUCCESS) {
538 ap_log_error(APLOG_MARK, APLOG_ERR, rv2, s,
539 "DBD: Failed to acquire thread mutex");
540 return rv2;
541 }
542
543 if (!svr->reslist) {
544 rv = dbd_setup(s, svr);
545 }
546
547 rv2 = apr_thread_mutex_unlock(svr->mutex);
548 if (rv2 != APR_SUCCESS) {
549 ap_log_error(APLOG_MARK, APLOG_ERR, rv2, s,
550 "DBD: Failed to release thread mutex");
551 if (rv == APR_SUCCESS) {
552 rv = rv2;
553 }
554 }
555
556 return rv;
557 }
558 #endif
559
560 /* Functions we export for modules to use:
561 - open acquires a connection from the pool (opens one if necessary)
562 - close releases it back in to the pool
563 */
564 DBD_DECLARE_NONSTD(void) ap_dbd_close(server_rec *s, ap_dbd_t *rec)
565 {
566 svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
567
568 if (!svr->persist) {
569 apr_pool_destroy(rec->pool);
570 }
571 #if APR_HAS_THREADS
572 else {
573 apr_reslist_release(svr->reslist, rec);
574 }
575 #endif
576 }
577
578 static apr_status_t dbd_check(apr_pool_t *pool, server_rec *s, ap_dbd_t *rec)
579 {
580 svr_cfg *svr;
581 apr_status_t rv = apr_dbd_check_conn(rec->driver, pool, rec->handle);
582 const char *errmsg;
583
584 if ((rv == APR_SUCCESS) || (rv == APR_ENOTIMPL)) {
585 return APR_SUCCESS;
586 }
587
588 errmsg = apr_dbd_error(rec->driver, rec->handle, rv);
589 if (!errmsg) {
590 errmsg = "(unknown)";
591 }
592
593 svr = ap_get_module_config(s->module_config, &dbd_module);
594 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
595 "DBD [%s] Error: %s", svr->name, errmsg);
596 return rv;
597 }
598
599 DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open(apr_pool_t *pool, server_rec *s)
600 {
601 svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
602 ap_dbd_t *rec = NULL;
603 #if APR_HAS_THREADS
604 apr_status_t rv;
605 #endif
606
607 /* If nothing is configured, we shouldn't be here */
608 if (svr->name == no_dbdriver) {
609 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "DBD: not configured");
610 return NULL;
611 }
612
613 if (!svr->persist) {
614 /* Return a once-only connection */
615 dbd_construct((void*) &rec, svr, pool);
616 return rec;
617 }
618
619 #if APR_HAS_THREADS
620 if (!svr->reslist) {
621 if (dbd_setup_lock(s, svr) != APR_SUCCESS) {
622 return NULL;
623 }
624 }
625
626 rv = apr_reslist_acquire(svr->reslist, (void*) &rec);
627 if (rv != APR_SUCCESS) {
628 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
629 "Failed to acquire DBD connection from pool!");
630 return NULL;
631 }
632
633 if (dbd_check(pool, s, rec) != APR_SUCCESS) {
634 apr_reslist_invalidate(svr->reslist, rec);
635 return NULL;
636 }
637 #else
638 /* If we have a persistent connection and it's good, we'll use it;
639 * since this is non-threaded, we can update without a mutex
640 */
641 rec = svr->rec;
642 if (rec) {
643 if (dbd_check(pool, s, rec) != APR_SUCCESS) {
644 apr_pool_destroy(rec->pool);
645 rec = NULL;
646 }
647 }
648
649 /* We don't have a connection right now, so we'll open one */
650 if (!rec) {
651 dbd_construct((void*) &rec, svr, svr->pool);
652 svr->rec = rec;
653 }
654 #endif
655
656 return rec;
657 }
658
659 #if APR_HAS_THREADS
660 typedef struct {
661 ap_dbd_t *rec;
662 apr_reslist_t *reslist;
663 } dbd_acquire_t;
664
665 static apr_status_t dbd_release(void *data)
666 {
667 dbd_acquire_t *acq = data;
668 apr_reslist_release(acq->reslist, acq->rec);
669 return APR_SUCCESS;
670 }
671
672 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r)
673 {
674 dbd_acquire_t *acq;
675
676 while (!ap_is_initial_req(r)) {
677 if (r->prev) {
678 r = r->prev;
679 }
680 else if (r->main) {
681 r = r->main;
682 }
683 }
684
685 acq = ap_get_module_config(r->request_config, &dbd_module);
686 if (!acq) {
687 acq = apr_palloc(r->pool, sizeof(dbd_acquire_t));
688 acq->rec = ap_dbd_open(r->pool, r->server);
689 if (acq->rec) {
690 svr_cfg *svr = ap_get_module_config(r->server->module_config,
691 &dbd_module);
692
693 ap_set_module_config(r->request_config, &dbd_module, acq);
694 if (svr->persist) {
695 acq->reslist = svr->reslist;
696 apr_pool_cleanup_register(r->pool, acq, dbd_release,
697 apr_pool_cleanup_null);
698 }
699 }
700 }
701
702 return acq->rec;
703 }
704
705 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c)
706 {
707 dbd_acquire_t *acq = ap_get_module_config(c->conn_config, &dbd_module);
708
709 if (!acq) {
710 acq = apr_palloc(c->pool, sizeof(dbd_acquire_t));
711 acq->rec = ap_dbd_open(c->pool, c->base_server);
712 if (acq->rec) {
713 svr_cfg *svr = ap_get_module_config(c->base_server->module_config,
714 &dbd_module);
715
716 ap_set_module_config(c->conn_config, &dbd_module, acq);
717 if (svr->persist) {
718 acq->reslist = svr->reslist;
719 apr_pool_cleanup_register(c->pool, acq, dbd_release,
720 apr_pool_cleanup_null);
721 }
722 }
723 }
724
725 return acq->rec;
726 }
727 #else
728 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r)
729 {
730 ap_dbd_t *rec;
731
732 while (!ap_is_initial_req(r)) {
733 if (r->prev) {
734 r = r->prev;
735 }
736 else if (r->main) {
737 r = r->main;
738 }
739 }
740
741 rec = ap_get_module_config(r->request_config, &dbd_module);
742 if (!rec) {
743 rec = ap_dbd_open(r->pool, r->server);
744 if (rec) {
745 ap_set_module_config(r->request_config, &dbd_module, rec);
746 }
747 }
748
749 return rec;
750 }
751
752 DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c)
753 {
754 ap_dbd_t *rec = ap_get_module_config(c->conn_config, &dbd_module);
755
756 if (!rec) {
757 rec = ap_dbd_open(c->pool, c->base_server);
758 if (rec) {
759 ap_set_module_config(c->conn_config, &dbd_module, rec);
760 }
761 }
762
763 return rec;
764 }
765 #endif
766
767 static void dbd_hooks(apr_pool_t *pool)
768 {
769 ap_hook_pre_config(dbd_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
770 ap_hook_post_config(dbd_post_config, NULL, NULL, APR_HOOK_MIDDLE);
771 ap_hook_child_init((void*)dbd_setup_init, NULL, NULL, APR_HOOK_MIDDLE);
772
773 APR_REGISTER_OPTIONAL_FN(ap_dbd_prepare);
774 APR_REGISTER_OPTIONAL_FN(ap_dbd_open);
775 APR_REGISTER_OPTIONAL_FN(ap_dbd_close);
776 APR_REGISTER_OPTIONAL_FN(ap_dbd_acquire);
777 APR_REGISTER_OPTIONAL_FN(ap_dbd_cacquire);
778
779 apr_dbd_init(pool);
780 }
781
782 module AP_MODULE_DECLARE_DATA dbd_module = {
783 STANDARD20_MODULE_STUFF,
784 NULL,
785 NULL,
786 create_dbd_config,
787 merge_dbd_config,
788 dbd_cmds,
789 dbd_hooks
790 };
791

Properties

Name Value
svn:eol-style native

apache@apache.org
ViewVC Help
Powered by ViewVC 1.1.2