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