Import BSDDB 4.7.25 (as of svn r89086)
This commit is contained in:
48
mod_db4/ABOUT
Normal file
48
mod_db4/ABOUT
Normal 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
10
mod_db4/BSD
Normal 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
13
mod_db4/INSTALL
Normal 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
26
mod_db4/Makefile.in
Normal 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
22
mod_db4/config.h.in
Normal 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
3219
mod_db4/configure
vendored
Normal file
File diff suppressed because it is too large
Load Diff
114
mod_db4/configure.in
Normal file
114
mod_db4/configure.in
Normal 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
138
mod_db4/mm_hash.c
Normal 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
48
mod_db4/mm_hash.h
Normal 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
130
mod_db4/mod_db4.c
Normal 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
27
mod_db4/mod_db4_export.h
Normal 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
115
mod_db4/sem_utils.c
Normal 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
21
mod_db4/sem_utils.h
Normal 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
514
mod_db4/skiplist.c
Normal 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
88
mod_db4/skiplist.h
Normal 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
617
mod_db4/utils.c
Normal 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
32
mod_db4/utils.h
Normal 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: */
|
||||
Reference in New Issue
Block a user