00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 extern "C"
00011 {
00012 #include "httpd.h"
00013 #include "http_config.h"
00014 #include "http_core.h"
00015 #include "http_log.h"
00016
00017 #include "sem_utils.h"
00018 #include "skiplist.h"
00019 #include "mm_hash.h"
00020 }
00021
00022 #include "utils.h"
00023 #include "db_cxx.h"
00024
00025
00026 static int semset;
00027
00028
00029
00030 #define OK_TO_PROCEED 0
00031 #define GLOBAL_LOCK 1
00032 #define NUM_SEMS 2
00033
00034
00035 static MM *mm;
00036 static MM_Hash *ref_counts;
00037
00038
00039 int env_locks_init()
00040 {
00041 char shmpath[32];
00042 unsigned short start[2] = { 1, 1 };
00043
00044 snprintf(shmpath, 32, "/tmp/.mod_db4.%d", getpid());
00045 mm = mm_create(0, shmpath);
00046 if(NULL == mm) {
00047 return -1;
00048 }
00049 mm_lock(mm, MM_LOCK_RW);
00050 ref_counts = mm_hash_new(mm, NULL);
00051 mm_unlock(mm);
00052 if((semset = md4_sem_create(NUM_SEMS, start)) < 0) {
00053 return -1;
00054 }
00055 return 0;
00056 }
00057
00058 void env_global_rw_lock()
00059 {
00060 mm_lock(mm, MM_LOCK_RW);
00061 }
00062
00063 void env_global_rd_lock()
00064 {
00065 mm_lock(mm, MM_LOCK_RD);
00066 }
00067
00068 void env_global_unlock()
00069 {
00070 mm_unlock(mm);
00071 }
00072
00073 void env_wait_for_child_crash()
00074 {
00075 md4_sem_wait_for_zero(semset, OK_TO_PROCEED);
00076 }
00077
00078 void env_child_crash()
00079 {
00080 md4_sem_set(semset, OK_TO_PROCEED, 0);
00081 }
00082
00083 void env_ok_to_proceed()
00084 {
00085 md4_sem_set(semset, OK_TO_PROCEED, 1);
00086 }
00087
00088
00089 static Skiplist open_transactions;
00090 static Skiplist open_cursors;
00091 static Skiplist open_log_cursors;
00092 static Skiplist open_dbs;
00093 static Skiplist open_dbenvs;
00094
00095
00096 struct named_resource {
00097 char *name;
00098 void *ptr;
00099 };
00100
00101
00102
00103 static int VP_COMPARE(void *a, void *b)
00104 {
00105 return (a < b) ? (-1) : ((a == b) ? (0) : (1));
00106 }
00107
00108
00109
00110 struct db_key {
00111 const char *fname;
00112 const char *dname;
00113 };
00114
00115 static int DB_COMPARE(void *a, void *b)
00116 {
00117 int ret;
00118 DB *ae = (DB *) a;
00119 DB *be = (DB *) b;
00120 if(ae->fname == NULL) {
00121 if(be->fname == NULL) {
00122 return (ae < be) ? (-1) : ((ae == be) ? (0) : (1));
00123 }
00124 return 1;
00125 }
00126 else if(be->fname == NULL) {
00127
00128 return -1;
00129 }
00130 ret = strcmp(ae->fname, be->fname);
00131 if(ret == 0) {
00132 if(ae->dname == NULL) {
00133 if(be->dname == NULL) {
00134 return 0;
00135 }
00136 return 1;
00137 }
00138 else if(be->dname == NULL) {
00139 return -1;
00140 }
00141 ret = strcmp(ae->dname, be->dname);
00142 }
00143 return ret;
00144 }
00145
00146 static int DB_COMPARE_K(void *a, void *b)
00147 {
00148 struct db_key *akey = (struct db_key *) a;
00149 DB *be = (DB *) b;
00150 int ret;
00151 if(akey->fname == NULL) {
00152 if(be->fname == NULL) {
00153
00154 return (a < b) ? (-1) : ((a == b) ? (0) : (1));
00155 }
00156 return 1;
00157 }
00158 else if(be->fname == NULL) {
00159
00160 return -1;
00161 }
00162 ret = strcmp(akey->fname, be->fname);
00163 if(ret == 0) {
00164 if(akey->dname == NULL) {
00165 if(be->dname == NULL) {
00166 return 0;
00167 }
00168 return 1;
00169 }
00170 else if(be->dname == NULL) {
00171 return -1;
00172 }
00173 ret = strcmp(akey->dname, be->dname);
00174 }
00175 return ret;
00176 }
00177
00178 static int DBENV_COMPARE(void *a, void *b)
00179 {
00180 DB_ENV *ae = (DB_ENV *) a;
00181 DB_ENV *be = (DB_ENV *) b;
00182 return strcmp(ae->db_home, be->db_home);
00183 }
00184
00185 static int DBENV_COMPARE_K(void *a, void *b)
00186 {
00187 const char *aname = (const char *) a;
00188 DB_ENV *be = (DB_ENV *) b;
00189 return strcmp(aname, be->db_home);
00190 }
00191
00192 void env_rsrc_list_init()
00193 {
00194 skiplist_init(&open_transactions);
00195 skiplist_set_compare(&open_transactions, VP_COMPARE, VP_COMPARE);
00196
00197 skiplist_init(&open_cursors);
00198 skiplist_set_compare(&open_cursors, VP_COMPARE, VP_COMPARE);
00199
00200 skiplist_init(&open_log_cursors);
00201 skiplist_set_compare(&open_log_cursors, VP_COMPARE, VP_COMPARE);
00202
00203 skiplist_init(&open_dbs);
00204 skiplist_set_compare(&open_dbs, DB_COMPARE, DB_COMPARE_K);
00205
00206 skiplist_init(&open_dbenvs);
00207 skiplist_set_compare(&open_dbenvs, DBENV_COMPARE, DBENV_COMPARE_K);
00208 }
00209
00210 static void register_cursor(DBC *dbc)
00211 {
00212 skiplist_insert(&open_cursors, dbc);
00213 }
00214
00215 static void unregister_cursor(DBC *dbc)
00216 {
00217 skiplist_remove(&open_cursors, dbc, NULL);
00218 }
00219
00220 static void register_log_cursor(DB_LOGC *cursor)
00221 {
00222 skiplist_insert(&open_log_cursors, cursor);
00223 }
00224
00225 static void unregister_log_cursor(DB_LOGC *cursor)
00226 {
00227 skiplist_remove(&open_log_cursors, cursor, NULL);
00228 }
00229
00230 static void register_transaction(DB_TXN *txn)
00231 {
00232 skiplist_insert(&open_transactions, txn);
00233 }
00234
00235 static void unregister_transaction(DB_TXN *txn)
00236 {
00237 skiplist_remove(&open_transactions, txn, NULL);
00238 }
00239
00240 static DB *retrieve_db(const char *fname, const char *dname)
00241 {
00242 DB *rv;
00243 struct db_key key;
00244 if(fname == NULL) {
00245 return NULL;
00246 }
00247 key.fname = fname;
00248 key.dname = dname;
00249 rv = (DB *) skiplist_find(&open_dbs, (void *) &key, NULL);
00250 return rv;
00251 }
00252
00253 static void register_db(DB *db)
00254 {
00255 skiplist_insert(&open_dbs, db);
00256 }
00257
00258 static void unregister_db(DB *db)
00259 {
00260 struct db_key key;
00261 key.fname = db->fname;
00262 key.dname = db->dname;
00263 skiplist_remove(&open_dbs, &key, NULL);
00264 }
00265
00266 static DB_ENV *retrieve_db_env(const char *db_home)
00267 {
00268 return (DB_ENV *) skiplist_find(&open_dbenvs, (void *) db_home, NULL);
00269 }
00270
00271 static void register_db_env(DB_ENV *dbenv)
00272 {
00273 global_ref_count_increase(dbenv->db_home);
00274 skiplist_insert(&open_dbenvs, dbenv);
00275 }
00276
00277 static void unregister_db_env(DB_ENV *dbenv)
00278 {
00279 global_ref_count_decrease(dbenv->db_home);
00280 skiplist_remove(&open_dbenvs, dbenv->db_home, NULL);
00281 }
00282
00283 int global_ref_count_increase(char *path)
00284 {
00285 int refcount = 0;
00286 int pathlen = 0;
00287 pathlen = strlen(path);
00288
00289 env_global_rw_lock();
00290 refcount = (int) mm_hash_find(ref_counts, path, pathlen);
00291 refcount++;
00292 mm_hash_update(ref_counts, path, pathlen, (void *)refcount);
00293 env_global_unlock();
00294 return refcount;
00295 }
00296
00297 int global_ref_count_decrease(char *path)
00298 {
00299 int refcount = 0;
00300 int pathlen = 0;
00301 pathlen = strlen(path);
00302
00303 env_global_rw_lock();
00304 refcount = (int) mm_hash_find(ref_counts, path, pathlen);
00305 if(refcount > 0) refcount--;
00306 mm_hash_update(ref_counts, path, pathlen, (void *)refcount);
00307 env_global_unlock();
00308 return refcount;
00309 }
00310
00311 int global_ref_count_get(const char *path)
00312 {
00313 int refcount = 0;
00314 int pathlen = 0;
00315 pathlen = strlen(path);
00316
00317 env_global_rd_lock();
00318 refcount = (int) mm_hash_find(ref_counts, path, pathlen);
00319 env_global_unlock();
00320 return refcount;
00321 }
00322
00323 void global_ref_count_clean()
00324 {
00325 env_global_rd_lock();
00326 mm_hash_free(ref_counts);
00327 ref_counts = mm_hash_new(mm, NULL);
00328 env_global_unlock();
00329 }
00330
00331
00332
00333 static int (*old_log_cursor_close)(DB_LOGC *, u_int32_t) = NULL;
00334 static int new_log_cursor_close(DB_LOGC *cursor, u_int32_t flags)
00335 {
00336 unregister_log_cursor(cursor);
00337 return old_log_cursor_close(cursor, flags);
00338 }
00339
00340 static int (*old_db_txn_abort)(DB_TXN *) = NULL;
00341 static int new_db_txn_abort(DB_TXN *tid)
00342 {
00343 unregister_transaction(tid);
00344 return old_db_txn_abort(tid);
00345 }
00346
00347 static int (*old_db_txn_commit)(DB_TXN *, u_int32_t) = NULL;
00348 static int new_db_txn_commit(DB_TXN *tid, u_int32_t flags)
00349 {
00350 unregister_transaction(tid);
00351 return old_db_txn_commit(tid, flags);
00352 }
00353
00354 static int (*old_db_txn_discard)(DB_TXN *, u_int32_t) = NULL;
00355 static int new_db_txn_discard(DB_TXN *tid, u_int32_t flags)
00356 {
00357 unregister_transaction(tid);
00358 return old_db_txn_discard(tid, flags);
00359 }
00360
00361 static int (*old_db_env_txn_begin)(DB_ENV *, DB_TXN *, DB_TXN **, u_int32_t);
00362 static int new_db_env_txn_begin(DB_ENV *env, DB_TXN *parent, DB_TXN **tid, u_int32_t flags)
00363 {
00364 int ret;
00365 if((ret = old_db_env_txn_begin(env, parent, tid, flags)) == 0) {
00366 register_transaction(*tid);
00367
00368 if(old_db_txn_abort == NULL) {
00369 old_db_txn_abort = (*tid)->abort;
00370 }
00371 (*tid)->abort = new_db_txn_abort;
00372
00373
00374 if(old_db_txn_commit == NULL) {
00375 old_db_txn_commit = (*tid)->commit;
00376 }
00377 (*tid)->commit = new_db_txn_commit;
00378
00379
00380 if(old_db_txn_discard == NULL) {
00381 old_db_txn_discard = (*tid)->discard;
00382 }
00383 (*tid)->discard = new_db_txn_discard;
00384 }
00385 return ret;
00386 }
00387
00388 static int (*old_db_env_open)(DB_ENV *, const char *, u_int32_t, int) = NULL;
00389 static int new_db_env_open(DB_ENV *dbenv, const char *db_home, u_int32_t flags, int mode)
00390 {
00391 int ret =666;
00392 DB_ENV *cached_dbenv;
00393 flags |= DB_INIT_MPOOL;
00394
00395 if(global_ref_count_get(db_home) == 0) {
00396 flags |= DB_RECOVER;
00397 flags |= DB_INIT_TXN;
00398 flags |= DB_CREATE;
00399 }
00400 if((cached_dbenv = retrieve_db_env(db_home)) != NULL) {
00401 memcpy(dbenv, cached_dbenv, sizeof(DB_ENV));
00402 ret = 0;
00403 }
00404 else if((ret = old_db_env_open(dbenv, db_home, flags, mode)) == 0) {
00405 register_db_env(dbenv);
00406 }
00407 return ret;
00408 }
00409
00410 static int(*old_db_env_close)(DB_ENV *, u_int32_t) = NULL;
00411 static int new_db_env_close(DB_ENV *dbenv, u_int32_t flags)
00412 {
00413 int ret;
00414
00415 unregister_db_env(dbenv);
00416 ret = old_db_env_close(dbenv, flags);
00417 }
00418
00419 static int (*old_db_env_log_cursor)(DB_ENV *, DB_LOGC **, u_int32_t) = NULL;
00420 static int new_db_env_log_cursor(DB_ENV *dbenv, DB_LOGC **cursop, u_int32_t flags)
00421 {
00422 int ret;
00423 if((ret = old_db_env_log_cursor(dbenv, cursop, flags)) == 0) {
00424 register_log_cursor(*cursop);
00425 if(old_log_cursor_close == NULL) {
00426 old_log_cursor_close = (*cursop)->close;
00427 }
00428 (*cursop)->close = new_log_cursor_close;
00429 }
00430 return ret;
00431 }
00432
00433 static int (*old_db_open)(DB *, DB_TXN *, const char *, const char *, DBTYPE, u_int32_t, int) = NULL;
00434 static int new_db_open(DB *db, DB_TXN *txnid, const char *file,
00435 const char *database, DBTYPE type, u_int32_t flags, int mode)
00436 {
00437 int ret;
00438 DB *cached_db;
00439
00440 cached_db = retrieve_db(file, database);
00441 if(cached_db) {
00442 memcpy(db, cached_db, sizeof(DB));
00443 ret = 0;
00444 }
00445 else if((ret = old_db_open(db, txnid, file, database, type, flags, mode)) == 0) {
00446 register_db(db);
00447 }
00448 return ret;
00449 }
00450
00451 static int (*old_db_close)(DB *, u_int32_t) = NULL;
00452 static int new_db_close(DB *db, u_int32_t flags)
00453 {
00454 unregister_db(db);
00455 return old_db_close(db, flags);
00456 }
00457
00458
00459 static int (*old_dbc_close)(DBC *);
00460 static int new_dbc_close(DBC *cursor)
00461 {
00462 unregister_cursor(cursor);
00463 return old_dbc_close(cursor);
00464 }
00465
00466 static int (*old_dbc_dup)(DBC *, DBC **, u_int32_t) = NULL;
00467 static int new_dbc_dup(DBC *oldcursor, DBC **newcursor, u_int32_t flags)
00468 {
00469 int ret;
00470 if((ret = old_dbc_dup(oldcursor, newcursor, flags)) == 0) {
00471 register_cursor(*newcursor);
00472
00473
00474 (*newcursor)->c_close = oldcursor->c_close;
00475
00476
00477 (*newcursor)->c_dup = oldcursor->c_dup;
00478 }
00479 return ret;
00480 }
00481
00482 static int (*old_db_cursor)(DB *, DB_TXN *, DBC **, u_int32_t) = NULL;
00483 static int new_db_cursor(DB *db, DB_TXN *txnid, DBC **cursop, u_int32_t flags)
00484 {
00485 int ret;
00486 if((ret = old_db_cursor(db, txnid, cursop, flags)) == 0) {
00487 register_cursor(*cursop);
00488
00489
00490 if(old_dbc_close == NULL) {
00491 old_dbc_close = (*cursop)->c_close;
00492 }
00493 (*cursop)->c_close = new_dbc_close;
00494
00495
00496 if(old_dbc_dup == NULL) {
00497 old_dbc_dup = (*cursop)->c_dup;
00498 }
00499 (*cursop)->c_dup = new_dbc_dup;
00500 }
00501 return ret;
00502 }
00503
00504
00505
00506
00507
00508
00509 int mod_db4_db_env_create(DB_ENV **dbenvp, u_int32_t flags)
00510 {
00511 int cachesize = 0;
00512 int ret;
00513 DB_ENV *dbenv;
00514
00515 if ((ret = db_env_create(dbenvp, 0)) != 0) {
00516
00517
00518 return ret;
00519 }
00520 dbenv = *dbenvp;
00521 DbEnv::wrap_DB_ENV(dbenv);
00522
00523
00524
00525 if (0 && cachesize) {
00526 if(( ret = dbenv->set_cachesize(dbenv, 0, cachesize, 0)) != 0) {
00527 dbenv->err(dbenv, ret, "set_cachesize");
00528 dbenv->close(dbenv, 0);
00529 }
00530 }
00531
00532 if(old_db_env_open == NULL) {
00533 old_db_env_open = dbenv->open;
00534 }
00535 dbenv->open = new_db_env_open;
00536
00537
00538 if(old_db_env_close == NULL) {
00539 old_db_env_close = dbenv->close;
00540 }
00541 dbenv->close = new_db_env_close;
00542
00543
00544 if(old_db_env_log_cursor == NULL) {
00545 old_db_env_log_cursor = dbenv->log_cursor;
00546 }
00547 dbenv->log_cursor = new_db_env_log_cursor;
00548
00549
00550 if(old_db_env_txn_begin == NULL) {
00551 old_db_env_txn_begin = dbenv->txn_begin;
00552 }
00553 dbenv->txn_begin = new_db_env_txn_begin;
00554 return 0;
00555 }
00556
00557
00558
00559
00560 int mod_db4_db_create(DB **dbp, DB_ENV *dbenv, u_int32_t flags)
00561 {
00562 int ret;
00563
00564 flags = 0;
00565
00566 if((ret = db_create(dbp, dbenv, flags)) == 0) {
00567
00568
00569 if(old_db_open == NULL) {
00570 old_db_open = (*dbp)->open;
00571 }
00572 (*dbp)->open = new_db_open;
00573
00574
00575 if(old_db_close == NULL) {
00576 old_db_close = (*dbp)->close;
00577 }
00578 (*dbp)->close = new_db_close;
00579
00580
00581 if(old_db_cursor == NULL) {
00582 old_db_cursor = (*dbp)->cursor;
00583 }
00584 (*dbp)->cursor = new_db_cursor;
00585 }
00586 return ret;
00587 }
00588
00589
00590
00591 void mod_db4_child_clean_request_shutdown()
00592 {
00593 DBC *cursor;
00594 DB_TXN *transaction;
00595 while(cursor = (DBC *)skiplist_pop(&open_cursors, NULL)) {
00596 cursor->c_close(cursor);
00597 }
00598 while(transaction = (DB_TXN *)skiplist_pop(&open_transactions, NULL)) {
00599 transaction->abort(transaction);
00600 }
00601 }
00602
00603 void mod_db4_child_clean_process_shutdown()
00604 {
00605 DB *db;
00606 DB_ENV *dbenv;
00607 mod_db4_child_clean_request_shutdown();
00608 while(db = (DB *)skiplist_pop(&open_dbs, NULL)) {
00609 db->close(db, 0);
00610 }
00611 while(dbenv = (DB_ENV *)skiplist_pop(&open_dbenvs, NULL)) {
00612 DbEnv *dbe = DbEnv::get_DbEnv(dbenv);
00613 global_ref_count_decrease(dbenv->db_home);
00614 dbe->close(0);
00615 delete dbe;
00616 }
00617 }
00618