init.c 21.7 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
2
/* init.c - initialize bdb backend */
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Notices    
Kurt Zeilenga committed
3
4
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Copyright 2000-2007 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Notices    
Kurt Zeilenga committed
6
7
8
9
10
11
12
13
14
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
15
16
17
18
19
20
 */

#include "portable.h"

#include <stdio.h>
#include <ac/string.h>
Howard Chu's avatar
Howard Chu committed
21
22
#include <ac/unistd.h>
#include <ac/stdlib.h>
Howard Chu's avatar
Howard Chu committed
23
24
#include <ac/errno.h>
#include <sys/stat.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
25
#include "back-bdb.h"
26
#include <lutil.h>
27
#include <ldap_rq.h>
28
#include "alock.h"
29
#include "config.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
30

31
static const struct bdbi_database {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
32
	char *file;
Howard Chu's avatar
Howard Chu committed
33
	struct berval name;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
34
35
	int type;
	int flags;
36
} bdbi_databases[] = {
Howard Chu's avatar
Howard Chu committed
37
38
39
	{ "id2entry" BDB_SUFFIX, BER_BVC("id2entry"), DB_BTREE, 0 },
	{ "dn2id" BDB_SUFFIX, BER_BVC("dn2id"), DB_BTREE, 0 },
	{ NULL, BER_BVNULL, 0, 0 }
Kurt Zeilenga's avatar
Kurt Zeilenga committed
40
41
};

42
43
44
typedef void * db_malloc(size_t);
typedef void * db_realloc(void *, size_t);

45
46
47
48
#define bdb_db_init	BDB_SYMBOL(db_init)
#define bdb_db_open BDB_SYMBOL(db_open)
#define bdb_db_close BDB_SYMBOL(db_close)

Kurt Zeilenga's avatar
Kurt Zeilenga committed
49
static int
50
bdb_db_init( BackendDB *be, ConfigReply *cr )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
51
{
52
	struct bdb_info	*bdb;
53
	int rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
54

Kurt Zeilenga's avatar
Kurt Zeilenga committed
55
56
57
	Debug( LDAP_DEBUG_TRACE,
		LDAP_XSTRING(bdb_db_init) ": Initializing " BDB_UCTYPE " database\n",
		0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
58

Kurt Zeilenga's avatar
Kurt Zeilenga committed
59
	/* allocate backend-database-specific stuff */
60
	bdb = (struct bdb_info *) ch_calloc( 1, sizeof(struct bdb_info) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
61
62

	/* DBEnv parameters */
63
	bdb->bi_dbenv_home = ch_strdup( SLAPD_DEFAULT_DB_DIR );
64
	bdb->bi_dbenv_xflags = 0;
65
	bdb->bi_dbenv_mode = SLAPD_DEFAULT_DB_MODE;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
66

67
	bdb->bi_cache.c_maxsize = DEFAULT_CACHE_SIZE;
Howard Chu's avatar
Howard Chu committed
68
	bdb->bi_cache.c_minfree = 1;
69

70
	bdb->bi_lock_detect = DB_LOCK_DEFAULT;
71
72
	bdb->bi_search_stack_depth = DEFAULT_SEARCH_STACK_DEPTH;
	bdb->bi_search_stack = NULL;
73

Howard Chu's avatar
Howard Chu committed
74
	ldap_pvt_thread_mutex_init( &bdb->bi_database_mutex );
75
	ldap_pvt_thread_mutex_init( &bdb->bi_lastid_mutex );
76
77
78
#ifdef BDB_HIER
	ldap_pvt_thread_mutex_init( &bdb->bi_modrdns_mutex );
#endif
79
	ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_lru_mutex );
80
81
	ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_count_mutex );
	ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_eifree_mutex );
Howard Chu's avatar
Howard Chu committed
82
	ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_dntree.bei_kids_mutex );
83
	ldap_pvt_thread_rdwr_init ( &bdb->bi_cache.c_rwlock );
84
85
	ldap_pvt_thread_rdwr_init( &bdb->bi_idl_tree_rwlock );
	ldap_pvt_thread_mutex_init( &bdb->bi_idl_tree_lrulock );
86

87
	be->be_private = bdb;
88
	be->be_cf_ocs = be->bd_info->bi_cf_ocs;
89

90
91
92
93
#ifndef BDB_MULTIPLE_SUFFIXES
	SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
#endif

Pierangelo Masarati's avatar
Pierangelo Masarati committed
94
	rc = bdb_monitor_db_init( be );
95
96

	return rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
97
98
}

99
static int
100
bdb_db_close( BackendDB *be, ConfigReply *cr );
101

Kurt Zeilenga's avatar
Kurt Zeilenga committed
102
static int
103
bdb_db_open( BackendDB *be, ConfigReply *cr )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
104
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
105
	int rc, i;
106
	struct bdb_info *bdb = (struct bdb_info *) be->be_private;
Howard Chu's avatar
Howard Chu committed
107
	struct stat stat1, stat2;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
108
	u_int32_t flags;
Howard Chu's avatar
Howard Chu committed
109
	char path[MAXPATHLEN];
Howard Chu's avatar
Howard Chu committed
110
	char *dbhome;
111
	Entry *e = NULL;
112
	int do_recover = 0, do_alock_recover = 0;
113
	int alockt, quick = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
114

115
116
	if ( be->be_suffix == NULL ) {
		Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
117
			LDAP_XSTRING(bdb_db_open) ": need suffix.\n",
118
			1, 0, 0 );
119
120
121
		return -1;
	}

122
	Debug( LDAP_DEBUG_ARGS,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
123
		LDAP_XSTRING(bdb_db_open) ": \"%s\"\n",
124
		be->be_suffix[0].bv_val, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
125

Howard Chu's avatar
Howard Chu committed
126
127
	/* Check existence of dbenv_home. Any error means trouble */
	rc = stat( bdb->bi_dbenv_home, &stat1 );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
128
	if( rc != 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
129
		Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
130
131
132
			LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
			"cannot access database directory \"%s\" (%d).\n",
			be->be_suffix[0].bv_val, bdb->bi_dbenv_home, errno );
133
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
134
	}
Howard Chu's avatar
Howard Chu committed
135

Howard Chu's avatar
Howard Chu committed
136
	/* Perform database use arbitration/recovery logic */
137
138
139
140
141
142
	alockt = (slapMode & SLAP_TOOL_READONLY) ? ALOCK_LOCKED : ALOCK_UNIQUE;
	if ( slapMode & SLAP_TOOL_QUICK ) {
		alockt |= ALOCK_NOSAVE;
		quick = 1;
	}

Howard Chu's avatar
Howard Chu committed
143
144
	rc = alock_open( &bdb->bi_alock_info, 
				"slapd", 
145
146
147
148
149
				bdb->bi_dbenv_home, alockt );

	/* alockt is TRUE if the existing environment was created in Quick mode */
	alockt = (rc & ALOCK_NOSAVE) ? 1 : 0;
	rc &= ~ALOCK_NOSAVE;
Howard Chu's avatar
Howard Chu committed
150

151
152
	if( rc == ALOCK_RECOVER ) {
		Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
153
154
155
			LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
			"unclean shutdown detected; attempting recovery.\n", 
			be->be_suffix[0].bv_val, 0, 0 );
Howard Chu's avatar
Howard Chu committed
156
		do_alock_recover = 1;
157
		do_recover = DB_RECOVER;
158
159
	} else if( rc == ALOCK_BUSY ) {
		Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
160
161
162
			LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
			"database already in use.\n", 
			be->be_suffix[0].bv_val, 0, 0 );
163
164
165
		return -1;
	} else if( rc != ALOCK_CLEAN ) {
		Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
166
167
168
			LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
			"alock package is unstable.\n", 
			be->be_suffix[0].bv_val, 0, 0 );
169
170
		return -1;
	}
Howard Chu's avatar
Howard Chu committed
171

Howard Chu's avatar
Howard Chu committed
172
173
174
175
176
177
	/*
	 * The DB_CONFIG file may have changed. If so, recover the
	 * database so that new settings are put into effect. Also
	 * note the possible absence of DB_CONFIG in the log.
	 */
	if( stat( bdb->bi_db_config_path, &stat1 ) == 0 ) {
Howard Chu's avatar
Howard Chu committed
178
179
180
181
182
		if ( !do_recover ) {
			char *ptr = lutil_strcopy(path, bdb->bi_dbenv_home);
			*ptr++ = LDAP_DIRSEP[0];
			strcpy( ptr, "__db.001" );
			if( stat( path, &stat2 ) == 0 ) {
183
				if( stat2.st_mtime < stat1.st_mtime ) {
Howard Chu's avatar
Howard Chu committed
184
					Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
185
186
187
188
189
190
191
192
193
194
195
196
197
198
						LDAP_XSTRING(bdb_db_open) ": DB_CONFIG for suffix \"%s\" has changed.\n",
							be->be_suffix[0].bv_val, 0, 0 );
					if ( quick ) {
						Debug( LDAP_DEBUG_ANY,
							"Cannot use Quick mode; perform manual recovery first.\n",
							0, 0, 0 );
						slapMode ^= SLAP_TOOL_QUICK;
						rc = -1;
						goto fail;
					} else {
						Debug( LDAP_DEBUG_ANY,
							"Performing database recovery to activate new settings.\n",
							0, 0, 0 );
					}
199
					do_recover = DB_RECOVER;
Howard Chu's avatar
Howard Chu committed
200
201
202
203
204
205
				}
			}
		}
	}
	else {
		Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
206
207
208
			LDAP_XSTRING(bdb_db_open) ": warning - no DB_CONFIG file found "
			"in directory %s: (%d).\n"
			"Expect poor performance for suffix \"%s\".\n",
Howard Chu's avatar
Howard Chu committed
209
210
211
			bdb->bi_dbenv_home, errno, be->be_suffix[0].bv_val );
	}

212
213
214
215
216
217
	/* Always let slapcat run, regardless of environment state.
	 * This can be used to cause a cache flush after an unclean
	 * shutdown.
	 */
	if ( do_recover && ( slapMode & SLAP_TOOL_READONLY )) {
		Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
218
219
			LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
			"recovery skipped in read-only mode. "
220
			"Run manual recovery if errors are encountered.\n",
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
221
			be->be_suffix[0].bv_val, 0, 0 );
222
223
224
225
226
227
228
		do_recover = 0;
		quick = alockt;
	}

	/* An existing environment in Quick mode has nothing to recover. */
	if ( alockt && do_recover ) {
		Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
229
230
231
			LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
			"cannot recover, database must be reinitialized.\n", 
			be->be_suffix[0].bv_val, 0, 0 );
232
233
234
235
		rc = -1;
		goto fail;
	}

Howard Chu's avatar
Howard Chu committed
236
237
238
	rc = db_env_create( &bdb->bi_dbenv, 0 );
	if( rc != 0 ) {
		Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
239
240
241
			LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
			"db_env_create failed: %s (%d).\n",
			be->be_suffix[0].bv_val, db_strerror(rc), rc );
242
		goto fail;
Howard Chu's avatar
Howard Chu committed
243
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
244

Howard Chu's avatar
Howard Chu committed
245
246
247
248
249
250
251
252
#ifdef HAVE_EBCDIC
	strcpy( path, bdb->bi_dbenv_home );
	__atoe( path );
	dbhome = path;
#else
	dbhome = bdb->bi_dbenv_home;
#endif

253
254
255
256
	/* If existing environment is clean but doesn't support
	 * currently requested modes, remove it.
	 */
	if ( !do_recover && ( alockt ^ quick )) {
257
shm_retry:
258
259
260
		rc = bdb->bi_dbenv->remove( bdb->bi_dbenv, dbhome, DB_FORCE );
		if ( rc ) {
			Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
261
262
263
				LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
				"dbenv remove failed: %s (%d).\n",
				be->be_suffix[0].bv_val, db_strerror(rc), rc );
264
265
266
267
268
269
			bdb->bi_dbenv = NULL;
			goto fail;
		}
		rc = db_env_create( &bdb->bi_dbenv, 0 );
		if( rc != 0 ) {
			Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
270
271
272
				LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
				"db_env_create failed: %s (%d).\n",
				be->be_suffix[0].bv_val, db_strerror(rc), rc );
273
274
275
276
			goto fail;
		}
	}

277
	bdb->bi_dbenv->set_errpfx( bdb->bi_dbenv, be->be_suffix[0].bv_val );
278
	bdb->bi_dbenv->set_errcall( bdb->bi_dbenv, bdb_errcall );
Howard Chu's avatar
Howard Chu committed
279

280
	bdb->bi_dbenv->set_lk_detect( bdb->bi_dbenv, bdb->bi_lock_detect );
281

Quanah Gibson-Mount's avatar
ITS5359    
Quanah Gibson-Mount committed
282
283
284
285
286
287
288
289
290
291
292
293
	if ( !BER_BVISNULL( &bdb->bi_db_crypt_key )) {
		rc = bdb->bi_dbenv->set_encrypt( bdb->bi_dbenv, bdb->bi_db_crypt_key.bv_val,
			DB_ENCRYPT_AES );
		if ( rc ) {
			Debug( LDAP_DEBUG_ANY,
				LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
				"dbenv set_encrypt failed: %s (%d).\n",
				be->be_suffix[0].bv_val, db_strerror(rc), rc );
			goto fail;
		}
	}

294
	/* One long-lived TXN per thread, two TXNs per write op */
295
	bdb->bi_dbenv->set_tx_max( bdb->bi_dbenv, connection_pool_max * 3 );
296

297
298
299
300
301
	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,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
302
303
304
				LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
				"dbenv_set_flags failed: %s (%d).\n",
				be->be_suffix[0].bv_val, db_strerror(rc), rc );
305
			goto fail;
306
307
308
		}
	}

Howard Chu's avatar
Howard Chu committed
309
#define	BDB_TXN_FLAGS	(DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
310

Howard Chu's avatar
Howard Chu committed
311
	Debug( LDAP_DEBUG_TRACE,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
312
313
314
		LDAP_XSTRING(bdb_db_open) ": database \"%s\": "
		"dbenv_open(%s).\n",
		be->be_suffix[0].bv_val, bdb->bi_dbenv_home, 0);
Howard Chu's avatar
Howard Chu committed
315

316
	flags = DB_INIT_MPOOL | DB_CREATE | DB_THREAD;
Howard Chu's avatar
Howard Chu committed
317

318
319
	if ( !quick )
		flags |= BDB_TXN_FLAGS;
Howard Chu's avatar
Howard Chu committed
320

321
322
323
324
	/* If a key was set, use shared memory for the BDB environment */
	if ( bdb->bi_shm_key ) {
		bdb->bi_dbenv->set_shm_key( bdb->bi_dbenv, bdb->bi_shm_key );
		flags |= DB_SYSTEM_MEM;
Howard Chu's avatar
Howard Chu committed
325
	}
326
	rc = (bdb->bi_dbenv->open)( bdb->bi_dbenv, dbhome,
327
			flags | do_recover, bdb->bi_dbenv_mode );
Howard Chu's avatar
Howard Chu committed
328

329
	if ( rc ) {
330
331
332
333
334
335
336
337
		/* Regular open failed, probably a missing shm environment.
		 * Start over, do a recovery.
		 */
		if ( !do_recover && bdb->bi_shm_key ) {
			bdb->bi_dbenv->close( bdb->bi_dbenv, 0 );
			rc = db_env_create( &bdb->bi_dbenv, 0 );
			if( rc == 0 ) {
				Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open)
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
338
339
340
					": database \"%s\": "
					"shared memory env open failed, assuming stale env.\n",
					be->be_suffix[0].bv_val, 0, 0 );
341
342
343
				goto shm_retry;
			}
		}
344
		Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
345
			LDAP_XSTRING(bdb_db_open) ": database \"%s\" cannot be %s, err %d. "
346
			"Restore from backup!\n",
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
347
			be->be_suffix[0].bv_val, do_recover ? "recovered" : "opened", rc );
348
		goto fail;
Howard Chu's avatar
Howard Chu committed
349
350
351
	}

	if ( do_alock_recover && alock_recover (&bdb->bi_alock_info) != 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
352
		Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
353
354
			LDAP_XSTRING(bdb_db_open) ": database \"%s\": alock_recover failed\n",
			be->be_suffix[0].bv_val, 0, 0 );
355
356
		rc = -1;
		goto fail;
Howard Chu's avatar
Howard Chu committed
357
358
359
360
361
	}

#ifdef SLAP_ZONE_ALLOC
	if ( bdb->bi_cache.c_maxsize ) {
		bdb->bi_cache.c_zctx = slap_zn_mem_create(
Kurt Zeilenga's avatar
Kurt Zeilenga committed
362
363
			SLAP_ZONE_INITSIZE, SLAP_ZONE_MAXSIZE,
			SLAP_ZONE_DELTA, SLAP_ZONE_SIZE);
Howard Chu's avatar
Howard Chu committed
364
365
366
	}
#endif

367
368
369
370
371
	/* Default dncache to 2x entrycache */
	if ( bdb->bi_cache.c_maxsize && !bdb->bi_cache.c_eimax ) {
		bdb->bi_cache.c_eimax = bdb->bi_cache.c_maxsize * 2;
	}

Howard Chu's avatar
Howard Chu committed
372
373
374
	if ( bdb->bi_idl_cache_max_size ) {
		bdb->bi_idl_tree = NULL;
		bdb->bi_idl_cache_size = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
375
376
	}

377
	flags = DB_THREAD | bdb->bi_db_opflags;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
378

379
#ifdef DB_AUTO_COMMIT
380
	if ( !quick )
381
382
383
		flags |= DB_AUTO_COMMIT;
#endif

384
385
386
	bdb->bi_databases = (struct bdb_db_info **) ch_malloc(
		BDB_INDICES * sizeof(struct bdb_db_info *) );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
387
	/* open (and create) main database */
Howard Chu's avatar
Howard Chu committed
388
	for( i = 0; bdbi_databases[i].name.bv_val; i++ ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
389
390
391
392
393
394
		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 ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
395
396
397
			snprintf(cr->msg, sizeof(cr->msg),
				"database \"%s\": db_create(%s) failed: %s (%d).",
				be->be_suffix[0].bv_val, 
Kurt Zeilenga's avatar
Kurt Zeilenga committed
398
				bdb->bi_dbenv_home, db_strerror(rc), rc );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
399
400
401
			Debug( LDAP_DEBUG_ANY,
				LDAP_XSTRING(bdb_db_open) ": %s\n",
				cr->msg, 0, 0 );
402
			goto fail;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
403
404
		}

Quanah Gibson-Mount's avatar
ITS5359    
Quanah Gibson-Mount committed
405
406
407
408
409
410
411
412
413
414
415
416
417
418
		if( !BER_BVISNULL( &bdb->bi_db_crypt_key )) {
			rc = db->bdi_db->set_flags( db->bdi_db, DB_ENCRYPT );
			if ( rc ) {
				snprintf(cr->msg, sizeof(cr->msg),
					"database \"%s\": db set_flags(DB_ENCRYPT)(%s) failed: %s (%d).",
					be->be_suffix[0].bv_val, 
					bdb->bi_dbenv_home, db_strerror(rc), rc );
				Debug( LDAP_DEBUG_ANY,
					LDAP_XSTRING(bdb_db_open) ": %s\n",
					cr->msg, 0, 0 );
				goto fail;
			}
		}

419
		if( i == BDB_ID2ENTRY ) {
420
421
422
423
			if ( slapMode & SLAP_TOOL_MODE )
				db->bdi_db->mpf->set_priority( db->bdi_db->mpf,
					DB_PRIORITY_VERY_LOW );

424
425
			rc = db->bdi_db->set_pagesize( db->bdi_db,
				BDB_ID2ENTRY_PAGESIZE );
426
427
428
429
430
			if ( slapMode & SLAP_TOOL_READMAIN ) {
				flags |= DB_RDONLY;
			} else {
				flags |= DB_CREATE;
			}
431
		} else {
432
			rc = db->bdi_db->set_flags( db->bdi_db, 
433
				DB_DUP | DB_DUPSORT );
Howard Chu's avatar
Howard Chu committed
434
#ifndef BDB_HIER
435
436
437
438
439
			if ( slapMode & SLAP_TOOL_READONLY ) {
				flags |= DB_RDONLY;
			} else {
				flags |= DB_CREATE;
			}
Howard Chu's avatar
Howard Chu committed
440
#else
Howard Chu's avatar
Howard Chu committed
441
442
			rc = db->bdi_db->set_dup_compare( db->bdi_db,
				bdb_dup_compare );
443
444
445
446
447
			if ( slapMode & (SLAP_TOOL_READONLY|SLAP_TOOL_READMAIN) ) {
				flags |= DB_RDONLY;
			} else {
				flags |= DB_CREATE;
			}
Howard Chu's avatar
Howard Chu committed
448
#endif
449
450
451
452
			rc = db->bdi_db->set_pagesize( db->bdi_db,
				BDB_PAGESIZE );
		}

Howard Chu's avatar
Howard Chu committed
453
454
455
#ifdef HAVE_EBCDIC
		strcpy( path, bdbi_databases[i].file );
		__atoe( path );
Howard Chu's avatar
Howard Chu committed
456
		rc = DB_OPEN( db->bdi_db,
Howard Chu's avatar
Howard Chu committed
457
458
459
			path,
		/*	bdbi_databases[i].name, */ NULL,
			bdbi_databases[i].type,
Howard Chu's avatar
Howard Chu committed
460
			bdbi_databases[i].flags | flags,
Howard Chu's avatar
Howard Chu committed
461
462
			bdb->bi_dbenv_mode );
#else
Howard Chu's avatar
Howard Chu committed
463
		rc = DB_OPEN( db->bdi_db,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
464
			bdbi_databases[i].file,
465
		/*	bdbi_databases[i].name, */ NULL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
466
			bdbi_databases[i].type,
Howard Chu's avatar
Howard Chu committed
467
			bdbi_databases[i].flags | flags,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
468
			bdb->bi_dbenv_mode );
Howard Chu's avatar
Howard Chu committed
469
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
470

471
		if ( rc != 0 ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
472
473
474
475
476
			snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
				"db_open(%s/%s) failed: %s (%d).", 
				be->be_suffix[0].bv_val, 
				bdb->bi_dbenv_home, bdbi_databases[i].file,
				db_strerror(rc), rc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
477
			Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
478
479
				LDAP_XSTRING(bdb_db_open) ": %s\n",
				cr->msg, 0, 0 );
480
481
			db->bdi_db->close( db->bdi_db, 0 );
			goto fail;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
482
		}
483

484
		flags &= ~(DB_CREATE | DB_RDONLY);
485
		db->bdi_name = bdbi_databases[i].name;
486
		bdb->bi_databases[i] = db;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
487
488
	}

489
490
491
	bdb->bi_databases[i] = NULL;
	bdb->bi_ndatabases = i;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
492
493
494
	/* get nextid */
	rc = bdb_last_id( be, NULL );
	if( rc != 0 ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
495
496
497
498
		snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
			"last_id(%s) failed: %s (%d).",
			be->be_suffix[0].bv_val, bdb->bi_dbenv_home,
			db_strerror(rc), rc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
499
		Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
500
501
			LDAP_XSTRING(bdb_db_open) ": %s\n",
			cr->msg, 0, 0 );
502
		goto fail;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
503
504
	}

505
	if ( !quick ) {
506
507
508
509
510
#if DB_VERSION_FULL >= 0x04060012
		u_int32_t lid;
		XLOCK_ID(bdb->bi_dbenv, &lid);
		__lock_getlocker(bdb->bi_dbenv->lk_handle, lid, 0, &bdb->bi_cache.c_locker);
#else
511
		XLOCK_ID(bdb->bi_dbenv, &bdb->bi_cache.c_locker);
512
#endif
513
514
	}

515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
	entry_prealloc( bdb->bi_cache.c_maxsize );
	attr_prealloc( bdb->bi_cache.c_maxsize * 20 );

	/* setup for empty-DN contexts */
	if ( BER_BVISEMPTY( &be->be_nsuffix[0] )) {
		rc = bdb_id2entry( be, NULL, 0, 0, &e );
	}
	if ( !e ) {
		e = entry_alloc();
		e->e_id = 0;
		ber_dupbv( &e->e_name, (struct berval *)&slap_empty_bv );
		ber_dupbv( &e->e_nname, (struct berval *)&slap_empty_bv );
	}
	e->e_ocflags = SLAP_OC_GLUE|SLAP_OC__END;
	e->e_private = &bdb->bi_cache.c_dntree;
	bdb->bi_cache.c_dntree.bei_e = e;

532
	/* monitor setup */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
533
	rc = bdb_monitor_db_open( be );
534
535
536
537
	if ( rc != 0 ) {
		goto fail;
	}

Howard Chu's avatar
Howard Chu committed
538
	bdb->bi_flags |= BDB_IS_OPEN;
539

Kurt Zeilenga's avatar
Kurt Zeilenga committed
540
	return 0;
541
542

fail:
543
	bdb_db_close( be, NULL );
544
	return rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
545
546
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
547
static int
548
bdb_db_close( BackendDB *be, ConfigReply *cr )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
549
550
{
	int rc;
551
	struct bdb_info *bdb = (struct bdb_info *) be->be_private;
Howard Chu's avatar
Howard Chu committed
552
	struct bdb_db_info *db;
553
	bdb_idl_cache_entry_t *entry, *next_entry;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
554

555
	/* monitor handling */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
556
	(void)bdb_monitor_db_close( be );
557

558
559
560
561
562
563
564
565
566
	{
		Entry *e = bdb->bi_cache.c_dntree.bei_e;
		if ( e ) {
			bdb->bi_cache.c_dntree.bei_e = NULL;
			e->e_private = NULL;
			bdb_entry_return( e );
		}
	}

Howard Chu's avatar
Howard Chu committed
567
	bdb->bi_flags &= ~BDB_IS_OPEN;
568
569

	ber_bvarray_free( bdb->bi_db_config );
570
	bdb->bi_db_config = NULL;
571

Howard Chu's avatar
Howard Chu committed
572
	while( bdb->bi_databases && bdb->bi_ndatabases-- ) {
Howard Chu's avatar
Howard Chu committed
573
574
		db = bdb->bi_databases[bdb->bi_ndatabases];
		rc = db->bdi_db->close( db->bdi_db, 0 );
575
576
		/* Lower numbered names are not strdup'd */
		if( bdb->bi_ndatabases >= BDB_NDB )
Howard Chu's avatar
Howard Chu committed
577
			free( db->bdi_name.bv_val );
Howard Chu's avatar
Howard Chu committed
578
		free( db );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
579
	}
Howard Chu's avatar
Howard Chu committed
580
	free( bdb->bi_databases );
581
582
	bdb->bi_databases = NULL;

583
584
	bdb_cache_release_all (&bdb->bi_cache);

Howard Chu's avatar
Howard Chu committed
585
	if ( bdb->bi_idl_cache_size ) {
586
		avl_free( bdb->bi_idl_tree, NULL );
587
		bdb->bi_idl_tree = NULL;
Howard Chu's avatar
Howard Chu committed
588
589
590
591
592
593
594
595
596
597
		entry = bdb->bi_idl_lru_head;
		do {
			next_entry = entry->idl_lru_next;
			if ( entry->idl )
				free( entry->idl );
			free( entry->kstr.bv_val );
			free( entry );
			entry = next_entry;
		} while ( entry != bdb->bi_idl_lru_head );
		bdb->bi_idl_lru_head = bdb->bi_idl_lru_tail = NULL;
598
599
	}

600
	/* close db environment */
601
	if( bdb->bi_dbenv ) {
602
		/* Free cache locker if we enabled locking */
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
603
		if ( !( slapMode & SLAP_TOOL_QUICK ) && bdb->bi_cache.c_locker ) {
604
605
606
#if DB_VERSION_FULL >= 0x04060012
			XLOCK_ID_FREE(bdb->bi_dbenv, bdb->bi_cache.c_locker->id);
#else
607
			XLOCK_ID_FREE(bdb->bi_dbenv, bdb->bi_cache.c_locker);
608
#endif
609
610
			bdb->bi_cache.c_locker = 0;
		}
611
612
613
#ifdef BDB_REUSE_LOCKERS
		bdb_locker_flush( bdb->bi_dbenv );
#endif
614
615
616
617
		/* force a checkpoint, but not if we were ReadOnly,
		 * and not in Quick mode since there are no transactions there.
		 */
		if ( !( slapMode & ( SLAP_TOOL_QUICK|SLAP_TOOL_READONLY ))) {
618
619
620
			rc = TXN_CHECKPOINT( bdb->bi_dbenv, 0, 0, DB_FORCE );
			if( rc != 0 ) {
				Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
621
622
623
					"bdb_db_close: database \"%s\": "
					"txn_checkpoint failed: %s (%d).\n",
					be->be_suffix[0].bv_val, db_strerror(rc), rc );
624
			}
625
626
		}

627
628
629
630
		rc = bdb->bi_dbenv->close( bdb->bi_dbenv, 0 );
		bdb->bi_dbenv = NULL;
		if( rc != 0 ) {
			Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
631
632
633
				"bdb_db_close: database \"%s\": "
				"close failed: %s (%d)\n",
				be->be_suffix[0].bv_val, db_strerror(rc), rc );
634
635
			return rc;
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
636
637
	}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
638
	rc = alock_close( &bdb->bi_alock_info, slapMode & SLAP_TOOL_QUICK );
639
640
	if( rc != 0 ) {
		Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
641
642
			"bdb_db_close: database \"%s\": alock_close failed\n",
			be->be_suffix[0].bv_val, 0, 0 );
643
		return -1;
644
645
	}

646
647
648
649
	return 0;
}

static int
650
bdb_db_destroy( BackendDB *be, ConfigReply *cr )
651
652
653
{
	struct bdb_info *bdb = (struct bdb_info *) be->be_private;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
654
	/* monitor handling */
655
	(void)bdb_monitor_db_destroy( be );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
656

Howard Chu's avatar
Howard Chu committed
657
	if( bdb->bi_dbenv_home ) ch_free( bdb->bi_dbenv_home );
658
	if( bdb->bi_db_config_path ) ch_free( bdb->bi_db_config_path );
Howard Chu's avatar
Howard Chu committed
659

660
	bdb_attr_index_destroy( bdb );
Howard Chu's avatar
Howard Chu committed
661

662
	ldap_pvt_thread_rdwr_destroy ( &bdb->bi_cache.c_rwlock );
663
	ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.c_lru_mutex );
664
665
	ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.c_count_mutex );
	ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.c_eifree_mutex );
Howard Chu's avatar
Howard Chu committed
666
	ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.c_dntree.bei_kids_mutex );
667
668
669
#ifdef BDB_HIER
	ldap_pvt_thread_mutex_destroy( &bdb->bi_modrdns_mutex );
#endif
670
	ldap_pvt_thread_mutex_destroy( &bdb->bi_lastid_mutex );
Howard Chu's avatar
Howard Chu committed
671
	ldap_pvt_thread_mutex_destroy( &bdb->bi_database_mutex );
672
673
	ldap_pvt_thread_rdwr_destroy( &bdb->bi_idl_tree_rwlock );
	ldap_pvt_thread_mutex_destroy( &bdb->bi_idl_tree_lrulock );
674

Howard Chu's avatar
Howard Chu committed
675
676
677
	ch_free( bdb );
	be->be_private = NULL;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
678
679
	return 0;
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
680
681

int
682
bdb_back_initialize(
683
	BackendInfo	*bi )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
684
{
685
686
	int rc;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
687
	static char *controls[] = {
688
		LDAP_CONTROL_ASSERT,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
689
690
		LDAP_CONTROL_MANAGEDSAIT,
		LDAP_CONTROL_NOOP,
691
		LDAP_CONTROL_PAGEDRESULTS,
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
692
693
		LDAP_CONTROL_PRE_READ,
		LDAP_CONTROL_POST_READ,
694
		LDAP_CONTROL_SUBENTRIES,
695
		LDAP_CONTROL_X_PERMISSIVE_MODIFY,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
696
697
698
#ifdef LDAP_X_TXN
		LDAP_CONTROL_X_TXN_SPEC,
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
699
700
701
702
		NULL
	};

	/* initialize the underlying database system */
703
704
705
	Debug( LDAP_DEBUG_TRACE,
		LDAP_XSTRING(bdb_back_initialize) ": initialize " 
		BDB_UCTYPE " backend\n", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
706

707
708
709
710
711
712
713
714
	bi->bi_flags |=
		SLAP_BFLAG_INCREMENT |
		SLAP_BFLAG_SUBENTRIES |
		SLAP_BFLAG_ALIASES |
		SLAP_BFLAG_REFERRALS;

	bi->bi_controls = controls;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
715
	{	/* version check */
716
		int major, minor, patch, ver;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
717
		char *version = db_version( &major, &minor, &patch );
Howard Chu's avatar
Howard Chu committed
718
719
720
721
722
723
724
725
726
727
728
#ifdef HAVE_EBCDIC
		char v2[1024];

		/* All our stdio does an ASCII to EBCDIC conversion on
		 * the output. Strings from the BDB library are already
		 * in EBCDIC; we have to go back and forth...
		 */
		strcpy( v2, version );
		__etoa( v2 );
		version = v2;
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
729

730
		ver = (major << 24) | (minor << 16) | patch;
731
732
733
		if( ver != DB_VERSION_FULL ) {
			/* fail if a versions don't match */
			Debug( LDAP_DEBUG_ANY,
734
				LDAP_XSTRING(bdb_back_initialize) ": "
Pierangelo Masarati's avatar
Pierangelo Masarati committed
735
				"BDB library version mismatch:"
736
737
				" expected " DB_VERSION_STRING ","
				" got %s\n", version, 0, 0 );
738
			return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
739
740
		}

741
		Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_back_initialize)
742
			": %s\n", version, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
743
744
	}

Howard Chu's avatar
Howard Chu committed
745
746
747
	db_env_set_func_free( ber_memfree );
	db_env_set_func_malloc( (db_malloc *)ber_memalloc );
	db_env_set_func_realloc( (db_realloc *)ber_memrealloc );
748
749
750
751
#ifndef NO_THREAD
	/* This is a no-op on a NO_THREAD build. Leave the default
	 * alone so that BDB will sleep on interprocess conflicts.
	 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
752
	db_env_set_func_yield( ldap_pvt_thread_yield );
753
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
754
755

	bi->bi_open = 0;
756
	bi->bi_close = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
757
	bi->bi_config = 0;
758
	bi->bi_destroy = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
759

Kurt Zeilenga's avatar
Kurt Zeilenga committed
760
	bi->bi_db_init = bdb_db_init;
761
	bi->bi_db_config = config_generic_wrapper;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
762
763
764
	bi->bi_db_open = bdb_db_open;
	bi->bi_db_close = bdb_db_close;
	bi->bi_db_destroy = bdb_db_destroy;
765

Kurt Zeilenga's avatar
Kurt Zeilenga committed
766
	bi->bi_op_add = bdb_add;
767
	bi->bi_op_bind = bdb_bind;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
768
769
	bi->bi_op_compare = bdb_compare;
	bi->bi_op_delete = bdb_delete;
770
771
	bi->bi_op_modify = bdb_modify;
	bi->bi_op_modrdn = bdb_modrdn;
772
773
	bi->bi_op_search = bdb_search;

Howard Chu's avatar
Howard Chu committed
774
	bi->bi_op_unbind = 0;
775

776
	bi->bi_extended = bdb_extended;
Howard Chu's avatar
Howard Chu committed
777

778
	bi->bi_chk_referrals = bdb_referrals;
779
	bi->bi_operational = bdb_operational;
780
	bi->bi_has_subordinates = bdb_hasSubordinates;
781
	bi->bi_entry_release_rw = bdb_entry_release;
782
	bi->bi_entry_get_rw = bdb_entry_get;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
783
784
785
786

	/*
	 * hooks for slap tools
	 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
787
788
789
790
791
792
	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;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
793
	bi->bi_tool_entry_reindex = bdb_tool_entry_reindex;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
794
	bi->bi_tool_sync = 0;
795
796
	bi->bi_tool_dn2id_get = bdb_tool_dn2id_get;
	bi->bi_tool_entry_modify = bdb_tool_entry_modify;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
797
798
799
800

	bi->bi_connection_init = 0;
	bi->bi_connection_destroy = 0;

801
	rc = bdb_back_init_cf( bi );
802
803

	return rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
804
}
805
806
807
808

#if	(SLAPD_BDB == SLAPD_MOD_DYNAMIC && !defined(BDB_HIER)) || \
	(SLAPD_HDB == SLAPD_MOD_DYNAMIC && defined(BDB_HIER))

Pierangelo Masarati's avatar
Pierangelo Masarati committed
809
/* conditionally define the init_module() function */
810
#ifdef BDB_HIER
Pierangelo Masarati's avatar
Pierangelo Masarati committed
811
812
813
814
SLAP_BACKEND_INIT_MODULE( hdb )
#else /* !BDB_HIER */
SLAP_BACKEND_INIT_MODULE( bdb )
#endif /* !BDB_HIER */
815

Pierangelo Masarati's avatar
Pierangelo Masarati committed
816
#endif /* SLAPD_[BH]DB == SLAPD_MOD_DYNAMIC */
817