Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

utils.c

00001 /*-
00002  * Copyright (c) 2004-2005
00003  *      Sleepycat Software.  All rights reserved.
00004  *
00005  * http://www.apache.org/licenses/LICENSE-2.0.txt
00006  * 
00007  * authors: George Schlossnagle <[email protected]>
00008  */
00009 
00010 extern "C"
00011 {
00012 #include "httpd.h"
00013 #include "http_config.h"
00014 #include "http_core.h"          /* For REMOTE_NAME */
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 /* the semaphore set for the application */
00026 static int semset;
00027 
00028 /* process-local handle for global ref count management */
00029 /* individual semaphores */
00030 #define OK_TO_PROCEED 0
00031 #define GLOBAL_LOCK   1
00032 #define NUM_SEMS      2
00033 
00034 /* mm helpers */
00035 static MM *mm;
00036 static MM_Hash *ref_counts;
00037 
00038 /* locks */
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 /* process resource globals */
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 /* named pointers for db_env and bd skiplists */
00096 struct named_resource {
00097   char *name;
00098   void *ptr;
00099 };
00100 
00101 /* skiplist comparitors for void pointers */
00102 
00103 static int VP_COMPARE(void *a, void *b)
00104 {
00105     return (a < b) ? (-1) : ((a == b) ? (0) : (1));
00106 }
00107 
00108 /* key for comparing DB *'s in skiplist */
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         /* ae->fname != NULL, from above */
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             /* should never match here */
00154             return (a < b) ? (-1) : ((a == b) ? (0) : (1));
00155         }
00156         return 1;
00157     }
00158     else if(be->fname == NULL) {
00159         /* akey->fname != NULL, from above */
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 /* wrapper methods  {{{ */
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         /* overload DB_TXN->abort */
00368         if(old_db_txn_abort == NULL) {
00369             old_db_txn_abort = (*tid)->abort;
00370         }
00371         (*tid)->abort = new_db_txn_abort;
00372 
00373         /* overload DB_TXN->commit */
00374         if(old_db_txn_commit == NULL) {
00375             old_db_txn_commit = (*tid)->commit;
00376         }
00377         (*tid)->commit = new_db_txn_commit;
00378 
00379         /* overload DB_TXN->discard */
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     /* if global ref count is 0, open for recovery */
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     /* we're already locked */
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         /* overload DBC->c_close */
00474         (*newcursor)->c_close = oldcursor->c_close;
00475         
00476         /* overload DBC->c_dup */
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         /* overload DBC->c_close */
00490         if(old_dbc_close == NULL) { 
00491             old_dbc_close = (*cursop)->c_close;
00492         }
00493         (*cursop)->c_close = new_dbc_close;
00494         
00495         /* overload DBC->c_dup */
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 /* {{{ new DB_ENV constructor
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         /* FIXME report error */
00517 
00518         return ret;
00519     }
00520     dbenv = *dbenvp;
00521     DbEnv::wrap_DB_ENV(dbenv);
00522     /* Here we set defaults settings for the db_env */
00523     /* grab context info from httpd.conf for error file */
00524     /* grab context info for cachesize */
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     /* overload DB_ENV->open */
00532     if(old_db_env_open == NULL) {
00533       old_db_env_open = dbenv->open;
00534     }
00535     dbenv->open = new_db_env_open;
00536 
00537     /* overload DB_ENV->close */
00538     if(old_db_env_close == NULL) {
00539       old_db_env_close = dbenv->close;
00540     }
00541     dbenv->close = new_db_env_close;
00542 
00543     /* overload DB_ENV->log_cursor */
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     /* overload DB_ENV->txn_begin */
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 /* {{{ new DB constructor
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         // FIXME this should be removed I think register_db(*dbp);
00568         /* overload DB->open */
00569         if(old_db_open == NULL) {
00570             old_db_open = (*dbp)->open;
00571         }
00572         (*dbp)->open = new_db_open;
00573 
00574         /* overload DB->close */
00575         if(old_db_close == NULL) {
00576             old_db_close = (*dbp)->close;
00577         }
00578         (*dbp)->close = new_db_close;
00579 
00580         /* overload DB->cursor */
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 /* vim: set ts=4 sts=4 expandtab bs=2 ai fdm=marker: */

Generated on Sun Dec 25 12:14:41 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2