Import BSDDB 4.7.25 (as of svn r89086)

This commit is contained in:
Zachary Ware
2017-09-04 13:40:25 -05:00
parent 4b29e0458f
commit 8f590873d0
4781 changed files with 2241032 additions and 6 deletions

48
mod_db4/ABOUT Normal file
View File

@@ -0,0 +1,48 @@
This is the mod_db4 apache module, providing a safe framework
for running db4 applications in the Apache 1.3 environment. In
general, it is dangerous to run db4 in a multi-process system
without some facility to coordinate recovery between
participating processes. Apache natively provides no
interface for commuication between processes, so the mod_db4
module exists to provide this communication.
Specifically, mod_db4 provides the following facilities:
o New constructors for DB and DB_ENV structures, which install
replacement open/close methods.
o Transparent caching of open DB and DB_ENV structures
o Reference counting on all structures, allowing the module to
detect the initial opening of any managed database
and automatically perform recovery.
o Automatic detection of unexpected failures (segfaults, or a
module actually calling exit() and avoiding shutdown phases,
and automatic termination of all child processes with open
database resources to attempt consistency.
mod_db4 is designed to be used as an alternative interface to db4.
To have another Apache module (for example, mod_foo) use mod_db4,
do not link mod_foo against libdb-4.2. In your mod_foo makefile,
you should
#include "mod_db4_export.h"
and add your Apache include directory to your CPPFLAGS.
In mod_foo, to create a mod_db4 managed DB_ENV, use the following:
int mod_db4_db_env_create(DB_ENV **dbenvp, u_int32_t flags);
which takes identical arguments to db_env_create().
To create a mod_db4 managed DB, use
int mod_db4_db_create(DB **dbp, DB_ENV *dbenv, u_int32_t flags);
which takes identical arguments to db_create().
Otherwise the API is completely consistent with the standard Berkeley
DB API.
For installation instructions, see the INSTALL file.

10
mod_db4/BSD Normal file
View File

@@ -0,0 +1,10 @@
Copyright (c) 2005, 2006, Theo Schlossnagle
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name OmniTI nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

13
mod_db4/INSTALL Normal file
View File

@@ -0,0 +1,13 @@
This apache module requires db-4.3 compiled with c++ extensions
and libmm (a shared memory manager).
To build this apache module, perform the following steps:
> ./configure --with-apxs=/path/to/apxs
--with-db4=/usr/local/BerkeleyDb-4.3 --with-mm=/usr/local
> make
> su -
# make install
Post-installation, modules can use this extension via the functions
documented in $APACHE_INCLUDEDIR/mod_db4_export.h

26
mod_db4/Makefile.in Normal file
View File

@@ -0,0 +1,26 @@
#
# Copyright (c) 2004,2008 Oracle. All rights reserved.
#
# http://www.apache.org/licenses/LICENSE-2.0.txt
#
APXS=@APXS@
CXXFLAGS=@CXXFLAGS@
CPPFLAGS=@CPPFLAGS@
LDFLAGS=@LDFLAGS@
LIBS=@LIBS@
SOURCES=mod_db4.c sem_utils.c skiplist.c utils.c mm_hash.c
all: mod_db4.so
mod_db4.so: $(SOURCES)
$(APXS) -c -S CC=$(CXX) $(LDFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(SOURCES) $(LIBS)
install: mod_db4.so
$(APXS) -i mod_db4.so
cp mod_db4_export.h `$(APXS) -q INCLUDEDIR`/
chmod a+r `$(APXS) -q INCLUDEDIR`/mod_db4_export.h
clean:
rm -f *.o *.a *.so *.lo *.tlo *.to config.cache config.log *.out core

22
mod_db4/config.h.in Normal file
View File

@@ -0,0 +1,22 @@
/* config.h.in. Generated from configure.in by autoheader. */
/* Define to 1 if you have the `mm' library (-lmm). */
#undef HAVE_LIBMM
/* */
#undef HAVE_SEMUN
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the version of this package. */
#undef PACKAGE_VERSION

3219
mod_db4/configure vendored Normal file

File diff suppressed because it is too large Load Diff

114
mod_db4/configure.in Normal file
View File

@@ -0,0 +1,114 @@
#
# Copyright (c) 2004,2008 Oracle. All rights reserved.
#
# http://www.apache.org/licenses/LICENSE-2.0.txt
#
AC_INIT(mod_db4.c)
AC_CONFIG_HEADER(config.h)
AC_PROG_CXX
AC_LANG_PUSH(C++)
if test "$cross_compiling" = no; then
AC_MSG_CHECKING([that C++ compiler can compile simple program])
fi
AC_TRY_RUN([int main() { return 0; }],
AC_MSG_RESULT(yes),
AC_MSG_RESULT(no);AC_MSG_ERROR([a working C++ compiler is required]))
# Allow user to specify flags
AC_ARG_WITH(cxxflags,
[ --with-cxxflags Specify additional flags to pass to compiler],
[
if test "x$withval" != "xno" ; then
CXXFLAGS="$withval $CXXFLAGS"
fi
]
)
CXXFLAGS=`echo $CXXFLAGS | sed -e 's/-O2//g;' | sed -e 's/-g//g;'`
AC_ARG_WITH(ldflags,
[ --with-ldflags Specify additional flags to pass to linker],
[
if test "x$withval" != "xno" ; then
LDFLAGS="$withval $LDFLAGS"
fi
]
)
AC_ARG_WITH(libs,
[ --with-libs Specify additional libraries],
[
if test "x$withval" != "xno" ; then
LIBS="$withval $LIBS"
fi
]
)
AC_ARG_WITH(mm,
[ --with-mm Specify additional libraries],
[
if test "x$withval" != "xno" ; then
LIBS="-L$withval/lib $LIBS"
CPPFLAGS="-I$withval/include $CPPFLAGS"
fi
]
)
AC_ARG_WITH(db4,
[ --with-db4 Specify additional libraries],
[
if test "x$withval" != "xno" ; then
LIBS="-L$withval/lib $LIBS"
CPPFLAGS="-I$withval/include $CPPFLAGS"
fi
]
)
AC_ARG_WITH(apxs,
[ --with-apxs[=FILE] Build shared Apache module. FILE is optional
pathname to the Apache apxs tool; defaults to
"apxs".],
[
if test "$withval" = "yes"; then
withval="apxs"
fi
APXS="$withval"
AC_SUBST(APXS)
],
[
AC_MSG_ERROR([apxs is required])
])
LIBS="$LIBS -ldb_cxx"
AC_CACHE_CHECK(for union semun,cv_semun,
AC_TRY_COMPILE([
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
],
[union semun x;],
[
cv_semun=yes
],[
cv_semun=no
])
)
if test "$cv_semun" = "yes"; then
AC_DEFINE(HAVE_SEMUN, 1, [ ])
else
AC_DEFINE(HAVE_SEMUN, 0, [ ])
fi
AC_SUBST(LDFLAGS)
AC_SUBST(LIBS)
AC_SUBST(CPPFLAGS)
AC_SUBST(CXXFLAGS)
AC_CHECK_LIB(mm, mm_core_create, , [ AC_MSG_ERROR([libmm required]) ])
AC_SUBST(HAVE_SEMUN)
AC_OUTPUT(Makefile)

138
mod_db4/mm_hash.c Normal file
View File

@@ -0,0 +1,138 @@
/*-
* Copyright (c) 2004,2008 Oracle. All rights reserved.
*
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
* authors: Thies C. Arntzen <thies@php.net>
* Sterling Hughes <sterling@php.net>
* George Schlossnagle <george@omniti.com>
*/
extern "C"
{
#include <stdlib.h>
#include <string.h>
#include "mm_hash.h"
}
MM_Hash *mm_hash_new(MM *mm, MM_HashDtor dtor)
{
MM_Hash *table;
table = (MM_Hash *) mm_calloc(mm, 1, sizeof(MM_Hash));
table->mm = mm;
table->dtor = dtor;
return table;
}
void mm_hash_free(MM_Hash *table)
{
MM_Bucket *cur;
MM_Bucket *next;
int i;
for (i = 0; i < MM_HASH_SIZE; i++) {
cur = table->buckets[i];
while (cur) {
next = cur->next;
if (table->dtor) table->dtor(cur->data);
mm_free(table->mm, cur->key);
mm_free(table->mm, cur);
cur = next;
}
}
mm_free(table->mm, table);
}
static unsigned int hash_hash(const char *key, int length)
{
unsigned int hash = 0;
while (--length)
hash = hash * 65599 + *key++;
return hash;
}
void *mm_hash_find(MM_Hash *table, const void *key, int length)
{
MM_Bucket *b;
unsigned int hash = hash_hash((const char *)key, length) % MM_HASH_SIZE;
for (b = table->buckets[ hash ]; b; b = b->next) {
if (hash != b->hash) continue;
if (length != b->length) continue;
if (memcmp(key, b->key, length)) continue;
return b->data;
}
return NULL;
}
void mm_hash_update(MM_Hash *table, char *key, int length, void *data)
{
MM_Bucket *b, p;
unsigned int hash;
hash = hash_hash(key, length) % MM_HASH_SIZE;
for(b = table->buckets[ hash ]; b; b = b->next) {
if (hash != b->hash) continue;
if (length != b->length) continue;
if (memcmp(key, b->key, length)) continue;
if (table->dtor) table->dtor(b->data);
b->data = data;
}
if(!b) {
b = (MM_Bucket *) mm_malloc(table->mm, sizeof(MM_Bucket));
b->key = (char *) mm_malloc(table->mm, length + 1);
memcpy(b->key, key, length);
b->key[length] = 0;
b->length = length;
b->hash = hash;
b->data = data;
b->next = table->buckets[ hash ];
table->buckets[ hash ] = b;
}
table->nElements++;
}
void mm_hash_delete(MM_Hash *table, char *key, int length)
{
MM_Bucket *b;
MM_Bucket *prev = NULL;
unsigned int hash;
hash = hash_hash(key, length) % MM_HASH_SIZE;
for (b = table->buckets[ hash ]; b; b = b->next) {
if (hash != b->hash || length != b->length || memcmp(key, b->key, length)) {
prev = b;
continue;
}
/* unlink */
if (prev) {
prev->next = b->next;
} else {
table->buckets[hash] = b->next;
}
if (table->dtor) table->dtor(b->data);
mm_free(table->mm, b->key);
mm_free(table->mm, b);
break;
}
}
/*
Local variables:
tab-width: 4
c-basic-offset: 4
End:
vim600: noet sw=4 ts=4 fdm=marker
vim<600: noet sw=4 ts=4
*/

48
mod_db4/mm_hash.h Normal file
View File

@@ -0,0 +1,48 @@
/*-
* Copyright (c) 2004,2008 Oracle. All rights reserved.
*
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
* authors: Thies C. Arntzen <thies@php.net>
* Sterling Hughes <sterling@php.net>
* George Schlossnagle <george@omniti.com>
*/
#ifndef _MM_HASH_H
#define _MM_HASH_H
#include "mm.h"
typedef void (*MM_HashDtor)(void *);
typedef struct _MM_Bucket {
struct _MM_Bucket *next;
char *key;
int length;
unsigned int hash;
void *data;
} MM_Bucket;
#define MM_HASH_SIZE 1009
typedef struct _Hash {
MM_Bucket *buckets[ MM_HASH_SIZE ];
MM *mm;
MM_HashDtor dtor;
int nElements;
} MM_Hash;
MM_Hash *mm_hash_new(MM *, MM_HashDtor);
void mm_hash_free(MM_Hash *table);
void *mm_hash_find(MM_Hash *table, const void *key, int length);
void mm_hash_add(MM_Hash *table, char *key, int length, void *data);
void mm_hash_delete(MM_Hash *table, char *key, int length);
void mm_hash_update(MM_Hash *table, char *key, int length, void *data);
#endif
/*
Local variables:
tab-width: 4
c-basic-offset: 4
End:
vim600: noet sw=4 ts=4 fdm=marker
vim<600: noet sw=4 ts=4
*/

130
mod_db4/mod_db4.c Normal file
View File

@@ -0,0 +1,130 @@
/*-
* Copyright (c) 2004,2008 Oracle. All rights reserved.
*
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
* authors: George Schlossnagle <george@omniti.com>
*/
extern "C"
{
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_main.h"
#include "http_protocol.h"
#include "scoreboard.h"
#include "util_script.h"
#include "sem_utils.h"
}
#include "mod_db4_export.h"
#include "utils.h"
extern scoreboard *ap_scoreboard_image;
/*
* Declare ourselves so the configuration routines can find and know us.
* We'll fill it in at the end of the module.
*/
extern module MODULE_VAR_EXPORT db4_module;
void kill_all_children()
{
int i, ret = 1;
ap_sync_scoreboard_image();
for(;ret != 0;) {
ret = 0;
for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
ret += kill(ap_scoreboard_image->parent[i].pid, SIGTERM);
}
}
}
int moderator_main(void * ptr, child_info *ci)
{
for(;;) {
env_wait_for_child_crash();
kill_all_children();
env_global_rw_lock();
global_ref_count_clean();
env_ok_to_proceed();
env_global_unlock();
}
}
static void sig_unrecoverable(int sig)
{
env_child_crash();
/* reinstall default apache handler */
signal(sig, SIG_DFL);
kill(getpid(), sig);
}
static void db4_init(server_rec *s, pool *p)
{
int mpid;
env_locks_init();
mpid=ap_spawn_child(p, moderator_main, NULL, kill_always, NULL, NULL, NULL);
}
/*
* Worker process init
*/
static void db4_child_init(server_rec *s, pool *p)
{
/* install our private signal handlers */
signal(SIGSEGV, sig_unrecoverable);
signal(SIGBUS, sig_unrecoverable);
signal(SIGABRT, sig_unrecoverable);
signal(SIGILL, sig_unrecoverable);
env_rsrc_list_init();
}
/*
* Worker process exit
*/
static void db4_child_exit(server_rec *s, pool *p)
{
mod_db4_child_clean_process_shutdown();
}
static const command_rec db4_cmds[] =
{
{NULL}
};
module MODULE_VAR_EXPORT db4_module =
{
STANDARD_MODULE_STUFF,
db4_init, /* module initializer */
NULL, /* per-directory config creator */
NULL, /* dir config merger */
NULL, /* server config creator */
NULL, /* server config merger */
db4_cmds, /* command table */
NULL, /* [9] list of handlers */
NULL, /* [2] filename-to-URI translation */
NULL, /* [5] check/validate user_id */
NULL, /* [6] check user_id is valid *here* */
NULL, /* [4] check access by host address */
NULL, /* [7] MIME type checker/setter */
NULL, /* [8] fixups */
NULL, /* [10] logger */
#if MODULE_MAGIC_NUMBER >= 19970103
NULL, /* [3] header parser */
#endif
#if MODULE_MAGIC_NUMBER >= 19970719
db4_child_init, /* process initializer */
#endif
#if MODULE_MAGIC_NUMBER >= 19970728
db4_child_exit, /* process exit/cleanup */
#endif
#if MODULE_MAGIC_NUMBER >= 19970902
NULL /* [1] post read_request handling */
#endif
};
/* vim: set ts=4 sts=4 bs=2 ai expandtab : */

27
mod_db4/mod_db4_export.h Normal file
View File

@@ -0,0 +1,27 @@
/*-
* Copyright (c) 2004,2008 Oracle. All rights reserved.
*
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
* authors: George Schlossnagle <george@omniti.com>
*/
#ifndef MOD_DB4_EXPORT_H
#define MOD_DB4_EXPORT_H
#include "db_cxx.h"
#if defined(__cplusplus)
extern "C" {
#endif
int mod_db4_db_env_create(DB_ENV **dbenvp, u_int32_t flags);
int mod_db4_db_create(DB **dbp, DB_ENV *dbenv, u_int32_t flags);
void mod_db4_child_clean_request_shutdown();
void mod_db4_child_clean_process_shutdown();
#if defined(__cplusplus)
}
#endif
#endif

115
mod_db4/sem_utils.c Normal file
View File

@@ -0,0 +1,115 @@
/*-
* Copyright (c) 2004,2008 Oracle. All rights reserved.
*
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
* authors: George Schlossnagle <george@omniti.com>
*/
extern "C"
{
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/stat.h>
#include <unistd.h>
#include "config.h"
#include "sem_utils.h"
#include <errno.h>
}
extern int errno;
#if HAVE_SEMUN
/* we have semun, no need to define */
#else
union semun {
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* array for GETALL, SETALL */
/* Linux specific part: */
struct seminfo *__buf; /* buffer for IPC_INFO */
};
#endif
#ifndef SEM_R
# define SEM_R 0444
#endif
#ifndef SEM_A
# define SEM_A 0222
#endif
int md4_sem_create(int semnum, unsigned short *start)
{
int semid;
int perms = 0777;
union semun arg;
key_t key = 12345;
int count = 0;
while((semid = semget(key, semnum, IPC_CREAT | IPC_EXCL | perms)) == -1) {
if(count++ > 2) {
return -1;
}
if (errno == EEXIST) {
semid = semget(key, 1, perms);
md4_sem_destroy(semid);
}
}
arg.array = start;
if(semctl(semid, 0, SETALL, arg) < 0) {
/* destroy (FIXME) and return */
md4_sem_destroy(semid);
return -1;
}
return semid;
}
void md4_sem_destroy(int semid)
{
union semun dummy;
/* semid should always be 0, this clobbers the whole set */
semctl(semid, 0, IPC_RMID, dummy);
}
void md4_sem_lock(int semid, int semnum)
{
struct sembuf sops;
sops.sem_num = semnum;
sops.sem_op = -1;
sops.sem_flg = SEM_UNDO;
semop(semid, &sops, 1);
}
void md4_sem_unlock(int semid, int semnum)
{
struct sembuf sops;
sops.sem_num = semnum;
sops.sem_op = 1;
sops.sem_flg = SEM_UNDO;
semop(semid, &sops, 1);
}
void md4_sem_wait_for_zero(int semid, int semnum)
{
struct sembuf sops;
sops.sem_num = semnum;
sops.sem_op = 0;
sops.sem_flg = SEM_UNDO;
semop(semid, &sops, 1);
}
void md4_sem_set(int semid, int semnum, int value)
{
union semun arg;
arg.val = value;
semctl(semid, semnum, SETALL, arg);
}
int md4_sem_get(int semid, int semnum)
{
union semun arg;
return semctl(semid, 0, GETVAL, arg);
}
/* vim: set ts=4 sts=4 expandtab bs=2 ai : */

21
mod_db4/sem_utils.h Normal file
View File

@@ -0,0 +1,21 @@
/*-
* Copyright (c) 2004,2008 Oracle. All rights reserved.
*
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
* authors: George Schlossnagle <george@omniti.com>
*/
#ifndef MOD_DB4_SEM_UTILS_H
#define MOD_DB4_SEM_UTILS_H
extern int md4_sem_create(int semnum, unsigned short *start);
extern void md4_sem_destroy(int semid);
extern void md4_sem_lock(int semid, int semnum);
extern void md4_sem_unlock(int semid, int semnum);
extern void md4_sem_wait_for_zero(int semid, int semnum);
extern void md4_sem_set(int semid, int semnum, int value);
extern int md4_sem_get(int semid, int semnum);
/* vim: set ts=4 sts=4 expandtab bs=2 ai : */
#endif

514
mod_db4/skiplist.c Normal file
View File

@@ -0,0 +1,514 @@
/* ======================================================================
* Copyright (c) 2000,2006 Theo Schlossnagle
* All rights reserved.
* The following code was written by Theo Schlossnagle for use in the
* Backhand project at The Center for Networking and Distributed Systems
* at The Johns Hopkins University.
*
* This is a skiplist implementation to be used for abstract structures
* and is release under the LGPL license version 2.1 or later. A copy
* of this license can be found file LGPL.
*
* Alternatively, this file may be licensed under the new BSD license.
* A copy of this license can be found file BSD.
*
* ======================================================================
*/
extern "C"
{
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "skiplist.h"
}
#ifdef USE_DMALLOC
# include <dmalloc.h>
#endif
#ifndef MIN
#define MIN(a,b) ((a<b)?(a):(b))
#endif
static int get_b_rand(void) {
static int ph=32; /* More bits than we will ever use */
static unsigned long randseq;
if(ph > 31) { /* Num bits in return of lrand48() */
ph=0;
randseq = lrand48();
}
ph++;
return ((randseq & (1 << (ph-1))) >> (ph-1));
}
void skiplisti_init(Skiplist *sl) {
sl->compare = (SkiplistComparator)NULL;
sl->comparek = (SkiplistComparator)NULL;
sl->height=0;
sl->preheight=0;
sl->size=0;
sl->top = NULL;
sl->bottom = NULL;
sl->index = NULL;
}
static int indexing_comp(void *a, void *b) {
assert(a);
assert(b);
return (void *)(((Skiplist *)a)->compare)>(void *)(((Skiplist *)b)->compare);
}
static int indexing_compk(void *a, void *b) {
assert(b);
return a>(void *)(((Skiplist *)b)->compare);
}
void skiplist_init(Skiplist *sl) {
skiplisti_init(sl);
sl->index = (Skiplist *)malloc(sizeof(Skiplist));
skiplisti_init(sl->index);
skiplist_set_compare(sl->index, indexing_comp, indexing_compk);
}
void skiplist_set_compare(Skiplist *sl,
SkiplistComparator comp,
SkiplistComparator compk) {
if(sl->compare && sl->comparek) {
skiplist_add_index(sl, comp, compk);
} else {
sl->compare = comp;
sl->comparek = compk;
}
}
void skiplist_add_index(Skiplist *sl,
SkiplistComparator comp,
SkiplistComparator compk) {
struct skiplistnode *m;
Skiplist *ni;
int icount=0;
#ifdef SLDEBUG
fprintf(stderr, "Adding index to %p\n", sl);
#endif
skiplist_find(sl->index, (void *)comp, &m);
if(m) return; /* Index already there! */
ni = (Skiplist *)malloc(sizeof(Skiplist));
skiplisti_init(ni);
skiplist_set_compare(ni, comp, compk);
/* Build the new index... This can be expensive! */
m = skiplist_insert(sl->index, ni);
while(m->prev) m=m->prev, icount++;
for(m=skiplist_getlist(sl); m; skiplist_next(sl, &m)) {
int j=icount-1;
struct skiplistnode *nsln;
nsln = skiplist_insert(ni, m->data);
/* skip from main index down list */
while(j>0) m=m->nextindex, j--;
/* insert this node in the indexlist after m */
nsln->nextindex = m->nextindex;
if(m->nextindex) m->nextindex->previndex = nsln;
nsln->previndex = m;
m->nextindex = nsln;
}
}
struct skiplistnode *skiplist_getlist(Skiplist *sl) {
if(!sl->bottom) return NULL;
return sl->bottom->next;
}
void *skiplist_find(Skiplist *sl,
void *data,
struct skiplistnode **iter) {
void *ret;
struct skiplistnode *aiter;
if(!sl->compare) return 0;
if(iter)
ret = skiplist_find_compare(sl, data, iter, sl->compare);
else
ret = skiplist_find_compare(sl, data, &aiter, sl->compare);
return ret;
}
void *skiplist_find_compare(Skiplist *sli,
void *data,
struct skiplistnode **iter,
SkiplistComparator comp) {
struct skiplistnode *m = NULL;
Skiplist *sl;
if(comp==sli->compare || !sli->index) {
sl = sli;
} else {
skiplist_find(sli->index, (void *)comp, &m);
assert(m);
sl= (Skiplist *) m->data;
}
skiplisti_find_compare(sl, data, iter, sl->comparek);
return (*iter)?((*iter)->data):(*iter);
}
int skiplisti_find_compare(Skiplist *sl,
void *data,
struct skiplistnode **ret,
SkiplistComparator comp) {
struct skiplistnode *m = NULL;
int count=0;
m = sl->top;
while(m) {
int compared;
if(m->next) compared=comp(data, m->next->data);
if(compared == 0) {
#ifdef SL_DEBUG
printf("Looking -- found in %d steps\n", count);
#endif
m=m->next;
while(m->down) m=m->down;
*ret = m;
return count;
}
if((m->next == NULL) || (compared<0))
m = m->down, count++;
else
m = m->next, count++;
}
#ifdef SL_DEBUG
printf("Looking -- not found in %d steps\n", count);
#endif
*ret = NULL;
return count;
}
void *skiplist_next(Skiplist *sl, struct skiplistnode **iter) {
if(!*iter) return NULL;
*iter = (*iter)->next;
return (*iter)?((*iter)->data):NULL;
}
void *skiplist_previous(Skiplist *sl, struct skiplistnode **iter) {
if(!*iter) return NULL;
*iter = (*iter)->prev;
return (*iter)?((*iter)->data):NULL;
}
struct skiplistnode *skiplist_insert(Skiplist *sl,
void *data) {
if(!sl->compare) return 0;
return skiplist_insert_compare(sl, data, sl->compare);
}
struct skiplistnode *skiplist_insert_compare(Skiplist *sl,
void *data,
SkiplistComparator comp) {
struct skiplistnode *m, *p, *tmp, *ret, **stack;
int nh=1, ch, stacki;
#ifdef SLDEBUG
skiplist_print_struct(sl, "BI: ");
#endif
if(!sl->top) {
sl->height = 1;
sl->topend = sl->bottomend = sl->top = sl->bottom =
(struct skiplistnode *)malloc(sizeof(struct skiplistnode));
assert(sl->top);
sl->top->next = (struct skiplistnode *) NULL;
sl->top->data = (struct skiplistnode *) NULL;
sl->top->prev =(struct skiplistnode *) NULL;
sl->top->up = (struct skiplistnode *) NULL;
sl->top->down = (struct skiplistnode *) NULL;
sl->top->nextindex= (struct skiplistnode *) NULL;
sl->top->previndex = (struct skiplistnode *) NULL;
sl->top->sl = sl;
}
if(sl->preheight) {
while(nh < sl->preheight && get_b_rand()) nh++;
} else {
while(nh <= sl->height && get_b_rand()) nh++;
}
/* Now we have the new height at which we wish to insert our new node */
/* Let us make sure that our tree is a least that tall (grow if necessary)*/
for(;sl->height<nh;sl->height++) {
sl->top->up =
(struct skiplistnode *)malloc(sizeof(struct skiplistnode));
assert(sl->top->up);
sl->top->up->down = sl->top;
sl->top = sl->topend = sl->top->up;
sl->top->prev = sl->top->next = sl->top->nextindex =
sl->top->previndex = sl->top->up = NULL;
sl->top->data = NULL;
sl->top->sl = sl;
}
ch = sl->height;
/* Find the node (or node after which we would insert) */
/* Keep a stack to pop back through for insertion */
m = sl->top;
stack = (struct skiplistnode **)malloc(sizeof(struct skiplistnode *)*(nh));
stacki=0;
while(m) {
int compared=-1;
if(m->next) compared=comp(data, m->next->data);
if(compared == 0) {
free(stack);
return 0;
}
if((m->next == NULL) || (compared<0)) {
if(ch<=nh) {
/* push on stack */
stack[stacki++] = m;
}
m = m->down;
ch--;
} else {
m = m->next;
}
}
/* Pop the stack and insert nodes */
p = NULL;
for(;stacki>0;stacki--) {
m = stack[stacki-1];
tmp = (struct skiplistnode *)malloc(sizeof(struct skiplistnode));
tmp->next = m->next;
if(m->next) m->next->prev=tmp;
tmp->prev = m;
tmp->up = NULL;
tmp->nextindex = tmp->previndex = NULL;
tmp->down = p;
if(p) p->up=tmp;
tmp->data = data;
tmp->sl = sl;
m->next = tmp;
/* This sets ret to the bottom-most node we are inserting */
if(!p) ret=tmp;
p = tmp;
}
free(stack);
if(sl->index != NULL) {
/* this is a external insertion, we must insert into each index as well */
struct skiplistnode *p, *ni, *li;
li=ret;
for(p = skiplist_getlist(sl->index); p; skiplist_next(sl->index, &p)) {
ni = skiplist_insert((Skiplist *)p->data, ret->data);
assert(ni);
#ifdef SLDEBUG
fprintf(stderr, "Adding %p to index %p\n", ret->data, p->data);
#endif
li->nextindex = ni;
ni->previndex = li;
li = ni;
}
} else {
sl->size++;
}
#ifdef SLDEBUG
skiplist_print_struct(sl, "AI: ");
#endif
return ret;
}
struct skiplistnode *skiplist_append(Skiplist *sl, void *data) {
int nh=1, ch, compared;
struct skiplistnode *lastnode, *nodeago;
if(sl->bottomend != sl->bottom) {
compared=sl->compare(data, sl->bottomend->prev->data);
/* If it doesn't belong at the end, then fail */
if(compared<=0) return NULL;
}
if(sl->preheight) {
while(nh < sl->preheight && get_b_rand()) nh++;
} else {
while(nh <= sl->height && get_b_rand()) nh++;
}
/* Now we have the new height at which we wish to insert our new node */
/* Let us make sure that our tree is a least that tall (grow if necessary)*/
lastnode = sl->bottomend;
nodeago = NULL;
if(!lastnode) return skiplist_insert(sl, data);
for(;sl->height<nh;sl->height++) {
sl->top->up =
(struct skiplistnode *)malloc(sizeof(struct skiplistnode));
assert(sl->top);
sl->top->up->down = sl->top;
sl->top = sl->top->up;
sl->top->prev = sl->top->next = sl->top->nextindex =
sl->top->previndex = NULL;
sl->top->data = NULL;
sl->top->sl = sl;
}
ch = sl->height;
while(nh) {
struct skiplistnode *anode;
anode =
(struct skiplistnode *)malloc(sizeof(struct skiplistnode));
anode->next = lastnode;
anode->prev = lastnode->prev;
anode->up = NULL;
anode->down = nodeago;
if(lastnode->prev) {
if(lastnode == sl->bottom)
sl->bottom = anode;
else if (lastnode == sl->top)
sl->top = anode;
}
nodeago = anode;
lastnode = lastnode->up;
nh--;
}
sl->size++;
return sl->bottomend;
}
Skiplist *skiplist_concat(Skiplist *sl1, Skiplist *sl2) {
/* Check integrity! */
int compared, eheight;
Skiplist temp;
struct skiplistnode *lbottom, *lbottomend, *b1, *e1, *b2, *e2;
if(sl1->bottomend == NULL || sl1->bottomend->prev == NULL) {
skiplist_remove_all(sl1, free);
temp = *sl1;
*sl1 = *sl2;
*sl2 = temp;
/* swap them so that sl2 can be freed normally upon return. */
return sl1;
}
if(sl2->bottom == NULL || sl2->bottom->next == NULL) {
skiplist_remove_all(sl2, free);
return sl1;
}
compared = sl1->compare(sl1->bottomend->prev->data, sl2->bottom->data);
/* If it doesn't belong at the end, then fail */
if(compared<=0) return NULL;
/* OK now append sl2 onto sl1 */
lbottom = lbottomend = NULL;
eheight = MIN(sl1->height, sl2->height);
b1 = sl1->bottom; e1 = sl1->bottomend;
b2 = sl2->bottom; e2 = sl2->bottomend;
while(eheight) {
e1->prev->next = b2;
b2->prev = e1->prev->next;
e2->prev->next = e1;
e1->prev = e2->prev;
e2->prev = NULL;
b2 = e2;
b1->down = lbottom;
e1->down = lbottomend;
if(lbottom) lbottom->up = b1;
if(lbottomend) lbottomend->up = e1;
lbottom = b1;
lbottomend = e1;
}
/* Take the top of the longer one (if it is sl2) and make it sl1's */
if(sl2->height > sl1->height) {
b1->up = b2->up;
e1->up = e2->up;
b1->up->down = b1;
e1->up->down = e1;
sl1->height = sl2->height;
sl1->top = sl2->top;
sl1->topend = sl2->topend;
}
/* move the top pointer to here if it isn't there already */
sl2->top = sl2->topend = b2;
sl2->top->up = NULL; /* If it isn't already */
sl1->size += sl2->size;
skiplist_remove_all(sl2, free);
return sl1;
}
int skiplist_remove(Skiplist *sl,
void *data, FreeFunc myfree) {
if(!sl->compare) return 0;
return skiplist_remove_compare(sl, data, myfree, sl->comparek);
}
void skiplist_print_struct(Skiplist *sl, char *prefix) {
struct skiplistnode *p, *q;
fprintf(stderr, "Skiplist Structure (height: %d)\n", sl->height);
p = sl->bottom;
while(p) {
q = p;
fprintf(stderr, prefix);
while(q) {
fprintf(stderr, "%p ", q->data);
q=q->up;
}
fprintf(stderr, "\n");
p=p->next;
}
}
int skiplisti_remove(Skiplist *sl, struct skiplistnode *m, FreeFunc myfree) {
struct skiplistnode *p;
if(!m) return 0;
if(m->nextindex) skiplisti_remove(m->nextindex->sl, m->nextindex, NULL);
else sl->size--;
#ifdef SLDEBUG
skiplist_print_struct(sl, "BR:");
#endif
while(m->up) m=m->up;
while(m) {
p=m;
p->prev->next = p->next; /* take me out of the list */
if(p->next) p->next->prev = p->prev; /* take me out of the list */
m=m->down;
/* This only frees the actual data in the bottom one */
if(!m && myfree && p->data) myfree(p->data);
free(p);
}
while(sl->top && sl->top->next == NULL) {
/* While the row is empty and we are not on the bottom row */
p = sl->top;
sl->top = sl->top->down; /* Move top down one */
if(sl->top) sl->top->up = NULL; /* Make it think its the top */
free(p);
sl->height--;
}
if(!sl->top) sl->bottom = NULL;
assert(sl->height>=0);
#ifdef SLDEBUG
skiplist_print_struct(sl, "AR: ");
#endif
return sl->height;
}
int skiplist_remove_compare(Skiplist *sli,
void *data,
FreeFunc myfree, SkiplistComparator comp) {
struct skiplistnode *m;
Skiplist *sl;
if(comp==sli->comparek || !sli->index) {
sl = sli;
} else {
skiplist_find(sli->index, (void *)comp, &m);
assert(m);
sl= (Skiplist *) m->data;
}
skiplisti_find_compare(sl, data, &m, comp);
if(!m) return 0;
while(m->previndex) m=m->previndex;
return skiplisti_remove(sl, m, myfree);
}
void skiplist_remove_all(Skiplist *sl, FreeFunc myfree) {
/* This must remove even the place holder nodes (bottom though top)
because we specify in the API that one can free the Skiplist after
making this call without memory leaks */
struct skiplistnode *m, *p, *u;
m=sl->bottom;
while(m) {
p = m->next;
if(myfree && p->data) myfree(p->data);
while(m) {
u = m->up;
free(m);
m=u;
}
m = p;
}
sl->top = sl->bottom = NULL;
sl->height = 0;
sl->size = 0;
}
void *skiplist_pop(Skiplist * a, FreeFunc myfree)
{
struct skiplistnode *sln;
void *data = NULL;
sln = skiplist_getlist(a);
if (sln) {
data = sln->data;
skiplisti_remove(a, sln, myfree);
}
return data;
}

88
mod_db4/skiplist.h Normal file
View File

@@ -0,0 +1,88 @@
/* ======================================================================
* Copyright (c) 2000,2006 Theo Schlossnagle
* All rights reserved.
* The following code was written by Theo Schlossnagle for use in the
* Backhand project at The Center for Networking and Distributed Systems
* at The Johns Hopkins University.
*
* This is a skiplist implementation to be used for abstract structures
* and is release under the LGPL license version 2.1 or later. A copy
* of this license can be found file LGPL.
*
* Alternatively, this file may be licensed under the new BSD license.
* A copy of this license can be found file BSD.
*
* ======================================================================
*/
#ifndef _SKIPLIST_P_H
#define _SKIPLIST_P_H
/* This is a skiplist implementation to be used for abstract structures
within the Spread multicast and group communication toolkit
This portion written by -- Theo Schlossnagle <jesus@cnds.jhu.eu>
*/
/* This is the function type that must be implemented per object type
that is used in a skiplist for comparisons to maintain order */
typedef int (*SkiplistComparator)(void *, void *);
typedef void (*FreeFunc)(void *);
struct skiplistnode;
typedef struct _iskiplist {
SkiplistComparator compare;
SkiplistComparator comparek;
int height;
int preheight;
int size;
struct skiplistnode *top;
struct skiplistnode *bottom;
/* These two are needed for appending */
struct skiplistnode *topend;
struct skiplistnode *bottomend;
struct _iskiplist *index;
} Skiplist;
struct skiplistnode {
void *data;
struct skiplistnode *next;
struct skiplistnode *prev;
struct skiplistnode *down;
struct skiplistnode *up;
struct skiplistnode *previndex;
struct skiplistnode *nextindex;
Skiplist *sl;
};
void skiplist_init(Skiplist *sl);
void skiplist_set_compare(Skiplist *sl, SkiplistComparator,
SkiplistComparator);
void skiplist_add_index(Skiplist *sl, SkiplistComparator,
SkiplistComparator);
struct skiplistnode *skiplist_getlist(Skiplist *sl);
void *skiplist_find_compare(Skiplist *sl, void *data, struct skiplistnode **iter,
SkiplistComparator func);
void *skiplist_find(Skiplist *sl, void *data, struct skiplistnode **iter);
void *skiplist_next(Skiplist *sl, struct skiplistnode **);
void *skiplist_previous(Skiplist *sl, struct skiplistnode **);
struct skiplistnode *skiplist_insert_compare(Skiplist *sl,
void *data, SkiplistComparator comp);
struct skiplistnode *skiplist_insert(Skiplist *sl, void *data);
int skiplist_remove_compare(Skiplist *sl, void *data,
FreeFunc myfree, SkiplistComparator comp);
int skiplist_remove(Skiplist *sl, void *data, FreeFunc myfree);
int skiplisti_remove(Skiplist *sl, struct skiplistnode *m, FreeFunc myfree);
void skiplist_remove_all(Skiplist *sl, FreeFunc myfree);
int skiplisti_find_compare(Skiplist *sl,
void *data,
struct skiplistnode **ret,
SkiplistComparator comp);
void *skiplist_pop(Skiplist * a, FreeFunc myfree);
#endif

617
mod_db4/utils.c Normal file
View File

@@ -0,0 +1,617 @@
/*-
* Copyright (c) 2004,2008 Oracle. All rights reserved.
*
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
* authors: George Schlossnagle <george@omniti.com>
*/
extern "C"
{
#include "httpd.h"
#include "http_config.h"
#include "http_core.h" /* For REMOTE_NAME */
#include "http_log.h"
#include "sem_utils.h"
#include "skiplist.h"
#include "mm_hash.h"
}
#include "utils.h"
#include "db_cxx.h"
/* the semaphore set for the application */
static int semset;
/* process-local handle for global ref count management */
/* individual semaphores */
#define OK_TO_PROCEED 0
#define GLOBAL_LOCK 1
#define NUM_SEMS 2
/* mm helpers */
static MM *mm;
static MM_Hash *ref_counts;
/* locks */
int env_locks_init()
{
char shmpath[32];
unsigned short start[2] = { 1, 1 };
snprintf(shmpath, 32, "/tmp/.mod_db4.%d", getpid());
mm = mm_create(0, shmpath);
if(NULL == mm) {
return -1;
}
mm_lock(mm, MM_LOCK_RW);
ref_counts = mm_hash_new(mm, NULL);
mm_unlock(mm);
if((semset = md4_sem_create(NUM_SEMS, start)) < 0) {
return -1;
}
return 0;
}
void env_global_rw_lock()
{
mm_lock(mm, MM_LOCK_RW);
}
void env_global_rd_lock()
{
mm_lock(mm, MM_LOCK_RD);
}
void env_global_unlock()
{
mm_unlock(mm);
}
void env_wait_for_child_crash()
{
md4_sem_wait_for_zero(semset, OK_TO_PROCEED);
}
void env_child_crash()
{
md4_sem_set(semset, OK_TO_PROCEED, 0);
}
void env_ok_to_proceed()
{
md4_sem_set(semset, OK_TO_PROCEED, 1);
}
/* process resource globals */
static Skiplist open_transactions;
static Skiplist open_cursors;
static Skiplist open_log_cursors;
static Skiplist open_dbs;
static Skiplist open_dbenvs;
/* named pointers for db_env and bd skiplists */
struct named_resource {
char *name;
void *ptr;
};
/* skiplist comparitors for void pointers */
static int VP_COMPARE(void *a, void *b)
{
return (a < b) ? (-1) : ((a == b) ? (0) : (1));
}
/* key for comparing DB *'s in skiplist */
struct db_key {
const char *fname;
const char *dname;
};
static int DB_COMPARE(void *a, void *b)
{
int ret;
DB *ae = (DB *) a;
DB *be = (DB *) b;
if(ae->fname == NULL) {
if(be->fname == NULL) {
return (ae < be) ? (-1) : ((ae == be) ? (0) : (1));
}
return 1;
}
else if(be->fname == NULL) {
/* ae->fname != NULL, from above */
return -1;
}
ret = strcmp(ae->fname, be->fname);
if(ret == 0) {
if(ae->dname == NULL) {
if(be->dname == NULL) {
return 0;
}
return 1;
}
else if(be->dname == NULL) {
return -1;
}
ret = strcmp(ae->dname, be->dname);
}
return ret;
}
static int DB_COMPARE_K(void *a, void *b)
{
struct db_key *akey = (struct db_key *) a;
DB *be = (DB *) b;
int ret;
if(akey->fname == NULL) {
if(be->fname == NULL) {
/* should never match here */
return (a < b) ? (-1) : ((a == b) ? (0) : (1));
}
return 1;
}
else if(be->fname == NULL) {
/* akey->fname != NULL, from above */
return -1;
}
ret = strcmp(akey->fname, be->fname);
if(ret == 0) {
if(akey->dname == NULL) {
if(be->dname == NULL) {
return 0;
}
return 1;
}
else if(be->dname == NULL) {
return -1;
}
ret = strcmp(akey->dname, be->dname);
}
return ret;
}
static int DBENV_COMPARE(void *a, void *b)
{
DB_ENV *ae = (DB_ENV *) a;
DB_ENV *be = (DB_ENV *) b;
return strcmp(ae->db_home, be->db_home);
}
static int DBENV_COMPARE_K(void *a, void *b)
{
const char *aname = (const char *) a;
DB_ENV *be = (DB_ENV *) b;
return strcmp(aname, be->db_home);
}
void env_rsrc_list_init()
{
skiplist_init(&open_transactions);
skiplist_set_compare(&open_transactions, VP_COMPARE, VP_COMPARE);
skiplist_init(&open_cursors);
skiplist_set_compare(&open_cursors, VP_COMPARE, VP_COMPARE);
skiplist_init(&open_log_cursors);
skiplist_set_compare(&open_log_cursors, VP_COMPARE, VP_COMPARE);
skiplist_init(&open_dbs);
skiplist_set_compare(&open_dbs, DB_COMPARE, DB_COMPARE_K);
skiplist_init(&open_dbenvs);
skiplist_set_compare(&open_dbenvs, DBENV_COMPARE, DBENV_COMPARE_K);
}
static void register_cursor(DBC *dbc)
{
skiplist_insert(&open_cursors, dbc);
}
static void unregister_cursor(DBC *dbc)
{
skiplist_remove(&open_cursors, dbc, NULL);
}
static void register_log_cursor(DB_LOGC *cursor)
{
skiplist_insert(&open_log_cursors, cursor);
}
static void unregister_log_cursor(DB_LOGC *cursor)
{
skiplist_remove(&open_log_cursors, cursor, NULL);
}
static void register_transaction(DB_TXN *txn)
{
skiplist_insert(&open_transactions, txn);
}
static void unregister_transaction(DB_TXN *txn)
{
skiplist_remove(&open_transactions, txn, NULL);
}
static DB *retrieve_db(const char *fname, const char *dname)
{
DB *rv;
struct db_key key;
if(fname == NULL) {
return NULL;
}
key.fname = fname;
key.dname = dname;
rv = (DB *) skiplist_find(&open_dbs, (void *) &key, NULL);
return rv;
}
static void register_db(DB *db)
{
skiplist_insert(&open_dbs, db);
}
static void unregister_db(DB *db)
{
struct db_key key;
key.fname = db->fname;
key.dname = db->dname;
skiplist_remove(&open_dbs, &key, NULL);
}
static DB_ENV *retrieve_db_env(const char *db_home)
{
return (DB_ENV *) skiplist_find(&open_dbenvs, (void *) db_home, NULL);
}
static void register_db_env(DB_ENV *dbenv)
{
global_ref_count_increase(dbenv->db_home);
skiplist_insert(&open_dbenvs, dbenv);
}
static void unregister_db_env(DB_ENV *dbenv)
{
global_ref_count_decrease(dbenv->db_home);
skiplist_remove(&open_dbenvs, dbenv->db_home, NULL);
}
int global_ref_count_increase(char *path)
{
int refcount = 0;
int pathlen = 0;
pathlen = strlen(path);
env_global_rw_lock();
refcount = (int) mm_hash_find(ref_counts, path, pathlen);
refcount++;
mm_hash_update(ref_counts, path, pathlen, (void *)refcount);
env_global_unlock();
return refcount;
}
int global_ref_count_decrease(char *path)
{
int refcount = 0;
int pathlen = 0;
pathlen = strlen(path);
env_global_rw_lock();
refcount = (int) mm_hash_find(ref_counts, path, pathlen);
if(refcount > 0) refcount--;
mm_hash_update(ref_counts, path, pathlen, (void *)refcount);
env_global_unlock();
return refcount;
}
int global_ref_count_get(const char *path)
{
int refcount = 0;
int pathlen = 0;
pathlen = strlen(path);
env_global_rd_lock();
refcount = (int) mm_hash_find(ref_counts, path, pathlen);
env_global_unlock();
return refcount;
}
void global_ref_count_clean()
{
env_global_rd_lock();
mm_hash_free(ref_counts);
ref_counts = mm_hash_new(mm, NULL);
env_global_unlock();
}
/* wrapper methods {{{ */
static int (*old_log_cursor_close)(DB_LOGC *, u_int32_t) = NULL;
static int new_log_cursor_close(DB_LOGC *cursor, u_int32_t flags)
{
unregister_log_cursor(cursor);
return old_log_cursor_close(cursor, flags);
}
static int (*old_db_txn_abort)(DB_TXN *) = NULL;
static int new_db_txn_abort(DB_TXN *tid)
{
unregister_transaction(tid);
return old_db_txn_abort(tid);
}
static int (*old_db_txn_commit)(DB_TXN *, u_int32_t) = NULL;
static int new_db_txn_commit(DB_TXN *tid, u_int32_t flags)
{
unregister_transaction(tid);
return old_db_txn_commit(tid, flags);
}
static int (*old_db_txn_discard)(DB_TXN *, u_int32_t) = NULL;
static int new_db_txn_discard(DB_TXN *tid, u_int32_t flags)
{
unregister_transaction(tid);
return old_db_txn_discard(tid, flags);
}
static int (*old_db_env_txn_begin)(DB_ENV *, DB_TXN *, DB_TXN **, u_int32_t);
static int new_db_env_txn_begin(DB_ENV *env, DB_TXN *parent, DB_TXN **tid, u_int32_t flags)
{
int ret;
if((ret = old_db_env_txn_begin(env, parent, tid, flags)) == 0) {
register_transaction(*tid);
/* overload DB_TXN->abort */
if(old_db_txn_abort == NULL) {
old_db_txn_abort = (*tid)->abort;
}
(*tid)->abort = new_db_txn_abort;
/* overload DB_TXN->commit */
if(old_db_txn_commit == NULL) {
old_db_txn_commit = (*tid)->commit;
}
(*tid)->commit = new_db_txn_commit;
/* overload DB_TXN->discard */
if(old_db_txn_discard == NULL) {
old_db_txn_discard = (*tid)->discard;
}
(*tid)->discard = new_db_txn_discard;
}
return ret;
}
static int (*old_db_env_open)(DB_ENV *, const char *, u_int32_t, int) = NULL;
static int new_db_env_open(DB_ENV *dbenv, const char *db_home, u_int32_t flags, int mode)
{
int ret =666;
DB_ENV *cached_dbenv;
flags |= DB_INIT_MPOOL;
/* if global ref count is 0, open for recovery */
if(global_ref_count_get(db_home) == 0) {
flags |= DB_RECOVER;
flags |= DB_INIT_TXN;
flags |= DB_CREATE;
}
if((cached_dbenv = retrieve_db_env(db_home)) != NULL) {
memcpy(dbenv, cached_dbenv, sizeof(DB_ENV));
ret = 0;
}
else if((ret = old_db_env_open(dbenv, db_home, flags, mode)) == 0) {
register_db_env(dbenv);
}
return ret;
}
static int(*old_db_env_close)(DB_ENV *, u_int32_t) = NULL;
static int new_db_env_close(DB_ENV *dbenv, u_int32_t flags)
{
int ret;
/* we're already locked */
unregister_db_env(dbenv);
ret = old_db_env_close(dbenv, flags);
}
static int (*old_db_env_log_cursor)(DB_ENV *, DB_LOGC **, u_int32_t) = NULL;
static int new_db_env_log_cursor(DB_ENV *dbenv, DB_LOGC **cursop, u_int32_t flags)
{
int ret;
if((ret = old_db_env_log_cursor(dbenv, cursop, flags)) == 0) {
register_log_cursor(*cursop);
if(old_log_cursor_close == NULL) {
old_log_cursor_close = (*cursop)->close;
}
(*cursop)->close = new_log_cursor_close;
}
return ret;
}
static int (*old_db_open)(DB *, DB_TXN *, const char *, const char *, DBTYPE, u_int32_t, int) = NULL;
static int new_db_open(DB *db, DB_TXN *txnid, const char *file,
const char *database, DBTYPE type, u_int32_t flags, int mode)
{
int ret;
DB *cached_db;
cached_db = retrieve_db(file, database);
if(cached_db) {
memcpy(db, cached_db, sizeof(DB));
ret = 0;
}
else if((ret = old_db_open(db, txnid, file, database, type, flags, mode)) == 0) {
register_db(db);
}
return ret;
}
static int (*old_db_close)(DB *, u_int32_t) = NULL;
static int new_db_close(DB *db, u_int32_t flags)
{
unregister_db(db);
return old_db_close(db, flags);
}
static int (*old_dbc_close)(DBC *);
static int new_dbc_close(DBC *cursor)
{
unregister_cursor(cursor);
return old_dbc_close(cursor);
}
static int (*old_dbc_dup)(DBC *, DBC **, u_int32_t) = NULL;
static int new_dbc_dup(DBC *oldcursor, DBC **newcursor, u_int32_t flags)
{
int ret;
if((ret = old_dbc_dup(oldcursor, newcursor, flags)) == 0) {
register_cursor(*newcursor);
/* overload DBC->close */
(*newcursor)->close = oldcursor->close;
/* overload DBC->dup */
(*newcursor)->dup = oldcursor->dup;
}
return ret;
}
static int (*old_db_cursor)(DB *, DB_TXN *, DBC **, u_int32_t) = NULL;
static int new_db_cursor(DB *db, DB_TXN *txnid, DBC **cursop, u_int32_t flags)
{
int ret;
if((ret = old_db_cursor(db, txnid, cursop, flags)) == 0) {
register_cursor(*cursop);
/* overload DBC->close */
if(old_dbc_close == NULL) {
old_dbc_close = (*cursop)->close;
}
(*cursop)->close = new_dbc_close;
/* overload DBC->dup */
if(old_dbc_dup == NULL) {
old_dbc_dup = (*cursop)->dup;
}
(*cursop)->dup = new_dbc_dup;
}
return ret;
}
/* }}} */
/* {{{ new DB_ENV constructor
*/
int mod_db4_db_env_create(DB_ENV **dbenvp, u_int32_t flags)
{
int cachesize = 0;
int ret;
DB_ENV *dbenv;
if ((ret = db_env_create(dbenvp, 0)) != 0) {
/* FIXME report error */
return ret;
}
dbenv = *dbenvp;
DbEnv::wrap_DB_ENV(dbenv);
/* Here we set defaults settings for the db_env */
/* grab context info from httpd.conf for error file */
/* grab context info for cachesize */
if (0 && cachesize) {
if ((ret = dbenv->set_cachesize(dbenv, 0, cachesize, 0)) != 0) {
dbenv->err(dbenv, ret, "set_cachesize");
dbenv->close(dbenv, 0);
}
}
/* overload DB_ENV->open */
if(old_db_env_open == NULL) {
old_db_env_open = dbenv->open;
}
dbenv->open = new_db_env_open;
/* overload DB_ENV->close */
if(old_db_env_close == NULL) {
old_db_env_close = dbenv->close;
}
dbenv->close = new_db_env_close;
/* overload DB_ENV->log_cursor */
if(old_db_env_log_cursor == NULL) {
old_db_env_log_cursor = dbenv->log_cursor;
}
dbenv->log_cursor = new_db_env_log_cursor;
/* overload DB_ENV->txn_begin */
if(old_db_env_txn_begin == NULL) {
old_db_env_txn_begin = dbenv->txn_begin;
}
dbenv->txn_begin = new_db_env_txn_begin;
return 0;
}
/* }}} */
/* {{{ new DB constructor
*/
int mod_db4_db_create(DB **dbp, DB_ENV *dbenv, u_int32_t flags)
{
int ret;
flags = 0;
if((ret = db_create(dbp, dbenv, flags)) == 0) {
// FIXME this should be removed I think register_db(*dbp);
/* overload DB->open */
if(old_db_open == NULL) {
old_db_open = (*dbp)->open;
}
(*dbp)->open = new_db_open;
/* overload DB->close */
if(old_db_close == NULL) {
old_db_close = (*dbp)->close;
}
(*dbp)->close = new_db_close;
/* overload DB->cursor */
if(old_db_cursor == NULL) {
old_db_cursor = (*dbp)->cursor;
}
(*dbp)->cursor = new_db_cursor;
}
return ret;
}
/* }}} */
void mod_db4_child_clean_request_shutdown()
{
DBC *cursor;
DB_TXN *transaction;
while(cursor = (DBC *)skiplist_pop(&open_cursors, NULL)) {
cursor->close(cursor);
}
while(transaction = (DB_TXN *)skiplist_pop(&open_transactions, NULL)) {
transaction->abort(transaction);
}
}
void mod_db4_child_clean_process_shutdown()
{
DB *db;
DB_ENV *dbenv;
mod_db4_child_clean_request_shutdown();
while(db = (DB *)skiplist_pop(&open_dbs, NULL)) {
db->close(db, 0);
}
while(dbenv = (DB_ENV *)skiplist_pop(&open_dbenvs, NULL)) {
DbEnv *dbe = DbEnv::get_DbEnv(dbenv);
global_ref_count_decrease(dbenv->db_home);
dbe->close(0);
delete dbe;
}
}
/* vim: set ts=4 sts=4 expandtab bs=2 ai fdm=marker: */

32
mod_db4/utils.h Normal file
View File

@@ -0,0 +1,32 @@
/*-
* Copyright (c) 2004,2008 Oracle. All rights reserved.
*
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
* authors: George Schlossnagle <george@omniti.com>
*/
#ifndef DB4_UTILS_H
#define DB4_UTILS_H
#include "db_cxx.h"
#include "mod_db4_export.h"
/* locks */
int env_locks_init();
void env_global_rw_lock();
void env_global_rd_lock();
void env_global_unlock();
void env_wait_for_child_crash();
void env_child_crash();
void env_ok_to_proceed();
void env_rsrc_list_init();
int global_ref_count_increase(char *path);
int global_ref_count_decrease(char *path);
int global_ref_count_get(const char *path);
void global_ref_count_clean();
#endif
/* vim: set ts=4 sts=4 expandtab bs=2 ai fdm=marker: */