1/* init.c - initialize bdb backend */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 2000-2011 The OpenLDAP Foundation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted only as authorized by the OpenLDAP 10 * Public License. 11 * 12 * A copy of this license is available in the file LICENSE in the 13 * top-level directory of the distribution or, alternatively, at 14 * <http://www.OpenLDAP.org/license.html>. 15 */ 16 17#include "portable.h" 18 19#include <stdio.h> 20#include <ac/string.h> 21#include <ac/unistd.h> 22#include <ac/stdlib.h> 23#include <ac/errno.h> 24#include <sys/stat.h> 25#include "back-bdb.h" 26#include <lutil.h> 27#include <ldap_rq.h> 28#include "alock.h" 29#include "config.h" 30 31static const struct bdbi_database { 32 char *file; 33 struct berval name; 34 int type; 35 int flags; 36} bdbi_databases[] = { 37 { "id2entry" BDB_SUFFIX, BER_BVC("id2entry"), DB_BTREE, 0 }, 38 { "dn2id" BDB_SUFFIX, BER_BVC("dn2id"), DB_BTREE, 0 }, 39 { NULL, BER_BVNULL, 0, 0 } 40}; 41 42typedef void * db_malloc(size_t); 43typedef void * db_realloc(void *, size_t); 44 45#define bdb_db_init BDB_SYMBOL(db_init) 46#define bdb_db_open BDB_SYMBOL(db_open) 47#define bdb_db_close BDB_SYMBOL(db_close) 48 49#if defined(__APPLE__) 50#include <fcntl.h> 51/* 52 * A custom sync() function for BDB. This one ensures that the data is 53 * written out faster than normal ldapadds (skips f_fullfsync) during slapdd 54 */ 55 static int 56apple_bdb_db_fsync(int fd) 57{ 58 return (fsync(fd)); 59} 60#endif /* __APPLE__ */ 61 62static int 63bdb_db_init( BackendDB *be, ConfigReply *cr ) 64{ 65 struct bdb_info *bdb; 66 int rc; 67 68 Debug( LDAP_DEBUG_TRACE, 69 LDAP_XSTRING(bdb_db_init) ": Initializing " BDB_UCTYPE " database\n", 70 0, 0, 0 ); 71 72 /* allocate backend-database-specific stuff */ 73 bdb = (struct bdb_info *) ch_calloc( 1, sizeof(struct bdb_info) ); 74 75 /* DBEnv parameters */ 76 bdb->bi_dbenv_home = ch_strdup( SLAPD_DEFAULT_DB_DIR ); 77 bdb->bi_dbenv_xflags = DB_TIME_NOTGRANTED; 78 bdb->bi_dbenv_mode = SLAPD_DEFAULT_DB_MODE; 79 80 bdb->bi_cache.c_maxsize = DEFAULT_CACHE_SIZE; 81 bdb->bi_cache.c_minfree = 1; 82 83 bdb->bi_lock_detect = DB_LOCK_DEFAULT; 84 bdb->bi_search_stack_depth = DEFAULT_SEARCH_STACK_DEPTH; 85 bdb->bi_search_stack = NULL; 86 87 ldap_pvt_thread_mutex_init( &bdb->bi_database_mutex ); 88 ldap_pvt_thread_mutex_init( &bdb->bi_lastid_mutex ); 89#ifdef BDB_HIER 90 ldap_pvt_thread_mutex_init( &bdb->bi_modrdns_mutex ); 91#endif 92 ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_lru_mutex ); 93 ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_count_mutex ); 94 ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_eifree_mutex ); 95 ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_dntree.bei_kids_mutex ); 96 ldap_pvt_thread_rdwr_init ( &bdb->bi_cache.c_rwlock ); 97 ldap_pvt_thread_rdwr_init( &bdb->bi_idl_tree_rwlock ); 98 ldap_pvt_thread_mutex_init( &bdb->bi_idl_tree_lrulock ); 99 100 be->be_private = bdb; 101 be->be_cf_ocs = be->bd_info->bi_cf_ocs; 102 103#ifndef BDB_MULTIPLE_SUFFIXES 104 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX; 105#endif 106 107 rc = bdb_monitor_db_init( be ); 108 109 return rc; 110} 111 112static int 113bdb_db_close( BackendDB *be, ConfigReply *cr ); 114 115static int 116bdb_db_open( BackendDB *be, ConfigReply *cr ) 117{ 118 int rc, i; 119 struct bdb_info *bdb = (struct bdb_info *) be->be_private; 120 struct stat stat1, stat2; 121 u_int32_t flags; 122 char path[MAXPATHLEN]; 123 char *dbhome; 124 Entry *e = NULL; 125 int do_recover = 0, do_alock_recover = 0; 126 int alockt, quick = 0; 127 int do_retry = 1; 128 129 if ( be->be_suffix == NULL ) { 130 Debug( LDAP_DEBUG_ANY, 131 LDAP_XSTRING(bdb_db_open) ": need suffix.\n", 132 1, 0, 0 ); 133 return -1; 134 } 135 136 Debug( LDAP_DEBUG_ARGS, 137 LDAP_XSTRING(bdb_db_open) ": \"%s\"\n", 138 be->be_suffix[0].bv_val, 0, 0 ); 139 140 /* Check existence of dbenv_home. Any error means trouble */ 141 rc = stat( bdb->bi_dbenv_home, &stat1 ); 142 if( rc != 0 ) { 143 Debug( LDAP_DEBUG_ANY, 144 LDAP_XSTRING(bdb_db_open) ": database \"%s\": " 145 "cannot access database directory \"%s\" (%d).\n", 146 be->be_suffix[0].bv_val, bdb->bi_dbenv_home, errno ); 147 return -1; 148 } 149 150 /* Perform database use arbitration/recovery logic */ 151 alockt = (slapMode & SLAP_TOOL_READONLY) ? ALOCK_LOCKED : ALOCK_UNIQUE; 152 if ( slapMode & SLAP_TOOL_QUICK ) { 153 alockt |= ALOCK_NOSAVE; 154 quick = 1; 155 } 156 157 rc = alock_open( &bdb->bi_alock_info, 158 "slapd", 159 bdb->bi_dbenv_home, alockt ); 160 161 /* alockt is TRUE if the existing environment was created in Quick mode */ 162 alockt = (rc & ALOCK_NOSAVE) ? 1 : 0; 163 rc &= ~ALOCK_NOSAVE; 164 165 if( rc == ALOCK_RECOVER ) { 166 Debug( LDAP_DEBUG_ANY, 167 LDAP_XSTRING(bdb_db_open) ": database \"%s\": " 168 "unclean shutdown detected; attempting recovery.\n", 169 be->be_suffix[0].bv_val, 0, 0 ); 170 do_alock_recover = 1; 171 do_recover = DB_RECOVER; 172 } else if( rc == ALOCK_BUSY ) { 173 Debug( LDAP_DEBUG_ANY, 174 LDAP_XSTRING(bdb_db_open) ": database \"%s\": " 175 "database already in use.\n", 176 be->be_suffix[0].bv_val, 0, 0 ); 177 return -1; 178 } else if( rc != ALOCK_CLEAN ) { 179 Debug( LDAP_DEBUG_ANY, 180 LDAP_XSTRING(bdb_db_open) ": database \"%s\": " 181 "alock package is unstable.\n", 182 be->be_suffix[0].bv_val, 0, 0 ); 183 return -1; 184 } 185 if ( rc == ALOCK_CLEAN ) 186 be->be_flags |= SLAP_DBFLAG_CLEAN; 187 188 /* 189 * The DB_CONFIG file may have changed. If so, recover the 190 * database so that new settings are put into effect. Also 191 * note the possible absence of DB_CONFIG in the log. 192 */ 193 if( stat( bdb->bi_db_config_path, &stat1 ) == 0 ) { 194 if ( !do_recover ) { 195 char *ptr = lutil_strcopy(path, bdb->bi_dbenv_home); 196 *ptr++ = LDAP_DIRSEP[0]; 197 strcpy( ptr, "__db.001" ); 198 if( stat( path, &stat2 ) == 0 ) { 199 if( stat2.st_mtime < stat1.st_mtime ) { 200 Debug( LDAP_DEBUG_ANY, 201 LDAP_XSTRING(bdb_db_open) ": DB_CONFIG for suffix \"%s\" has changed.\n", 202 be->be_suffix[0].bv_val, 0, 0 ); 203 if ( quick ) { 204 Debug( LDAP_DEBUG_ANY, 205 "Cannot use Quick mode; perform manual recovery first.\n", 206 0, 0, 0 ); 207 slapMode ^= SLAP_TOOL_QUICK; 208 rc = -1; 209 goto fail; 210 } else { 211 Debug( LDAP_DEBUG_ANY, 212 "Performing database recovery to activate new settings.\n", 213 0, 0, 0 ); 214 } 215 do_recover = DB_RECOVER; 216 } 217 } 218 } 219 } 220 else { 221 Debug( LDAP_DEBUG_ANY, 222 LDAP_XSTRING(bdb_db_open) ": warning - no DB_CONFIG file found " 223 "in directory %s: (%d).\n" 224 "Expect poor performance for suffix \"%s\".\n", 225 bdb->bi_dbenv_home, errno, be->be_suffix[0].bv_val ); 226 } 227 228 /* Always let slapcat run, regardless of environment state. 229 * This can be used to cause a cache flush after an unclean 230 * shutdown. 231 */ 232 if ( do_recover && ( slapMode & SLAP_TOOL_READONLY )) { 233 Debug( LDAP_DEBUG_ANY, 234 LDAP_XSTRING(bdb_db_open) ": database \"%s\": " 235 "recovery skipped in read-only mode. " 236 "Run manual recovery if errors are encountered.\n", 237 be->be_suffix[0].bv_val, 0, 0 ); 238 do_recover = 0; 239 do_alock_recover = 0; 240 quick = alockt; 241 } 242 243 /* An existing environment in Quick mode has nothing to recover. */ 244 if ( alockt && do_recover ) { 245 Debug( LDAP_DEBUG_ANY, 246 LDAP_XSTRING(bdb_db_open) ": database \"%s\": " 247 "cannot recover, database must be reinitialized.\n", 248 be->be_suffix[0].bv_val, 0, 0 ); 249 rc = -1; 250 goto fail; 251 } 252 253 rc = db_env_create( &bdb->bi_dbenv, 0 ); 254 if( rc != 0 ) { 255 Debug( LDAP_DEBUG_ANY, 256 LDAP_XSTRING(bdb_db_open) ": database \"%s\": " 257 "db_env_create failed: %s (%d).\n", 258 be->be_suffix[0].bv_val, db_strerror(rc), rc ); 259 goto fail; 260 } 261 262#ifdef HAVE_EBCDIC 263 strcpy( path, bdb->bi_dbenv_home ); 264 __atoe( path ); 265 dbhome = path; 266#else 267 dbhome = bdb->bi_dbenv_home; 268#endif 269 270 /* If existing environment is clean but doesn't support 271 * currently requested modes, remove it. 272 */ 273 if ( !do_recover && ( alockt ^ quick )) { 274shm_retry: 275 rc = bdb->bi_dbenv->remove( bdb->bi_dbenv, dbhome, DB_FORCE ); 276 if ( rc ) { 277 Debug( LDAP_DEBUG_ANY, 278 LDAP_XSTRING(bdb_db_open) ": database \"%s\": " 279 "dbenv remove failed: %s (%d).\n", 280 be->be_suffix[0].bv_val, db_strerror(rc), rc ); 281 bdb->bi_dbenv = NULL; 282 goto fail; 283 } 284 rc = db_env_create( &bdb->bi_dbenv, 0 ); 285 if( rc != 0 ) { 286 Debug( LDAP_DEBUG_ANY, 287 LDAP_XSTRING(bdb_db_open) ": database \"%s\": " 288 "db_env_create failed: %s (%d).\n", 289 be->be_suffix[0].bv_val, db_strerror(rc), rc ); 290 goto fail; 291 } 292 } 293 294 bdb->bi_dbenv->set_errpfx( bdb->bi_dbenv, be->be_suffix[0].bv_val ); 295 bdb->bi_dbenv->set_errcall( bdb->bi_dbenv, bdb_errcall ); 296 297 bdb->bi_dbenv->set_lk_detect( bdb->bi_dbenv, bdb->bi_lock_detect ); 298 299#if defined(__APPLE__) 300 if(slapAddMode || bdb->bi_disable_fullfsync_mode ) { 301 Debug( LDAP_DEBUG_ANY, "slapd is running in import mode - only use if importing large data \n", 0, 0, 0 ); 302 (void) db_env_set_func_fsync(apple_bdb_db_fsync); 303 } 304#endif /* __APPLE__ */ 305 if ( !BER_BVISNULL( &bdb->bi_db_crypt_key )) { 306 rc = bdb->bi_dbenv->set_encrypt( bdb->bi_dbenv, bdb->bi_db_crypt_key.bv_val, 307 DB_ENCRYPT_AES ); 308 if ( rc ) { 309 Debug( LDAP_DEBUG_ANY, 310 LDAP_XSTRING(bdb_db_open) ": database \"%s\": " 311 "dbenv set_encrypt failed: %s (%d).\n", 312 be->be_suffix[0].bv_val, db_strerror(rc), rc ); 313 goto fail; 314 } 315 } 316 317 /* One long-lived TXN per thread, two TXNs per write op */ 318 bdb->bi_dbenv->set_tx_max( bdb->bi_dbenv, connection_pool_max * 3 ); 319 320 if( bdb->bi_dbenv_xflags != 0 ) { 321 rc = bdb->bi_dbenv->set_flags( bdb->bi_dbenv, 322 bdb->bi_dbenv_xflags, 1); 323 if( rc != 0 ) { 324 Debug( LDAP_DEBUG_ANY, 325 LDAP_XSTRING(bdb_db_open) ": database \"%s\": " 326 "dbenv_set_flags failed: %s (%d).\n", 327 be->be_suffix[0].bv_val, db_strerror(rc), rc ); 328 goto fail; 329 } 330 } 331 332#define BDB_TXN_FLAGS (DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN) 333 334 Debug( LDAP_DEBUG_TRACE, 335 LDAP_XSTRING(bdb_db_open) ": database \"%s\": " 336 "dbenv_open(%s).\n", 337 be->be_suffix[0].bv_val, bdb->bi_dbenv_home, 0); 338 339 flags = DB_INIT_MPOOL | DB_CREATE | DB_THREAD; 340 341 if ( !quick ) 342 flags |= BDB_TXN_FLAGS; 343 344 /* If a key was set, use shared memory for the BDB environment */ 345 if ( bdb->bi_shm_key ) { 346 bdb->bi_dbenv->set_shm_key( bdb->bi_dbenv, bdb->bi_shm_key ); 347 flags |= DB_SYSTEM_MEM; 348 } 349 rc = (bdb->bi_dbenv->open)( bdb->bi_dbenv, dbhome, 350 flags | do_recover, bdb->bi_dbenv_mode ); 351 352 if ( rc ) { 353 /* Regular open failed, probably a missing shm environment. 354 * Start over, do a recovery. 355 */ 356 if ( !do_recover && bdb->bi_shm_key && do_retry ) { 357 bdb->bi_dbenv->close( bdb->bi_dbenv, 0 ); 358 rc = db_env_create( &bdb->bi_dbenv, 0 ); 359 if( rc == 0 ) { 360 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) 361 ": database \"%s\": " 362 "shared memory env open failed, assuming stale env.\n", 363 be->be_suffix[0].bv_val, 0, 0 ); 364 do_retry = 0; 365 goto shm_retry; 366 } 367 } 368 Debug( LDAP_DEBUG_ANY, 369 LDAP_XSTRING(bdb_db_open) ": database \"%s\" cannot be %s, err %d. " 370 "Restore from backup!\n", 371 be->be_suffix[0].bv_val, do_recover ? "recovered" : "opened", rc ); 372 goto fail; 373 } 374 375 if ( do_alock_recover && alock_recover (&bdb->bi_alock_info) != 0 ) { 376 Debug( LDAP_DEBUG_ANY, 377 LDAP_XSTRING(bdb_db_open) ": database \"%s\": alock_recover failed\n", 378 be->be_suffix[0].bv_val, 0, 0 ); 379 rc = -1; 380 goto fail; 381 } 382 383#ifdef SLAP_ZONE_ALLOC 384 if ( bdb->bi_cache.c_maxsize ) { 385 bdb->bi_cache.c_zctx = slap_zn_mem_create( 386 SLAP_ZONE_INITSIZE, SLAP_ZONE_MAXSIZE, 387 SLAP_ZONE_DELTA, SLAP_ZONE_SIZE); 388 } 389#endif 390 391 /* dncache defaults to 0 == unlimited 392 * must be >= entrycache 393 */ 394 if ( bdb->bi_cache.c_eimax && bdb->bi_cache.c_eimax < bdb->bi_cache.c_maxsize ) { 395 bdb->bi_cache.c_eimax = bdb->bi_cache.c_maxsize; 396 } 397 398 if ( bdb->bi_idl_cache_max_size ) { 399 bdb->bi_idl_tree = NULL; 400 bdb->bi_idl_cache_size = 0; 401 } 402 403 flags = DB_THREAD | bdb->bi_db_opflags; 404 405#ifdef DB_AUTO_COMMIT 406 if ( !quick ) 407 flags |= DB_AUTO_COMMIT; 408#endif 409 410 bdb->bi_databases = (struct bdb_db_info **) ch_malloc( 411 BDB_INDICES * sizeof(struct bdb_db_info *) ); 412 413 /* open (and create) main database */ 414 for( i = 0; bdbi_databases[i].name.bv_val; i++ ) { 415 struct bdb_db_info *db; 416 417 db = (struct bdb_db_info *) ch_calloc(1, sizeof(struct bdb_db_info)); 418 419 rc = db_create( &db->bdi_db, bdb->bi_dbenv, 0 ); 420 if( rc != 0 ) { 421 snprintf(cr->msg, sizeof(cr->msg), 422 "database \"%s\": db_create(%s) failed: %s (%d).", 423 be->be_suffix[0].bv_val, 424 bdb->bi_dbenv_home, db_strerror(rc), rc ); 425 Debug( LDAP_DEBUG_ANY, 426 LDAP_XSTRING(bdb_db_open) ": %s\n", 427 cr->msg, 0, 0 ); 428 goto fail; 429 } 430 431 if( !BER_BVISNULL( &bdb->bi_db_crypt_key )) { 432 rc = db->bdi_db->set_flags( db->bdi_db, DB_ENCRYPT ); 433 if ( rc ) { 434 snprintf(cr->msg, sizeof(cr->msg), 435 "database \"%s\": db set_flags(DB_ENCRYPT)(%s) failed: %s (%d).", 436 be->be_suffix[0].bv_val, 437 bdb->bi_dbenv_home, db_strerror(rc), rc ); 438 Debug( LDAP_DEBUG_ANY, 439 LDAP_XSTRING(bdb_db_open) ": %s\n", 440 cr->msg, 0, 0 ); 441 goto fail; 442 } 443 } 444 445 if( bdb->bi_flags & BDB_CHKSUM ) { 446 rc = db->bdi_db->set_flags( db->bdi_db, DB_CHKSUM ); 447 if ( rc ) { 448 snprintf(cr->msg, sizeof(cr->msg), 449 "database \"%s\": db set_flags(DB_CHKSUM)(%s) failed: %s (%d).", 450 be->be_suffix[0].bv_val, 451 bdb->bi_dbenv_home, db_strerror(rc), rc ); 452 Debug( LDAP_DEBUG_ANY, 453 LDAP_XSTRING(bdb_db_open) ": %s\n", 454 cr->msg, 0, 0 ); 455 goto fail; 456 } 457 } 458 459 rc = bdb_db_findsize( bdb, (struct berval *)&bdbi_databases[i].name ); 460 461 if( i == BDB_ID2ENTRY ) { 462 if ( !rc ) rc = BDB_ID2ENTRY_PAGESIZE; 463 rc = db->bdi_db->set_pagesize( db->bdi_db, rc ); 464 465 if ( slapMode & SLAP_TOOL_MODE ) 466 db->bdi_db->mpf->set_priority( db->bdi_db->mpf, 467 DB_PRIORITY_VERY_LOW ); 468 469 if ( slapMode & SLAP_TOOL_READMAIN ) { 470 flags |= DB_RDONLY; 471 } else { 472 flags |= DB_CREATE; 473 } 474 } else { 475 /* Use FS default size if not configured */ 476 if ( rc ) 477 rc = db->bdi_db->set_pagesize( db->bdi_db, rc ); 478 479 rc = db->bdi_db->set_flags( db->bdi_db, 480 DB_DUP | DB_DUPSORT ); 481#ifndef BDB_HIER 482 if ( slapMode & SLAP_TOOL_READONLY ) { 483 flags |= DB_RDONLY; 484 } else { 485 flags |= DB_CREATE; 486 } 487#else 488 rc = db->bdi_db->set_dup_compare( db->bdi_db, 489 bdb_dup_compare ); 490 if ( slapMode & (SLAP_TOOL_READONLY|SLAP_TOOL_READMAIN) ) { 491 flags |= DB_RDONLY; 492 } else { 493 flags |= DB_CREATE; 494 } 495#endif 496 } 497 498#ifdef HAVE_EBCDIC 499 strcpy( path, bdbi_databases[i].file ); 500 __atoe( path ); 501 rc = DB_OPEN( db->bdi_db, 502 path, 503 /* bdbi_databases[i].name, */ NULL, 504 bdbi_databases[i].type, 505 bdbi_databases[i].flags | flags, 506 bdb->bi_dbenv_mode ); 507#else 508 rc = DB_OPEN( db->bdi_db, 509 bdbi_databases[i].file, 510 /* bdbi_databases[i].name, */ NULL, 511 bdbi_databases[i].type, 512 bdbi_databases[i].flags | flags, 513 bdb->bi_dbenv_mode ); 514#endif 515 516 if ( rc != 0 ) { 517 snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": " 518 "db_open(%s/%s) failed: %s (%d).", 519 be->be_suffix[0].bv_val, 520 bdb->bi_dbenv_home, bdbi_databases[i].file, 521 db_strerror(rc), rc ); 522 Debug( LDAP_DEBUG_ANY, 523 LDAP_XSTRING(bdb_db_open) ": %s\n", 524 cr->msg, 0, 0 ); 525 db->bdi_db->close( db->bdi_db, 0 ); 526 goto fail; 527 } 528 529 flags &= ~(DB_CREATE | DB_RDONLY); 530 db->bdi_name = bdbi_databases[i].name; 531 bdb->bi_databases[i] = db; 532 } 533 534 bdb->bi_databases[i] = NULL; 535 bdb->bi_ndatabases = i; 536 537 /* get nextid */ 538 rc = bdb_last_id( be, NULL ); 539 if( rc != 0 ) { 540 snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": " 541 "last_id(%s) failed: %s (%d).", 542 be->be_suffix[0].bv_val, bdb->bi_dbenv_home, 543 db_strerror(rc), rc ); 544 Debug( LDAP_DEBUG_ANY, 545 LDAP_XSTRING(bdb_db_open) ": %s\n", 546 cr->msg, 0, 0 ); 547 goto fail; 548 } 549 550 if ( !quick ) { 551 TXN_BEGIN(bdb->bi_dbenv, NULL, &bdb->bi_cache.c_txn, DB_READ_COMMITTED | DB_TXN_NOWAIT); 552 } 553 554 entry_prealloc( bdb->bi_cache.c_maxsize ); 555 attr_prealloc( bdb->bi_cache.c_maxsize * 20 ); 556 557 /* setup for empty-DN contexts */ 558 if ( BER_BVISEMPTY( &be->be_nsuffix[0] )) { 559 rc = bdb_id2entry( be, NULL, 0, &e ); 560 } 561 if ( !e ) { 562 struct berval gluebv = BER_BVC("glue"); 563 Operation op = {0}; 564 Opheader ohdr = {0}; 565 e = entry_alloc(); 566 e->e_id = 0; 567 ber_dupbv( &e->e_name, (struct berval *)&slap_empty_bv ); 568 ber_dupbv( &e->e_nname, (struct berval *)&slap_empty_bv ); 569 attr_merge_one( e, slap_schema.si_ad_objectClass, 570 &gluebv, NULL ); 571 attr_merge_one( e, slap_schema.si_ad_structuralObjectClass, 572 &gluebv, NULL ); 573 op.o_hdr = &ohdr; 574 op.o_bd = be; 575 op.ora_e = e; 576 op.o_dn = be->be_rootdn; 577 op.o_ndn = be->be_rootndn; 578 slap_add_opattrs( &op, NULL, NULL, 0, 0 ); 579 } 580 e->e_ocflags = SLAP_OC_GLUE|SLAP_OC__END; 581 e->e_private = &bdb->bi_cache.c_dntree; 582 bdb->bi_cache.c_dntree.bei_e = e; 583 584 /* monitor setup */ 585 rc = bdb_monitor_db_open( be ); 586 if ( rc != 0 ) { 587 goto fail; 588 } 589 590 bdb->bi_flags |= BDB_IS_OPEN; 591 592 return 0; 593 594fail: 595 bdb_db_close( be, NULL ); 596 return rc; 597} 598 599static int 600bdb_db_close( BackendDB *be, ConfigReply *cr ) 601{ 602 int rc; 603 struct bdb_info *bdb = (struct bdb_info *) be->be_private; 604 struct bdb_db_info *db; 605 bdb_idl_cache_entry_t *entry, *next_entry; 606 607 /* monitor handling */ 608 (void)bdb_monitor_db_close( be ); 609 610 { 611 Entry *e = bdb->bi_cache.c_dntree.bei_e; 612 if ( e ) { 613 bdb->bi_cache.c_dntree.bei_e = NULL; 614 e->e_private = NULL; 615 bdb_entry_return( e ); 616 } 617 } 618 619 bdb->bi_flags &= ~BDB_IS_OPEN; 620 621 ber_bvarray_free( bdb->bi_db_config ); 622 bdb->bi_db_config = NULL; 623 624 if( bdb->bi_dbenv ) { 625 /* Free cache locker if we enabled locking. 626 * TXNs must all be closed before DBs... 627 */ 628 if ( !( slapMode & SLAP_TOOL_QUICK ) && bdb->bi_cache.c_txn ) { 629 TXN_ABORT( bdb->bi_cache.c_txn ); 630 bdb->bi_cache.c_txn = NULL; 631 } 632 bdb_reader_flush( bdb->bi_dbenv ); 633 } 634 635 while( bdb->bi_databases && bdb->bi_ndatabases-- ) { 636 db = bdb->bi_databases[bdb->bi_ndatabases]; 637 rc = db->bdi_db->close( db->bdi_db, 0 ); 638 /* Lower numbered names are not strdup'd */ 639 if( bdb->bi_ndatabases >= BDB_NDB ) 640 free( db->bdi_name.bv_val ); 641 free( db ); 642 } 643 free( bdb->bi_databases ); 644 bdb->bi_databases = NULL; 645 646 bdb_cache_release_all (&bdb->bi_cache); 647 648 if ( bdb->bi_idl_cache_size ) { 649 avl_free( bdb->bi_idl_tree, NULL ); 650 bdb->bi_idl_tree = NULL; 651 entry = bdb->bi_idl_lru_head; 652 do { 653 next_entry = entry->idl_lru_next; 654 if ( entry->idl ) 655 free( entry->idl ); 656 free( entry->kstr.bv_val ); 657 free( entry ); 658 entry = next_entry; 659 } while ( entry != bdb->bi_idl_lru_head ); 660 bdb->bi_idl_lru_head = bdb->bi_idl_lru_tail = NULL; 661 } 662 663 /* close db environment */ 664 if( bdb->bi_dbenv ) { 665 /* force a checkpoint, but not if we were ReadOnly, 666 * and not in Quick mode since there are no transactions there. 667 */ 668 if ( !( slapMode & ( SLAP_TOOL_QUICK|SLAP_TOOL_READONLY ))) { 669 rc = TXN_CHECKPOINT( bdb->bi_dbenv, 0, 0, DB_FORCE ); 670 if( rc != 0 ) { 671 Debug( LDAP_DEBUG_ANY, 672 "bdb_db_close: database \"%s\": " 673 "txn_checkpoint failed: %s (%d).\n", 674 be->be_suffix[0].bv_val, db_strerror(rc), rc ); 675 } 676 } 677 678 rc = bdb->bi_dbenv->close( bdb->bi_dbenv, 0 ); 679 bdb->bi_dbenv = NULL; 680 if( rc != 0 ) { 681 Debug( LDAP_DEBUG_ANY, 682 "bdb_db_close: database \"%s\": " 683 "close failed: %s (%d)\n", 684 be->be_suffix[0].bv_val, db_strerror(rc), rc ); 685 return rc; 686 } 687 } 688 689 rc = alock_close( &bdb->bi_alock_info, slapMode & SLAP_TOOL_QUICK ); 690 if( rc != 0 ) { 691 Debug( LDAP_DEBUG_ANY, 692 "bdb_db_close: database \"%s\": alock_close failed\n", 693 be->be_suffix[0].bv_val, 0, 0 ); 694 return -1; 695 } 696 697 return 0; 698} 699 700static int 701bdb_db_destroy( BackendDB *be, ConfigReply *cr ) 702{ 703 struct bdb_info *bdb = (struct bdb_info *) be->be_private; 704 705 /* stop and remove checkpoint task */ 706 if ( bdb->bi_txn_cp_task ) { 707 struct re_s *re = bdb->bi_txn_cp_task; 708 bdb->bi_txn_cp_task = NULL; 709 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 710 if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) ) 711 ldap_pvt_runqueue_stoptask( &slapd_rq, re ); 712 ldap_pvt_runqueue_remove( &slapd_rq, re ); 713 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 714 } 715 716 /* monitor handling */ 717 (void)bdb_monitor_db_destroy( be ); 718 719 if( bdb->bi_dbenv_home ) ch_free( bdb->bi_dbenv_home ); 720 if( bdb->bi_db_config_path ) ch_free( bdb->bi_db_config_path ); 721 722 bdb_attr_index_destroy( bdb ); 723 724 ldap_pvt_thread_rdwr_destroy ( &bdb->bi_cache.c_rwlock ); 725 ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.c_lru_mutex ); 726 ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.c_count_mutex ); 727 ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.c_eifree_mutex ); 728 ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.c_dntree.bei_kids_mutex ); 729#ifdef BDB_HIER 730 ldap_pvt_thread_mutex_destroy( &bdb->bi_modrdns_mutex ); 731#endif 732 ldap_pvt_thread_mutex_destroy( &bdb->bi_lastid_mutex ); 733 ldap_pvt_thread_mutex_destroy( &bdb->bi_database_mutex ); 734 ldap_pvt_thread_rdwr_destroy( &bdb->bi_idl_tree_rwlock ); 735 ldap_pvt_thread_mutex_destroy( &bdb->bi_idl_tree_lrulock ); 736 737 ch_free( bdb ); 738 be->be_private = NULL; 739 740 return 0; 741} 742 743int 744bdb_back_initialize( 745 BackendInfo *bi ) 746{ 747 int rc; 748 749 static char *controls[] = { 750 LDAP_CONTROL_ASSERT, 751 LDAP_CONTROL_MANAGEDSAIT, 752 LDAP_CONTROL_NOOP, 753 LDAP_CONTROL_PAGEDRESULTS, 754 LDAP_CONTROL_PRE_READ, 755 LDAP_CONTROL_POST_READ, 756 LDAP_CONTROL_SUBENTRIES, 757 LDAP_CONTROL_X_PERMISSIVE_MODIFY, 758#ifdef LDAP_X_TXN 759 LDAP_CONTROL_X_TXN_SPEC, 760#endif 761 NULL 762 }; 763 764 /* initialize the underlying database system */ 765 Debug( LDAP_DEBUG_TRACE, 766 LDAP_XSTRING(bdb_back_initialize) ": initialize " 767 BDB_UCTYPE " backend\n", 0, 0, 0 ); 768 769 bi->bi_flags |= 770 SLAP_BFLAG_INCREMENT | 771 SLAP_BFLAG_SUBENTRIES | 772 SLAP_BFLAG_ALIASES | 773 SLAP_BFLAG_REFERRALS; 774 775 bi->bi_controls = controls; 776 777 { /* version check */ 778 int major, minor, patch, ver; 779 char *version = db_version( &major, &minor, &patch ); 780#ifdef HAVE_EBCDIC 781 char v2[1024]; 782 783 /* All our stdio does an ASCII to EBCDIC conversion on 784 * the output. Strings from the BDB library are already 785 * in EBCDIC; we have to go back and forth... 786 */ 787 strcpy( v2, version ); 788 __etoa( v2 ); 789 version = v2; 790#endif 791 792 ver = (major << 24) | (minor << 16) | patch; 793 if( ver != DB_VERSION_FULL ) { 794 /* fail if a versions don't match */ 795 Debug( LDAP_DEBUG_ANY, 796 LDAP_XSTRING(bdb_back_initialize) ": " 797 "BDB library version mismatch:" 798 " expected " DB_VERSION_STRING "," 799 " got %s\n", version, 0, 0 ); 800 return -1; 801 } 802 803 Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_back_initialize) 804 ": %s\n", version, 0, 0 ); 805 } 806 807 db_env_set_func_free( ber_memfree ); 808 db_env_set_func_malloc( (db_malloc *)ber_memalloc ); 809 db_env_set_func_realloc( (db_realloc *)ber_memrealloc ); 810#if !defined(NO_THREAD) && DB_VERSION_FULL <= 0x04070000 811 /* This is a no-op on a NO_THREAD build. Leave the default 812 * alone so that BDB will sleep on interprocess conflicts. 813 * Don't bother on BDB 4.7... 814 */ 815 db_env_set_func_yield( ldap_pvt_thread_yield ); 816#endif 817 818 bi->bi_open = 0; 819 bi->bi_close = 0; 820 bi->bi_config = 0; 821 bi->bi_destroy = 0; 822 823 bi->bi_db_init = bdb_db_init; 824 bi->bi_db_config = config_generic_wrapper; 825 bi->bi_db_open = bdb_db_open; 826 bi->bi_db_close = bdb_db_close; 827 bi->bi_db_destroy = bdb_db_destroy; 828 829 bi->bi_op_add = bdb_add; 830 bi->bi_op_bind = bdb_bind; 831 bi->bi_op_compare = bdb_compare; 832 bi->bi_op_delete = bdb_delete; 833 bi->bi_op_modify = bdb_modify; 834 bi->bi_op_modrdn = bdb_modrdn; 835 bi->bi_op_search = bdb_search; 836 837 bi->bi_op_unbind = 0; 838 839 bi->bi_extended = bdb_extended; 840 841 bi->bi_chk_referrals = bdb_referrals; 842 bi->bi_operational = bdb_operational; 843 bi->bi_has_subordinates = bdb_hasSubordinates; 844 bi->bi_entry_release_rw = bdb_entry_release; 845 bi->bi_entry_get_rw = bdb_entry_get; 846 847 /* 848 * hooks for slap tools 849 */ 850 bi->bi_tool_entry_open = bdb_tool_entry_open; 851 bi->bi_tool_entry_close = bdb_tool_entry_close; 852 bi->bi_tool_entry_first = backend_tool_entry_first; 853 bi->bi_tool_entry_first_x = bdb_tool_entry_first_x; 854 bi->bi_tool_entry_next = bdb_tool_entry_next; 855 bi->bi_tool_entry_get = bdb_tool_entry_get; 856 bi->bi_tool_entry_put = bdb_tool_entry_put; 857 bi->bi_tool_entry_reindex = bdb_tool_entry_reindex; 858 bi->bi_tool_sync = 0; 859 bi->bi_tool_dn2id_get = bdb_tool_dn2id_get; 860 bi->bi_tool_entry_modify = bdb_tool_entry_modify; 861 862 bi->bi_connection_init = 0; 863 bi->bi_connection_destroy = 0; 864 865 rc = bdb_back_init_cf( bi ); 866 867 return rc; 868} 869 870#if (SLAPD_BDB == SLAPD_MOD_DYNAMIC && !defined(BDB_HIER)) || \ 871 (SLAPD_HDB == SLAPD_MOD_DYNAMIC && defined(BDB_HIER)) 872 873/* conditionally define the init_module() function */ 874#ifdef BDB_HIER 875SLAP_BACKEND_INIT_MODULE( hdb ) 876#else /* !BDB_HIER */ 877SLAP_BACKEND_INIT_MODULE( bdb ) 878#endif /* !BDB_HIER */ 879 880#endif /* SLAPD_[BH]DB == SLAPD_MOD_DYNAMIC */ 881 882