mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-12-29 11:09:34 -05:00
Add code to bdb_attribute and bdb_group where use TXN id and to provide error, but need to rework callers (and their callers) to ensure error is properly bubbled up to the backend operation routine handling the transaction. Ugh.
481 lines
10 KiB
C
481 lines
10 KiB
C
/* init.c - initialize bdb backend */
|
|
/* $OpenLDAP$ */
|
|
/*
|
|
* Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
|
|
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
|
|
*/
|
|
|
|
#include "portable.h"
|
|
|
|
#include <stdio.h>
|
|
#include <ac/string.h>
|
|
#include <ac/unistd.h>
|
|
#include <ac/stdlib.h>
|
|
|
|
#include "back-bdb.h"
|
|
#include "external.h"
|
|
|
|
static struct bdbi_database {
|
|
char *file;
|
|
char *name;
|
|
int type;
|
|
int flags;
|
|
} bdbi_databases[] = {
|
|
{ "id2entry" BDB_SUFFIX, "id2entry", DB_BTREE, 0 },
|
|
#ifdef BDB_HIER
|
|
{ "id2parent" BDB_SUFFIX, "id2parent", DB_BTREE, 0 },
|
|
#else
|
|
{ "dn2id" BDB_SUFFIX, "dn2id", DB_BTREE, 0 },
|
|
#endif
|
|
{ NULL, NULL, 0, 0 }
|
|
};
|
|
|
|
#if 0
|
|
static int
|
|
bdb_destroy( BackendInfo *bi )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
bdb_open( BackendInfo *bi )
|
|
{
|
|
/* initialize the underlying database system */
|
|
Debug( LDAP_DEBUG_TRACE, "bdb_open: initialize BDB backend\n",
|
|
0, 0, 0 );
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
bdb_close( BackendInfo *bi )
|
|
{
|
|
/* terminate the underlying database system */
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int
|
|
bdb_db_init( BackendDB *be )
|
|
{
|
|
struct bdb_info *bdb;
|
|
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"bdb_db_init: Initializing BDB database\n",
|
|
0, 0, 0 );
|
|
|
|
/* indicate system schema supported */
|
|
be->be_flags |= SLAP_BFLAG_ALIASES
|
|
| SLAP_BFLAG_REFERRALS
|
|
| SLAP_BFLAG_SUBENTRIES;
|
|
|
|
/* allocate backend-database-specific stuff */
|
|
bdb = (struct bdb_info *) ch_calloc( 1, sizeof(struct bdb_info) );
|
|
|
|
/* DBEnv parameters */
|
|
bdb->bi_dbenv_home = ch_strdup( BDB_DBENV_HOME );
|
|
bdb->bi_dbenv_xflags = 0;
|
|
bdb->bi_dbenv_mode = DEFAULT_MODE;
|
|
bdb->bi_txn = 1; /* default to using transactions */
|
|
|
|
#ifndef NO_THREADS
|
|
bdb->bi_lock_detect = DB_LOCK_NORUN;
|
|
#endif
|
|
|
|
ldap_pvt_thread_mutex_init( &bdb->bi_database_mutex );
|
|
ldap_pvt_thread_mutex_init( &bdb->bi_lastid_mutex );
|
|
#ifdef BDB_HIER
|
|
ldap_pvt_thread_rdwr_init( &bdb->bi_tree_rdwr );
|
|
#endif
|
|
|
|
be->be_private = bdb;
|
|
return 0;
|
|
}
|
|
|
|
#ifndef NO_THREADS
|
|
static void *lock_detect_task( void *arg )
|
|
{
|
|
struct bdb_info *bdb = (struct bdb_info *) arg;
|
|
|
|
while( bdb->bi_dbenv != NULL ) {
|
|
int rc;
|
|
sleep( bdb->bi_lock_detect_seconds );
|
|
|
|
rc = LOCK_DETECT( bdb->bi_dbenv, 0,
|
|
bdb->bi_lock_detect, NULL );
|
|
|
|
if( rc != 0 ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
int
|
|
bdb_bt_compare(
|
|
DB *db,
|
|
const DBT *usrkey,
|
|
const DBT *curkey
|
|
)
|
|
{
|
|
unsigned char *u, *c;
|
|
int i;
|
|
|
|
u = usrkey->data;
|
|
c = curkey->data;
|
|
|
|
#ifdef WORDS_BIGENDIAN
|
|
for( i = 0; i < sizeof(ID); i++)
|
|
#else
|
|
for( i = sizeof(ID)-1; i >= 0; i--)
|
|
#endif
|
|
{
|
|
if( u[i] - c[i] )
|
|
return u[i] - c[i];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
bdb_db_open( BackendDB *be )
|
|
{
|
|
int rc, i;
|
|
struct bdb_info *bdb = (struct bdb_info *) be->be_private;
|
|
u_int32_t flags;
|
|
|
|
Debug( LDAP_DEBUG_ARGS,
|
|
"bdb_db_open: %s\n",
|
|
be->be_suffix[0]->bv_val, 0, 0 );
|
|
|
|
/* we should check existance of dbenv_home and db_directory */
|
|
|
|
rc = db_env_create( &bdb->bi_dbenv, 0 );
|
|
if( rc != 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"bdb_db_open: db_env_create failed: %s (%d)\n",
|
|
db_strerror(rc), rc, 0 );
|
|
return rc;
|
|
}
|
|
|
|
flags = DB_INIT_MPOOL | DB_THREAD | DB_CREATE;
|
|
|
|
if( bdb->bi_txn ) {
|
|
flags |= DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN | DB_RECOVER;
|
|
|
|
} else {
|
|
flags |= DB_INIT_CDB;
|
|
bdb->bi_txn_cp = 0;
|
|
}
|
|
|
|
bdb->bi_dbenv->set_errpfx( bdb->bi_dbenv, be->be_suffix[0]->bv_val );
|
|
bdb->bi_dbenv->set_errcall( bdb->bi_dbenv, bdb_errcall );
|
|
|
|
#ifdef BDB_SUBDIRS
|
|
{
|
|
char dir[MAXPATHLEN];
|
|
size_t len = strlen( bdb->bi_dbenv_home );
|
|
|
|
strcpy( dir, bdb->bi_dbenv_home );
|
|
strcat( &dir[len], BDB_TMP_SUBDIR );
|
|
|
|
rc = bdb->bi_dbenv->set_tmp_dir( bdb->bi_dbenv, dir );
|
|
if( rc != 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"bdb_db_open: set_tmp_dir(%s) failed: %s (%d)\n",
|
|
dir, db_strerror(rc), rc );
|
|
return rc;
|
|
}
|
|
|
|
strcat( &dir[len], BDB_LG_SUBDIR );
|
|
|
|
rc = bdb->bi_dbenv->set_lg_dir( bdb->bi_dbenv, dir );
|
|
if( rc != 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"bdb_db_open: set_lg_dir(%s) failed: %s (%d)\n",
|
|
dir, db_strerror(rc), rc );
|
|
return rc;
|
|
}
|
|
|
|
strcat( &dir[len], BDB_DATA_SUBDIR );
|
|
|
|
rc = bdb->bi_dbenv->set_data_dir( bdb->bi_dbenv, dir );
|
|
if( rc != 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"bdb_db_open: set_data_dir(%s) failed: %s (%d)\n",
|
|
dir, db_strerror(rc), rc );
|
|
return rc;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"bdb_db_open: dbenv_open(%s)\n",
|
|
bdb->bi_dbenv_home, 0, 0);
|
|
|
|
rc = bdb->bi_dbenv->open( bdb->bi_dbenv,
|
|
bdb->bi_dbenv_home,
|
|
flags,
|
|
bdb->bi_dbenv_mode );
|
|
if( rc != 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"bdb_db_open: dbenv_open failed: %s (%d)\n",
|
|
db_strerror(rc), rc, 0 );
|
|
return rc;
|
|
}
|
|
|
|
if( bdb->bi_dbenv_xflags != 0 ) {
|
|
rc = bdb->bi_dbenv->set_flags( bdb->bi_dbenv,
|
|
bdb->bi_dbenv_xflags, 1);
|
|
if( rc != 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"bdb_db_open: dbenv_set_flags failed: %s (%d)\n",
|
|
db_strerror(rc), rc, 0 );
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
flags = DB_THREAD | DB_CREATE | bdb->bi_db_opflags;
|
|
|
|
bdb->bi_databases = (struct bdb_db_info **) ch_malloc(
|
|
BDB_INDICES * sizeof(struct bdb_db_info *) );
|
|
|
|
/* open (and create) main database */
|
|
for( i = 0; bdbi_databases[i].name; i++ ) {
|
|
struct bdb_db_info *db;
|
|
|
|
db = (struct bdb_db_info *) ch_calloc(1, sizeof(struct bdb_db_info));
|
|
|
|
rc = db_create( &db->bdi_db, bdb->bi_dbenv, 0 );
|
|
if( rc != 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"bdb_db_open: db_create(%s) failed: %s (%d)\n",
|
|
bdb->bi_dbenv_home, db_strerror(rc), rc );
|
|
return rc;
|
|
}
|
|
|
|
if( i == BDB_ID2ENTRY ) {
|
|
rc = db->bdi_db->set_bt_compare( db->bdi_db,
|
|
bdb_bt_compare );
|
|
rc = db->bdi_db->set_pagesize( db->bdi_db,
|
|
BDB_ID2ENTRY_PAGESIZE );
|
|
} else {
|
|
#ifdef BDB_HIER
|
|
rc = db->bdi_db->set_bt_compare( db->bdi_db,
|
|
bdb_bt_compare );
|
|
#elif defined(BDB_IDL_MULTI)
|
|
rc = db->bdi_db->set_flags( db->bdi_db,
|
|
DB_DUP | DB_DUPSORT | DB_NODUPDATA );
|
|
rc = db->bdi_db->set_dup_compare( db->bdi_db,
|
|
bdb_bt_compare );
|
|
#endif
|
|
rc = db->bdi_db->set_pagesize( db->bdi_db,
|
|
BDB_PAGESIZE );
|
|
}
|
|
|
|
rc = db->bdi_db->open( db->bdi_db,
|
|
bdbi_databases[i].file,
|
|
/* bdbi_databases[i].name, */ NULL,
|
|
bdbi_databases[i].type,
|
|
bdbi_databases[i].flags | flags,
|
|
bdb->bi_dbenv_mode );
|
|
|
|
if( rc != 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"bdb_db_open: db_open(%s) failed: %s (%d)\n",
|
|
bdb->bi_dbenv_home, db_strerror(rc), rc );
|
|
return rc;
|
|
}
|
|
|
|
db->bdi_name = bdbi_databases[i].name;
|
|
bdb->bi_databases[i] = db;
|
|
}
|
|
|
|
bdb->bi_databases[i] = NULL;
|
|
bdb->bi_ndatabases = i;
|
|
|
|
/* get nextid */
|
|
rc = bdb_last_id( be, NULL );
|
|
if( rc != 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"bdb_db_open: last_id(%s) failed: %s (%d)\n",
|
|
bdb->bi_dbenv_home, db_strerror(rc), rc );
|
|
return rc;
|
|
}
|
|
|
|
/* <insert> open (and create) index databases */
|
|
#ifdef BDB_HIER
|
|
rc = bdb_build_tree( be );
|
|
#endif
|
|
|
|
#ifndef NO_THREADS
|
|
if( bdb->bi_lock_detect != DB_LOCK_NORUN ) {
|
|
/* listener as a separate THREAD */
|
|
rc = ldap_pvt_thread_create( &bdb->bi_lock_detect_tid,
|
|
1, lock_detect_task, bdb );
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
bdb_db_close( BackendDB *be )
|
|
{
|
|
int rc;
|
|
struct bdb_info *bdb = (struct bdb_info *) be->be_private;
|
|
struct bdb_db_info *db;
|
|
|
|
while( bdb->bi_ndatabases-- ) {
|
|
db = bdb->bi_databases[bdb->bi_ndatabases];
|
|
rc = db->bdi_db->close( db->bdi_db, 0 );
|
|
/* Lower numbered names are not strdup'd */
|
|
if( bdb->bi_ndatabases >= BDB_NDB )
|
|
free( db->bdi_name );
|
|
free( db );
|
|
}
|
|
free( bdb->bi_databases );
|
|
bdb_attr_index_destroy( bdb->bi_attrs );
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
bdb_db_destroy( BackendDB *be )
|
|
{
|
|
int rc;
|
|
struct bdb_info *bdb = (struct bdb_info *) be->be_private;
|
|
|
|
/* force a checkpoint */
|
|
if( bdb->bi_txn ) {
|
|
rc = TXN_CHECKPOINT( bdb->bi_dbenv, 0, 0, DB_FORCE );
|
|
if( rc != 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"bdb_db_destroy: txn_checkpoint failed: %s (%d)\n",
|
|
db_strerror(rc), rc, 0 );
|
|
}
|
|
}
|
|
|
|
/* close db environment */
|
|
if( bdb->bi_dbenv ) {
|
|
rc = bdb->bi_dbenv->close( bdb->bi_dbenv, 0 );
|
|
bdb->bi_dbenv = NULL;
|
|
if( rc != 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"bdb_db_destroy: close failed: %s (%d)\n",
|
|
db_strerror(rc), rc, 0 );
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef SLAPD_BDB_DYNAMIC
|
|
int back_bdb_LTX_init_module( int argc, char *argv[] ) {
|
|
BackendInfo bi;
|
|
|
|
memset( &bi, '\0', sizeof(bi) );
|
|
bi.bi_type = "bdb";
|
|
bi.bi_init = bdb_initialize;
|
|
|
|
backend_add( &bi );
|
|
return 0;
|
|
}
|
|
#endif /* SLAPD_BDB_DYNAMIC */
|
|
|
|
int
|
|
bdb_initialize(
|
|
BackendInfo *bi
|
|
)
|
|
{
|
|
static char *controls[] = {
|
|
LDAP_CONTROL_MANAGEDSAIT,
|
|
LDAP_CONTROL_SUBENTRIES,
|
|
NULL
|
|
};
|
|
|
|
{ /* version check */
|
|
int major, minor, patch;
|
|
char *version = db_version( &major, &minor, &patch );
|
|
|
|
if( major != DB_VERSION_MAJOR ||
|
|
minor != DB_VERSION_MINOR ||
|
|
patch < DB_VERSION_PATCH )
|
|
{
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"bi_back_initialize: version mismatch\n"
|
|
"\texpected: " DB_VERSION_STRING "\n"
|
|
"\tgot: %s \n", version, 0, 0 );
|
|
}
|
|
|
|
Debug( LDAP_DEBUG_ANY, "bdb_initialize: %s\n",
|
|
version, 0, 0 );
|
|
}
|
|
|
|
#if 0
|
|
db_env_set_func_malloc( ch_malloc );
|
|
db_env_set_func_realloc( ch_realloc );
|
|
db_env_set_func_free( ch_free );
|
|
#endif
|
|
|
|
db_env_set_func_yield( ldap_pvt_thread_yield );
|
|
|
|
bi->bi_controls = controls;
|
|
|
|
bi->bi_open = 0;
|
|
bi->bi_close = 0;
|
|
bi->bi_config = 0;
|
|
bi->bi_destroy = 0;
|
|
|
|
bi->bi_db_init = bdb_db_init;
|
|
bi->bi_db_config = bdb_db_config;
|
|
bi->bi_db_open = bdb_db_open;
|
|
bi->bi_db_close = bdb_db_close;
|
|
bi->bi_db_destroy = bdb_db_destroy;
|
|
|
|
bi->bi_op_add = bdb_add;
|
|
bi->bi_op_bind = bdb_bind;
|
|
bi->bi_op_compare = bdb_compare;
|
|
bi->bi_op_delete = bdb_delete;
|
|
bi->bi_op_modify = bdb_modify;
|
|
bi->bi_op_modrdn = bdb_modrdn;
|
|
bi->bi_op_search = bdb_search;
|
|
|
|
bi->bi_op_unbind = 0;
|
|
bi->bi_op_abandon = 0;
|
|
|
|
bi->bi_extended = bdb_extended;
|
|
|
|
#if 0
|
|
/*
|
|
* these routines (and their callers) are not yet designed
|
|
* to work with transaction. Using them may cause deadlock.
|
|
*/
|
|
bi->bi_acl_group = bdb_group;
|
|
bi->bi_acl_attribute = bdb_attribute;
|
|
#else
|
|
bi->bi_acl_group = 0;
|
|
bi->bi_acl_attribute = 0;
|
|
#endif
|
|
|
|
bi->bi_chk_referrals = bdb_referrals;
|
|
bi->bi_entry_release_rw = bdb_entry_release;
|
|
|
|
/*
|
|
* hooks for slap tools
|
|
*/
|
|
bi->bi_tool_entry_open = bdb_tool_entry_open;
|
|
bi->bi_tool_entry_close = bdb_tool_entry_close;
|
|
bi->bi_tool_entry_first = bdb_tool_entry_next;
|
|
bi->bi_tool_entry_next = bdb_tool_entry_next;
|
|
bi->bi_tool_entry_get = bdb_tool_entry_get;
|
|
bi->bi_tool_entry_put = bdb_tool_entry_put;
|
|
bi->bi_tool_entry_reindex = bdb_tool_entry_reindex;
|
|
bi->bi_tool_sync = 0;
|
|
|
|
bi->bi_connection_init = 0;
|
|
bi->bi_connection_destroy = 0;
|
|
|
|
return 0;
|
|
}
|