Back to index

openldap  2.4.31
init.c
Go to the documentation of this file.
00001 /* init.c - initialize bdb backend */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2000-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 
00017 #include "portable.h"
00018 
00019 #include <stdio.h>
00020 #include <ac/string.h>
00021 #include <ac/unistd.h>
00022 #include <ac/stdlib.h>
00023 #include <ac/errno.h>
00024 #include <sys/stat.h>
00025 #include "back-bdb.h"
00026 #include <lutil.h>
00027 #include <ldap_rq.h>
00028 #include "alock.h"
00029 #include "config.h"
00030 
00031 static const struct bdbi_database {
00032        char *file;
00033        struct berval name;
00034        int type;
00035        int flags;
00036 } bdbi_databases[] = {
00037        { "id2entry" BDB_SUFFIX, BER_BVC("id2entry"), DB_BTREE, 0 },
00038        { "dn2id" BDB_SUFFIX, BER_BVC("dn2id"), DB_BTREE, 0 },
00039        { NULL, BER_BVNULL, 0, 0 }
00040 };
00041 
00042 typedef void * db_malloc(size_t);
00043 typedef void * db_realloc(void *, size_t);
00044 
00045 #define bdb_db_init  BDB_SYMBOL(db_init)
00046 #define bdb_db_open BDB_SYMBOL(db_open)
00047 #define bdb_db_close BDB_SYMBOL(db_close)
00048 
00049 static int
00050 bdb_db_init( BackendDB *be, ConfigReply *cr )
00051 {
00052        struct bdb_info      *bdb;
00053        int rc;
00054 
00055        Debug( LDAP_DEBUG_TRACE,
00056               LDAP_XSTRING(bdb_db_init) ": Initializing " BDB_UCTYPE " database\n",
00057               0, 0, 0 );
00058 
00059        /* allocate backend-database-specific stuff */
00060        bdb = (struct bdb_info *) ch_calloc( 1, sizeof(struct bdb_info) );
00061 
00062        /* DBEnv parameters */
00063        bdb->bi_dbenv_home = ch_strdup( SLAPD_DEFAULT_DB_DIR );
00064        bdb->bi_dbenv_xflags = DB_TIME_NOTGRANTED;
00065        bdb->bi_dbenv_mode = SLAPD_DEFAULT_DB_MODE;
00066 
00067        bdb->bi_cache.c_maxsize = DEFAULT_CACHE_SIZE;
00068        bdb->bi_cache.c_minfree = 1;
00069 
00070        bdb->bi_lock_detect = DB_LOCK_DEFAULT;
00071        bdb->bi_search_stack_depth = DEFAULT_SEARCH_STACK_DEPTH;
00072        bdb->bi_search_stack = NULL;
00073 
00074        ldap_pvt_thread_mutex_init( &bdb->bi_database_mutex );
00075        ldap_pvt_thread_mutex_init( &bdb->bi_lastid_mutex );
00076 #ifdef BDB_HIER
00077        ldap_pvt_thread_mutex_init( &bdb->bi_modrdns_mutex );
00078 #endif
00079        ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_lru_mutex );
00080        ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_count_mutex );
00081        ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_eifree_mutex );
00082        ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_dntree.bei_kids_mutex );
00083        ldap_pvt_thread_rdwr_init ( &bdb->bi_cache.c_rwlock );
00084        ldap_pvt_thread_rdwr_init( &bdb->bi_idl_tree_rwlock );
00085        ldap_pvt_thread_mutex_init( &bdb->bi_idl_tree_lrulock );
00086 
00087        be->be_private = bdb;
00088        be->be_cf_ocs = be->bd_info->bi_cf_ocs;
00089 
00090 #ifndef BDB_MULTIPLE_SUFFIXES
00091        SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
00092 #endif
00093 
00094        rc = bdb_monitor_db_init( be );
00095 
00096        return rc;
00097 }
00098 
00099 static int
00100 bdb_db_close( BackendDB *be, ConfigReply *cr );
00101 
00102 static int
00103 bdb_db_open( BackendDB *be, ConfigReply *cr )
00104 {
00105        int rc, i;
00106        struct bdb_info *bdb = (struct bdb_info *) be->be_private;
00107        struct stat stat1, stat2;
00108        u_int32_t flags;
00109        char path[MAXPATHLEN];
00110        char *dbhome;
00111        Entry *e = NULL;
00112        int do_recover = 0, do_alock_recover = 0;
00113        int alockt, quick = 0;
00114        int do_retry = 1;
00115 
00116        if ( be->be_suffix == NULL ) {
00117               Debug( LDAP_DEBUG_ANY,
00118                      LDAP_XSTRING(bdb_db_open) ": need suffix.\n",
00119                      1, 0, 0 );
00120               return -1;
00121        }
00122 
00123        Debug( LDAP_DEBUG_ARGS,
00124               LDAP_XSTRING(bdb_db_open) ": \"%s\"\n",
00125               be->be_suffix[0].bv_val, 0, 0 );
00126 
00127        /* Check existence of dbenv_home. Any error means trouble */
00128        rc = stat( bdb->bi_dbenv_home, &stat1 );
00129        if( rc != 0 ) {
00130               Debug( LDAP_DEBUG_ANY,
00131                      LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
00132                      "cannot access database directory \"%s\" (%d).\n",
00133                      be->be_suffix[0].bv_val, bdb->bi_dbenv_home, errno );
00134               return -1;
00135        }
00136 
00137        /* Perform database use arbitration/recovery logic */
00138        alockt = (slapMode & SLAP_TOOL_READONLY) ? ALOCK_LOCKED : ALOCK_UNIQUE;
00139        if ( slapMode & SLAP_TOOL_QUICK ) {
00140               alockt |= ALOCK_NOSAVE;
00141               quick = 1;
00142        }
00143 
00144        rc = alock_open( &bdb->bi_alock_info, 
00145                             "slapd", 
00146                             bdb->bi_dbenv_home, alockt );
00147 
00148        /* alockt is TRUE if the existing environment was created in Quick mode */
00149        alockt = (rc & ALOCK_NOSAVE) ? 1 : 0;
00150        rc &= ~ALOCK_NOSAVE;
00151 
00152        if( rc == ALOCK_RECOVER ) {
00153               Debug( LDAP_DEBUG_ANY,
00154                      LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
00155                      "unclean shutdown detected; attempting recovery.\n", 
00156                      be->be_suffix[0].bv_val, 0, 0 );
00157               do_alock_recover = 1;
00158               do_recover = DB_RECOVER;
00159        } else if( rc == ALOCK_BUSY ) {
00160               Debug( LDAP_DEBUG_ANY,
00161                      LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
00162                      "database already in use.\n", 
00163                      be->be_suffix[0].bv_val, 0, 0 );
00164               return -1;
00165        } else if( rc != ALOCK_CLEAN ) {
00166               Debug( LDAP_DEBUG_ANY,
00167                      LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
00168                      "alock package is unstable.\n", 
00169                      be->be_suffix[0].bv_val, 0, 0 );
00170               return -1;
00171        }
00172        if ( rc == ALOCK_CLEAN )
00173               be->be_flags |= SLAP_DBFLAG_CLEAN;
00174 
00175        /*
00176         * The DB_CONFIG file may have changed. If so, recover the
00177         * database so that new settings are put into effect. Also
00178         * note the possible absence of DB_CONFIG in the log.
00179         */
00180        if( stat( bdb->bi_db_config_path, &stat1 ) == 0 ) {
00181               if ( !do_recover ) {
00182                      char *ptr = lutil_strcopy(path, bdb->bi_dbenv_home);
00183                      *ptr++ = LDAP_DIRSEP[0];
00184                      strcpy( ptr, "__db.001" );
00185                      if( stat( path, &stat2 ) == 0 ) {
00186                             if( stat2.st_mtime < stat1.st_mtime ) {
00187                                    Debug( LDAP_DEBUG_ANY,
00188                                           LDAP_XSTRING(bdb_db_open) ": DB_CONFIG for suffix \"%s\" has changed.\n",
00189                                                  be->be_suffix[0].bv_val, 0, 0 );
00190                                    if ( quick ) {
00191                                           Debug( LDAP_DEBUG_ANY,
00192                                                  "Cannot use Quick mode; perform manual recovery first.\n",
00193                                                  0, 0, 0 );
00194                                           slapMode ^= SLAP_TOOL_QUICK;
00195                                           rc = -1;
00196                                           goto fail;
00197                                    } else {
00198                                           Debug( LDAP_DEBUG_ANY,
00199                                                  "Performing database recovery to activate new settings.\n",
00200                                                  0, 0, 0 );
00201                                    }
00202                                    do_recover = DB_RECOVER;
00203                             }
00204                      }
00205               }
00206        }
00207        else {
00208               Debug( LDAP_DEBUG_ANY,
00209                      LDAP_XSTRING(bdb_db_open) ": warning - no DB_CONFIG file found "
00210                      "in directory %s: (%d).\n"
00211                      "Expect poor performance for suffix \"%s\".\n",
00212                      bdb->bi_dbenv_home, errno, be->be_suffix[0].bv_val );
00213        }
00214 
00215        /* Always let slapcat run, regardless of environment state.
00216         * This can be used to cause a cache flush after an unclean
00217         * shutdown.
00218         */
00219        if ( do_recover && ( slapMode & SLAP_TOOL_READONLY )) {
00220               Debug( LDAP_DEBUG_ANY,
00221                      LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
00222                      "recovery skipped in read-only mode. "
00223                      "Run manual recovery if errors are encountered.\n",
00224                      be->be_suffix[0].bv_val, 0, 0 );
00225               do_recover = 0;
00226               do_alock_recover = 0;
00227               quick = alockt;
00228        }
00229 
00230        /* An existing environment in Quick mode has nothing to recover. */
00231        if ( alockt && do_recover ) {
00232               Debug( LDAP_DEBUG_ANY,
00233                      LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
00234                      "cannot recover, database must be reinitialized.\n", 
00235                      be->be_suffix[0].bv_val, 0, 0 );
00236               rc = -1;
00237               goto fail;
00238        }
00239 
00240        rc = db_env_create( &bdb->bi_dbenv, 0 );
00241        if( rc != 0 ) {
00242               Debug( LDAP_DEBUG_ANY,
00243                      LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
00244                      "db_env_create failed: %s (%d).\n",
00245                      be->be_suffix[0].bv_val, db_strerror(rc), rc );
00246               goto fail;
00247        }
00248 
00249 #ifdef HAVE_EBCDIC
00250        strcpy( path, bdb->bi_dbenv_home );
00251        __atoe( path );
00252        dbhome = path;
00253 #else
00254        dbhome = bdb->bi_dbenv_home;
00255 #endif
00256 
00257        /* If existing environment is clean but doesn't support
00258         * currently requested modes, remove it.
00259         */
00260        if ( !do_recover && ( alockt ^ quick )) {
00261 shm_retry:
00262               rc = bdb->bi_dbenv->remove( bdb->bi_dbenv, dbhome, DB_FORCE );
00263               if ( rc ) {
00264                      Debug( LDAP_DEBUG_ANY,
00265                             LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
00266                             "dbenv remove failed: %s (%d).\n",
00267                             be->be_suffix[0].bv_val, db_strerror(rc), rc );
00268                      bdb->bi_dbenv = NULL;
00269                      goto fail;
00270               }
00271               rc = db_env_create( &bdb->bi_dbenv, 0 );
00272               if( rc != 0 ) {
00273                      Debug( LDAP_DEBUG_ANY,
00274                             LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
00275                             "db_env_create failed: %s (%d).\n",
00276                             be->be_suffix[0].bv_val, db_strerror(rc), rc );
00277                      goto fail;
00278               }
00279        }
00280 
00281        bdb->bi_dbenv->set_errpfx( bdb->bi_dbenv, be->be_suffix[0].bv_val );
00282        bdb->bi_dbenv->set_errcall( bdb->bi_dbenv, bdb_errcall );
00283 
00284        bdb->bi_dbenv->set_lk_detect( bdb->bi_dbenv, bdb->bi_lock_detect );
00285 
00286        if ( !BER_BVISNULL( &bdb->bi_db_crypt_key )) {
00287               rc = bdb->bi_dbenv->set_encrypt( bdb->bi_dbenv, bdb->bi_db_crypt_key.bv_val,
00288                      DB_ENCRYPT_AES );
00289               if ( rc ) {
00290                      Debug( LDAP_DEBUG_ANY,
00291                             LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
00292                             "dbenv set_encrypt failed: %s (%d).\n",
00293                             be->be_suffix[0].bv_val, db_strerror(rc), rc );
00294                      goto fail;
00295               }
00296        }
00297 
00298        /* One long-lived TXN per thread, two TXNs per write op */
00299        bdb->bi_dbenv->set_tx_max( bdb->bi_dbenv, connection_pool_max * 3 );
00300 
00301        if( bdb->bi_dbenv_xflags != 0 ) {
00302               rc = bdb->bi_dbenv->set_flags( bdb->bi_dbenv,
00303                      bdb->bi_dbenv_xflags, 1);
00304               if( rc != 0 ) {
00305                      Debug( LDAP_DEBUG_ANY,
00306                             LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
00307                             "dbenv_set_flags failed: %s (%d).\n",
00308                             be->be_suffix[0].bv_val, db_strerror(rc), rc );
00309                      goto fail;
00310               }
00311        }
00312 
00313 #define       BDB_TXN_FLAGS (DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN)
00314 
00315        Debug( LDAP_DEBUG_TRACE,
00316               LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
00317               "dbenv_open(%s).\n",
00318               be->be_suffix[0].bv_val, bdb->bi_dbenv_home, 0);
00319 
00320        flags = DB_INIT_MPOOL | DB_CREATE | DB_THREAD;
00321 
00322        if ( !quick )
00323               flags |= BDB_TXN_FLAGS;
00324 
00325        /* If a key was set, use shared memory for the BDB environment */
00326        if ( bdb->bi_shm_key ) {
00327               bdb->bi_dbenv->set_shm_key( bdb->bi_dbenv, bdb->bi_shm_key );
00328               flags |= DB_SYSTEM_MEM;
00329        }
00330        rc = (bdb->bi_dbenv->open)( bdb->bi_dbenv, dbhome,
00331                      flags | do_recover, bdb->bi_dbenv_mode );
00332 
00333        if ( rc ) {
00334               /* Regular open failed, probably a missing shm environment.
00335                * Start over, do a recovery.
00336                */
00337               if ( !do_recover && bdb->bi_shm_key && do_retry ) {
00338                      bdb->bi_dbenv->close( bdb->bi_dbenv, 0 );
00339                      rc = db_env_create( &bdb->bi_dbenv, 0 );
00340                      if( rc == 0 ) {
00341                             Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open)
00342                                    ": database \"%s\": "
00343                                    "shared memory env open failed, assuming stale env.\n",
00344                                    be->be_suffix[0].bv_val, 0, 0 );
00345                             do_retry = 0;
00346                             goto shm_retry;
00347                      }
00348               }
00349               Debug( LDAP_DEBUG_ANY,
00350                      LDAP_XSTRING(bdb_db_open) ": database \"%s\" cannot be %s, err %d. "
00351                      "Restore from backup!\n",
00352                      be->be_suffix[0].bv_val, do_recover ? "recovered" : "opened", rc );
00353               goto fail;
00354        }
00355 
00356        if ( do_alock_recover && alock_recover (&bdb->bi_alock_info) != 0 ) {
00357               Debug( LDAP_DEBUG_ANY,
00358                      LDAP_XSTRING(bdb_db_open) ": database \"%s\": alock_recover failed\n",
00359                      be->be_suffix[0].bv_val, 0, 0 );
00360               rc = -1;
00361               goto fail;
00362        }
00363 
00364 #ifdef SLAP_ZONE_ALLOC
00365        if ( bdb->bi_cache.c_maxsize ) {
00366               bdb->bi_cache.c_zctx = slap_zn_mem_create(
00367                      SLAP_ZONE_INITSIZE, SLAP_ZONE_MAXSIZE,
00368                      SLAP_ZONE_DELTA, SLAP_ZONE_SIZE);
00369        }
00370 #endif
00371 
00372        /* dncache defaults to 0 == unlimited
00373         * must be >= entrycache
00374         */
00375        if ( bdb->bi_cache.c_eimax && bdb->bi_cache.c_eimax < bdb->bi_cache.c_maxsize ) {
00376               bdb->bi_cache.c_eimax = bdb->bi_cache.c_maxsize;
00377        }
00378 
00379        if ( bdb->bi_idl_cache_max_size ) {
00380               bdb->bi_idl_tree = NULL;
00381               bdb->bi_idl_cache_size = 0;
00382        }
00383 
00384        flags = DB_THREAD | bdb->bi_db_opflags;
00385 
00386 #ifdef DB_AUTO_COMMIT
00387        if ( !quick )
00388               flags |= DB_AUTO_COMMIT;
00389 #endif
00390 
00391        bdb->bi_databases = (struct bdb_db_info **) ch_malloc(
00392               BDB_INDICES * sizeof(struct bdb_db_info *) );
00393 
00394        /* open (and create) main database */
00395        for( i = 0; bdbi_databases[i].name.bv_val; i++ ) {
00396               struct bdb_db_info *db;
00397 
00398               db = (struct bdb_db_info *) ch_calloc(1, sizeof(struct bdb_db_info));
00399 
00400               rc = db_create( &db->bdi_db, bdb->bi_dbenv, 0 );
00401               if( rc != 0 ) {
00402                      snprintf(cr->msg, sizeof(cr->msg),
00403                             "database \"%s\": db_create(%s) failed: %s (%d).",
00404                             be->be_suffix[0].bv_val, 
00405                             bdb->bi_dbenv_home, db_strerror(rc), rc );
00406                      Debug( LDAP_DEBUG_ANY,
00407                             LDAP_XSTRING(bdb_db_open) ": %s\n",
00408                             cr->msg, 0, 0 );
00409                      goto fail;
00410               }
00411 
00412               if( !BER_BVISNULL( &bdb->bi_db_crypt_key )) {
00413                      rc = db->bdi_db->set_flags( db->bdi_db, DB_ENCRYPT );
00414                      if ( rc ) {
00415                             snprintf(cr->msg, sizeof(cr->msg),
00416                                    "database \"%s\": db set_flags(DB_ENCRYPT)(%s) failed: %s (%d).",
00417                                    be->be_suffix[0].bv_val, 
00418                                    bdb->bi_dbenv_home, db_strerror(rc), rc );
00419                             Debug( LDAP_DEBUG_ANY,
00420                                    LDAP_XSTRING(bdb_db_open) ": %s\n",
00421                                    cr->msg, 0, 0 );
00422                             goto fail;
00423                      }
00424               }
00425 
00426               if( bdb->bi_flags & BDB_CHKSUM ) {
00427                      rc = db->bdi_db->set_flags( db->bdi_db, DB_CHKSUM );
00428                      if ( rc ) {
00429                             snprintf(cr->msg, sizeof(cr->msg),
00430                                    "database \"%s\": db set_flags(DB_CHKSUM)(%s) failed: %s (%d).",
00431                                    be->be_suffix[0].bv_val, 
00432                                    bdb->bi_dbenv_home, db_strerror(rc), rc );
00433                             Debug( LDAP_DEBUG_ANY,
00434                                    LDAP_XSTRING(bdb_db_open) ": %s\n",
00435                                    cr->msg, 0, 0 );
00436                             goto fail;
00437                      }
00438               }
00439 
00440               rc = bdb_db_findsize( bdb, (struct berval *)&bdbi_databases[i].name );
00441 
00442               if( i == BDB_ID2ENTRY ) {
00443                      if ( !rc ) rc = BDB_ID2ENTRY_PAGESIZE;
00444                      rc = db->bdi_db->set_pagesize( db->bdi_db, rc );
00445 
00446                      if ( slapMode & SLAP_TOOL_MODE )
00447                             db->bdi_db->mpf->set_priority( db->bdi_db->mpf,
00448                                    DB_PRIORITY_VERY_LOW );
00449 
00450                      if ( slapMode & SLAP_TOOL_READMAIN ) {
00451                             flags |= DB_RDONLY;
00452                      } else {
00453                             flags |= DB_CREATE;
00454                      }
00455               } else {
00456                      /* Use FS default size if not configured */
00457                      if ( rc )
00458                             rc = db->bdi_db->set_pagesize( db->bdi_db, rc );
00459 
00460                      rc = db->bdi_db->set_flags( db->bdi_db, 
00461                             DB_DUP | DB_DUPSORT );
00462 #ifndef BDB_HIER
00463                      if ( slapMode & SLAP_TOOL_READONLY ) {
00464                             flags |= DB_RDONLY;
00465                      } else {
00466                             flags |= DB_CREATE;
00467                      }
00468 #else
00469                      rc = db->bdi_db->set_dup_compare( db->bdi_db,
00470                             bdb_dup_compare );
00471                      if ( slapMode & (SLAP_TOOL_READONLY|SLAP_TOOL_READMAIN) ) {
00472                             flags |= DB_RDONLY;
00473                      } else {
00474                             flags |= DB_CREATE;
00475                      }
00476 #endif
00477               }
00478 
00479 #ifdef HAVE_EBCDIC
00480               strcpy( path, bdbi_databases[i].file );
00481               __atoe( path );
00482               rc = DB_OPEN( db->bdi_db,
00483                      path,
00484               /*     bdbi_databases[i].name, */ NULL,
00485                      bdbi_databases[i].type,
00486                      bdbi_databases[i].flags | flags,
00487                      bdb->bi_dbenv_mode );
00488 #else
00489               rc = DB_OPEN( db->bdi_db,
00490                      bdbi_databases[i].file,
00491               /*     bdbi_databases[i].name, */ NULL,
00492                      bdbi_databases[i].type,
00493                      bdbi_databases[i].flags | flags,
00494                      bdb->bi_dbenv_mode );
00495 #endif
00496 
00497               if ( rc != 0 ) {
00498                      snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
00499                             "db_open(%s/%s) failed: %s (%d).", 
00500                             be->be_suffix[0].bv_val, 
00501                             bdb->bi_dbenv_home, bdbi_databases[i].file,
00502                             db_strerror(rc), rc );
00503                      Debug( LDAP_DEBUG_ANY,
00504                             LDAP_XSTRING(bdb_db_open) ": %s\n",
00505                             cr->msg, 0, 0 );
00506                      db->bdi_db->close( db->bdi_db, 0 );
00507                      goto fail;
00508               }
00509 
00510               flags &= ~(DB_CREATE | DB_RDONLY);
00511               db->bdi_name = bdbi_databases[i].name;
00512               bdb->bi_databases[i] = db;
00513        }
00514 
00515        bdb->bi_databases[i] = NULL;
00516        bdb->bi_ndatabases = i;
00517 
00518        /* get nextid */
00519        rc = bdb_last_id( be, NULL );
00520        if( rc != 0 ) {
00521               snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
00522                      "last_id(%s) failed: %s (%d).",
00523                      be->be_suffix[0].bv_val, bdb->bi_dbenv_home,
00524                      db_strerror(rc), rc );
00525               Debug( LDAP_DEBUG_ANY,
00526                      LDAP_XSTRING(bdb_db_open) ": %s\n",
00527                      cr->msg, 0, 0 );
00528               goto fail;
00529        }
00530 
00531        if ( !quick ) {
00532               TXN_BEGIN(bdb->bi_dbenv, NULL, &bdb->bi_cache.c_txn, DB_READ_COMMITTED | DB_TXN_NOWAIT);
00533        }
00534 
00535        entry_prealloc( bdb->bi_cache.c_maxsize );
00536        attr_prealloc( bdb->bi_cache.c_maxsize * 20 );
00537 
00538        /* setup for empty-DN contexts */
00539        if ( BER_BVISEMPTY( &be->be_nsuffix[0] )) {
00540               rc = bdb_id2entry( be, NULL, 0, &e );
00541        }
00542        if ( !e ) {
00543               struct berval gluebv = BER_BVC("glue");
00544               Operation op = {0};
00545               Opheader ohdr = {0};
00546               e = entry_alloc();
00547               e->e_id = 0;
00548               ber_dupbv( &e->e_name, (struct berval *)&slap_empty_bv );
00549               ber_dupbv( &e->e_nname, (struct berval *)&slap_empty_bv );
00550               attr_merge_one( e, slap_schema.si_ad_objectClass,
00551                      &gluebv, NULL );
00552               attr_merge_one( e, slap_schema.si_ad_structuralObjectClass,
00553                      &gluebv, NULL );
00554               op.o_hdr = &ohdr;
00555               op.o_bd = be;
00556               op.ora_e = e;
00557               op.o_dn = be->be_rootdn;
00558               op.o_ndn = be->be_rootndn;
00559               slap_add_opattrs( &op, NULL, NULL, 0, 0 );
00560        }
00561        e->e_ocflags = SLAP_OC_GLUE|SLAP_OC__END;
00562        e->e_private = &bdb->bi_cache.c_dntree;
00563        bdb->bi_cache.c_dntree.bei_e = e;
00564 
00565        /* monitor setup */
00566        rc = bdb_monitor_db_open( be );
00567        if ( rc != 0 ) {
00568               goto fail;
00569        }
00570 
00571        bdb->bi_flags |= BDB_IS_OPEN;
00572 
00573        return 0;
00574 
00575 fail:
00576        bdb_db_close( be, NULL );
00577        return rc;
00578 }
00579 
00580 static int
00581 bdb_db_close( BackendDB *be, ConfigReply *cr )
00582 {
00583        int rc;
00584        struct bdb_info *bdb = (struct bdb_info *) be->be_private;
00585        struct bdb_db_info *db;
00586        bdb_idl_cache_entry_t *entry, *next_entry;
00587 
00588        /* monitor handling */
00589        (void)bdb_monitor_db_close( be );
00590 
00591        {
00592               Entry *e = bdb->bi_cache.c_dntree.bei_e;
00593               if ( e ) {
00594                      bdb->bi_cache.c_dntree.bei_e = NULL;
00595                      e->e_private = NULL;
00596                      bdb_entry_return( e );
00597               }
00598        }
00599 
00600        bdb->bi_flags &= ~BDB_IS_OPEN;
00601 
00602        ber_bvarray_free( bdb->bi_db_config );
00603        bdb->bi_db_config = NULL;
00604 
00605        if( bdb->bi_dbenv ) {
00606               /* Free cache locker if we enabled locking.
00607                * TXNs must all be closed before DBs...
00608                */
00609               if ( !( slapMode & SLAP_TOOL_QUICK ) && bdb->bi_cache.c_txn ) {
00610                      TXN_ABORT( bdb->bi_cache.c_txn );
00611                      bdb->bi_cache.c_txn = NULL;
00612               }
00613               bdb_reader_flush( bdb->bi_dbenv );
00614        }
00615 
00616        while( bdb->bi_databases && bdb->bi_ndatabases-- ) {
00617               db = bdb->bi_databases[bdb->bi_ndatabases];
00618               rc = db->bdi_db->close( db->bdi_db, 0 );
00619               /* Lower numbered names are not strdup'd */
00620               if( bdb->bi_ndatabases >= BDB_NDB )
00621                      free( db->bdi_name.bv_val );
00622               free( db );
00623        }
00624        free( bdb->bi_databases );
00625        bdb->bi_databases = NULL;
00626 
00627        bdb_cache_release_all (&bdb->bi_cache);
00628 
00629        if ( bdb->bi_idl_cache_size ) {
00630               avl_free( bdb->bi_idl_tree, NULL );
00631               bdb->bi_idl_tree = NULL;
00632               entry = bdb->bi_idl_lru_head;
00633               do {
00634                      next_entry = entry->idl_lru_next;
00635                      if ( entry->idl )
00636                             free( entry->idl );
00637                      free( entry->kstr.bv_val );
00638                      free( entry );
00639                      entry = next_entry;
00640               } while ( entry != bdb->bi_idl_lru_head );
00641               bdb->bi_idl_lru_head = bdb->bi_idl_lru_tail = NULL;
00642        }
00643 
00644        /* close db environment */
00645        if( bdb->bi_dbenv ) {
00646               /* force a checkpoint, but not if we were ReadOnly,
00647                * and not in Quick mode since there are no transactions there.
00648                */
00649               if ( !( slapMode & ( SLAP_TOOL_QUICK|SLAP_TOOL_READONLY ))) {
00650                      rc = TXN_CHECKPOINT( bdb->bi_dbenv, 0, 0, DB_FORCE );
00651                      if( rc != 0 ) {
00652                             Debug( LDAP_DEBUG_ANY,
00653                                    "bdb_db_close: database \"%s\": "
00654                                    "txn_checkpoint failed: %s (%d).\n",
00655                                    be->be_suffix[0].bv_val, db_strerror(rc), rc );
00656                      }
00657               }
00658 
00659               rc = bdb->bi_dbenv->close( bdb->bi_dbenv, 0 );
00660               bdb->bi_dbenv = NULL;
00661               if( rc != 0 ) {
00662                      Debug( LDAP_DEBUG_ANY,
00663                             "bdb_db_close: database \"%s\": "
00664                             "close failed: %s (%d)\n",
00665                             be->be_suffix[0].bv_val, db_strerror(rc), rc );
00666                      return rc;
00667               }
00668        }
00669 
00670        rc = alock_close( &bdb->bi_alock_info, slapMode & SLAP_TOOL_QUICK );
00671        if( rc != 0 ) {
00672               Debug( LDAP_DEBUG_ANY,
00673                      "bdb_db_close: database \"%s\": alock_close failed\n",
00674                      be->be_suffix[0].bv_val, 0, 0 );
00675               return -1;
00676        }
00677 
00678        return 0;
00679 }
00680 
00681 static int
00682 bdb_db_destroy( BackendDB *be, ConfigReply *cr )
00683 {
00684        struct bdb_info *bdb = (struct bdb_info *) be->be_private;
00685 
00686        /* stop and remove checkpoint task */
00687        if ( bdb->bi_txn_cp_task ) {
00688               struct re_s *re = bdb->bi_txn_cp_task;
00689               bdb->bi_txn_cp_task = NULL;
00690               ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
00691               if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) )
00692                      ldap_pvt_runqueue_stoptask( &slapd_rq, re );
00693               ldap_pvt_runqueue_remove( &slapd_rq, re );
00694               ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
00695        }
00696 
00697        /* monitor handling */
00698        (void)bdb_monitor_db_destroy( be );
00699 
00700        if( bdb->bi_dbenv_home ) ch_free( bdb->bi_dbenv_home );
00701        if( bdb->bi_db_config_path ) ch_free( bdb->bi_db_config_path );
00702 
00703        bdb_attr_index_destroy( bdb );
00704 
00705        ldap_pvt_thread_rdwr_destroy ( &bdb->bi_cache.c_rwlock );
00706        ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.c_lru_mutex );
00707        ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.c_count_mutex );
00708        ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.c_eifree_mutex );
00709        ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.c_dntree.bei_kids_mutex );
00710 #ifdef BDB_HIER
00711        ldap_pvt_thread_mutex_destroy( &bdb->bi_modrdns_mutex );
00712 #endif
00713        ldap_pvt_thread_mutex_destroy( &bdb->bi_lastid_mutex );
00714        ldap_pvt_thread_mutex_destroy( &bdb->bi_database_mutex );
00715        ldap_pvt_thread_rdwr_destroy( &bdb->bi_idl_tree_rwlock );
00716        ldap_pvt_thread_mutex_destroy( &bdb->bi_idl_tree_lrulock );
00717 
00718        ch_free( bdb );
00719        be->be_private = NULL;
00720 
00721        return 0;
00722 }
00723 
00724 int
00725 bdb_back_initialize(
00726        BackendInfo   *bi )
00727 {
00728        int rc;
00729 
00730        static char *controls[] = {
00731               LDAP_CONTROL_ASSERT,
00732               LDAP_CONTROL_MANAGEDSAIT,
00733               LDAP_CONTROL_NOOP,
00734               LDAP_CONTROL_PAGEDRESULTS,
00735               LDAP_CONTROL_PRE_READ,
00736               LDAP_CONTROL_POST_READ,
00737               LDAP_CONTROL_SUBENTRIES,
00738               LDAP_CONTROL_X_PERMISSIVE_MODIFY,
00739 #ifdef LDAP_X_TXN
00740               LDAP_CONTROL_X_TXN_SPEC,
00741 #endif
00742               NULL
00743        };
00744 
00745        /* initialize the underlying database system */
00746        Debug( LDAP_DEBUG_TRACE,
00747               LDAP_XSTRING(bdb_back_initialize) ": initialize " 
00748               BDB_UCTYPE " backend\n", 0, 0, 0 );
00749 
00750        bi->bi_flags |=
00751               SLAP_BFLAG_INCREMENT |
00752               SLAP_BFLAG_SUBENTRIES |
00753               SLAP_BFLAG_ALIASES |
00754               SLAP_BFLAG_REFERRALS;
00755 
00756        bi->bi_controls = controls;
00757 
00758        {      /* version check */
00759               int major, minor, patch, ver;
00760               char *version = db_version( &major, &minor, &patch );
00761 #ifdef HAVE_EBCDIC
00762               char v2[1024];
00763 
00764               /* All our stdio does an ASCII to EBCDIC conversion on
00765                * the output. Strings from the BDB library are already
00766                * in EBCDIC; we have to go back and forth...
00767                */
00768               strcpy( v2, version );
00769               __etoa( v2 );
00770               version = v2;
00771 #endif
00772 
00773               ver = (major << 24) | (minor << 16) | patch;
00774               if( ver != DB_VERSION_FULL ) {
00775                      /* fail if a versions don't match */
00776                      Debug( LDAP_DEBUG_ANY,
00777                             LDAP_XSTRING(bdb_back_initialize) ": "
00778                             "BDB library version mismatch:"
00779                             " expected " DB_VERSION_STRING ","
00780                             " got %s\n", version, 0, 0 );
00781                      return -1;
00782               }
00783 
00784               Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_back_initialize)
00785                      ": %s\n", version, 0, 0 );
00786        }
00787 
00788        db_env_set_func_free( ber_memfree );
00789        db_env_set_func_malloc( (db_malloc *)ber_memalloc );
00790        db_env_set_func_realloc( (db_realloc *)ber_memrealloc );
00791 #if !defined(NO_THREAD) && DB_VERSION_FULL <= 0x04070000
00792        /* This is a no-op on a NO_THREAD build. Leave the default
00793         * alone so that BDB will sleep on interprocess conflicts.
00794         * Don't bother on BDB 4.7...
00795         */
00796        db_env_set_func_yield( ldap_pvt_thread_yield );
00797 #endif
00798 
00799        bi->bi_open = 0;
00800        bi->bi_close = 0;
00801        bi->bi_config = 0;
00802        bi->bi_destroy = 0;
00803 
00804        bi->bi_db_init = bdb_db_init;
00805        bi->bi_db_config = config_generic_wrapper;
00806        bi->bi_db_open = bdb_db_open;
00807        bi->bi_db_close = bdb_db_close;
00808        bi->bi_db_destroy = bdb_db_destroy;
00809 
00810        bi->bi_op_add = bdb_add;
00811        bi->bi_op_bind = bdb_bind;
00812        bi->bi_op_compare = bdb_compare;
00813        bi->bi_op_delete = bdb_delete;
00814        bi->bi_op_modify = bdb_modify;
00815        bi->bi_op_modrdn = bdb_modrdn;
00816        bi->bi_op_search = bdb_search;
00817 
00818        bi->bi_op_unbind = 0;
00819 
00820        bi->bi_extended = bdb_extended;
00821 
00822        bi->bi_chk_referrals = bdb_referrals;
00823        bi->bi_operational = bdb_operational;
00824        bi->bi_has_subordinates = bdb_hasSubordinates;
00825        bi->bi_entry_release_rw = bdb_entry_release;
00826        bi->bi_entry_get_rw = bdb_entry_get;
00827 
00828        /*
00829         * hooks for slap tools
00830         */
00831        bi->bi_tool_entry_open = bdb_tool_entry_open;
00832        bi->bi_tool_entry_close = bdb_tool_entry_close;
00833        bi->bi_tool_entry_first = backend_tool_entry_first;
00834        bi->bi_tool_entry_first_x = bdb_tool_entry_first_x;
00835        bi->bi_tool_entry_next = bdb_tool_entry_next;
00836        bi->bi_tool_entry_get = bdb_tool_entry_get;
00837        bi->bi_tool_entry_put = bdb_tool_entry_put;
00838        bi->bi_tool_entry_reindex = bdb_tool_entry_reindex;
00839        bi->bi_tool_sync = 0;
00840        bi->bi_tool_dn2id_get = bdb_tool_dn2id_get;
00841        bi->bi_tool_entry_modify = bdb_tool_entry_modify;
00842 
00843        bi->bi_connection_init = 0;
00844        bi->bi_connection_destroy = 0;
00845 
00846        rc = bdb_back_init_cf( bi );
00847 
00848        return rc;
00849 }
00850 
00851 #if    (SLAPD_BDB == SLAPD_MOD_DYNAMIC && !defined(BDB_HIER)) || \
00852        (SLAPD_HDB == SLAPD_MOD_DYNAMIC && defined(BDB_HIER))
00853 
00854 /* conditionally define the init_module() function */
00855 #ifdef BDB_HIER
00856 SLAP_BACKEND_INIT_MODULE( hdb )
00857 #else /* !BDB_HIER */
00858 SLAP_BACKEND_INIT_MODULE( bdb )
00859 #endif /* !BDB_HIER */
00860 
00861 #endif /* SLAPD_[BH]DB == SLAPD_MOD_DYNAMIC */
00862