init.c 19.9 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-2005 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>
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"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
29

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

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
44
static int
45
bdb_db_init( BackendDB *be )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
46
{
47
	struct bdb_info	*bdb;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
48

49
50
51
	Debug( LDAP_DEBUG_TRACE,
		LDAP_XSTRING(bdb_db_init) ": Initializing " BDB_UCTYPE " database\n",
		0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
52

Kurt Zeilenga's avatar
Kurt Zeilenga committed
53
	/* allocate backend-database-specific stuff */
54
	bdb = (struct bdb_info *) ch_calloc( 1, sizeof(struct bdb_info) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
55
56

	/* DBEnv parameters */
57
	bdb->bi_dbenv_home = ch_strdup( SLAPD_DEFAULT_DB_DIR );
58
	bdb->bi_dbenv_xflags = 0;
59
	bdb->bi_dbenv_mode = SLAPD_DEFAULT_DB_MODE;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
60

61
62
	bdb->bi_cache.c_maxsize = DEFAULT_CACHE_SIZE;

63
	bdb->bi_lock_detect = DB_LOCK_DEFAULT;
64
65
	bdb->bi_search_stack_depth = DEFAULT_SEARCH_STACK_DEPTH;
	bdb->bi_search_stack = NULL;
66

Howard Chu's avatar
Howard Chu committed
67
	ldap_pvt_thread_mutex_init( &bdb->bi_database_mutex );
68
	ldap_pvt_thread_mutex_init( &bdb->bi_lastid_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
69
70
71
#ifdef BDB_HIER
	ldap_pvt_thread_mutex_init( &bdb->bi_modrdns_mutex );
#endif
72
	ldap_pvt_thread_mutex_init( &bdb->bi_cache.lru_mutex );
Howard Chu's avatar
Howard Chu committed
73
	ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_dntree.bei_kids_mutex );
74
	ldap_pvt_thread_rdwr_init ( &bdb->bi_cache.c_rwlock );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
75
76
	ldap_pvt_thread_rdwr_init( &bdb->bi_idl_tree_rwlock );
	ldap_pvt_thread_mutex_init( &bdb->bi_idl_tree_lrulock );
77

78
	be->be_private = bdb;
79
	be->be_cf_ocs = be->bd_info->bi_cf_ocs;
80

Kurt Zeilenga's avatar
Kurt Zeilenga committed
81
82
83
	return 0;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
84
static int
Kurt Zeilenga's avatar
Kurt Zeilenga committed
85
bdb_db_open( BackendDB *be )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
86
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
87
	int rc, i;
88
	struct bdb_info *bdb = (struct bdb_info *) be->be_private;
89
	struct stat stat1, stat2;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
90
	u_int32_t flags;
Howard Chu's avatar
Howard Chu committed
91
	char path[MAXPATHLEN];
Kurt Zeilenga's avatar
Kurt Zeilenga committed
92
93
	char *dbhome;
	int do_recover = 0, do_alock_recover = 0, open_env = 1, got_env = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
94

Kurt Zeilenga's avatar
Kurt Zeilenga committed
95
96
97
98
99
100
101
	if ( be->be_suffix == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"bdb_db_open: need suffix\n",
			0, 0, 0 );
		return -1;
	}

102
103
	Debug( LDAP_DEBUG_ARGS,
		"bdb_db_open: %s\n",
104
		be->be_suffix[0].bv_val, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
105

106
107
#ifndef BDB_MULTIPLE_SUFFIXES
	if ( be->be_suffix[1].bv_val ) {
108
	Debug( LDAP_DEBUG_ANY,
109
110
111
112
		"bdb_db_open: only one suffix allowed\n", 0, 0, 0 );
		return -1;
	}
#endif
113
114
115
116
117
118
119
120
121

	/* Check existence of dbenv_home. Any error means trouble */
	rc = stat( bdb->bi_dbenv_home, &stat1 );
	if( rc !=0 ) {
		Debug( LDAP_DEBUG_ANY,
			"bdb_db_open: Cannot access database directory %s (%d)\n",
			bdb->bi_dbenv_home, errno, 0 );
			return -1;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
122

123
124
125
126
127
128
129
130
131
132
133
134
	/* Perform database use arbitration/recovery logic */
	rc = alock_open( &bdb->bi_alock_info, 
				"slapd", 
				bdb->bi_dbenv_home,
				slapMode & SLAP_TOOL_READONLY ?
				ALOCK_LOCKED : ALOCK_UNIQUE );

	if( rc == ALOCK_RECOVER ) {
		Debug( LDAP_DEBUG_ANY,
			"bdb_db_open: unclean shutdown detected;"
			" attempting recovery.\n", 
			0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
135
136
		do_alock_recover = 1;
		do_recover = 1;
137
138
139
140
141
142
143
144
145
146
147
	} else if( rc == ALOCK_BUSY ) {
		Debug( LDAP_DEBUG_ANY,
			"bdb_db_open: database already in use\n", 
			0, 0, 0 );
		return -1;
	} else if( rc != ALOCK_CLEAN ) {
		Debug( LDAP_DEBUG_ANY,
			"bdb_db_open: alock package is unstable\n", 
			0, 0, 0 );
		return -1;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
148

149
150
151
152
153
154
	/*
	 * 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 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
155
156
157
158
159
160
		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 ) {
				if( stat2.st_mtime <= stat1.st_mtime ) {
161
					Debug( LDAP_DEBUG_ANY,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
162
163
164
165
						"bdb_db_open: DB_CONFIG for suffix %s has changed.\n"
						"Performing database recovery to activate new settings.\n",
						be->be_suffix[0].bv_val, 0, 0 );
					do_recover = 1;
166
167
168
169
170
171
172
173
174
175
176
				}
			}
		}
	}
	else {
		Debug( LDAP_DEBUG_ANY,
			"bdb_db_open: Warning - No DB_CONFIG file found "
			"in directory %s: (%d)\n"
			"Expect poor performance for suffix %s.\n",
			bdb->bi_dbenv_home, errno, be->be_suffix[0].bv_val );
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
177

178
	rc = db_env_create( &bdb->bi_dbenv, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
179
180
	if( rc != 0 ) {
		Debug( LDAP_DEBUG_ANY,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
181
			"bdb_db_open: db_env_create failed: %s (%d)\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
182
183
184
185
			db_strerror(rc), rc, 0 );
		return rc;
	}

186
	bdb->bi_dbenv->set_errpfx( bdb->bi_dbenv, be->be_suffix[0].bv_val );
187
	bdb->bi_dbenv->set_errcall( bdb->bi_dbenv, bdb_errcall );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
188

189
	bdb->bi_dbenv->set_lk_detect( bdb->bi_dbenv, bdb->bi_lock_detect );
190

191
	/* One long-lived TXN per thread, two TXNs per write op */
192
	bdb->bi_dbenv->set_tx_max( bdb->bi_dbenv, connection_pool_max * 3 );
193

194
195
196
197
198
199
200
201
202
203
204
	if( bdb->bi_dbenv_xflags != 0 ) {
		rc = bdb->bi_dbenv->set_flags( bdb->bi_dbenv,
			bdb->bi_dbenv_xflags, 1);
		if( rc != 0 ) {
			Debug( LDAP_DEBUG_ANY,
				"bdb_db_open: dbenv_set_flags failed: %s (%d)\n",
				db_strerror(rc), rc, 0 );
			return rc;
		}
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
205
#define	BDB_TXN_FLAGS	(DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
206

Howard Chu's avatar
Howard Chu committed
207
208
209
#ifdef HAVE_EBCDIC
	strcpy( path, bdb->bi_dbenv_home );
	__atoe( path );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
210
	dbhome = path;
Howard Chu's avatar
Howard Chu committed
211
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
212
	dbhome = bdb->bi_dbenv_home;
Howard Chu's avatar
Howard Chu committed
213
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280

	Debug( LDAP_DEBUG_TRACE,
		"bdb_db_open: dbenv_open(%s)\n",
		bdb->bi_dbenv_home, 0, 0);

	/* Check if there is a usable existing environment */
	flags = DB_JOINENV | DB_THREAD;

	rc = bdb->bi_dbenv->open( bdb->bi_dbenv, dbhome,
		flags, bdb->bi_dbenv_mode );
	if( rc == 0 ) {
		int flags_ok = 0;

		got_env = 1;

		rc = bdb->bi_dbenv->get_open_flags( bdb->bi_dbenv, &flags );
		if ( rc == 0 ) {
			int flag2 = flags & BDB_TXN_FLAGS;

			/* In quick mode, none of these flags are allowed */
			if ( slapMode & SLAP_TOOL_QUICK ) {
				if ( !flag2 )
					flags_ok = 1;
			} else {
			/* In normal mode, all of these flags are required */
				if ( flag2 == BDB_TXN_FLAGS )
					flags_ok = 1;
			}
		}

		/* In Quick mode, we cannot Recover... */
		if ( slapMode & SLAP_TOOL_QUICK ) {
			/* If we need to recover but we had no TXNs, just fail */
			if ( do_recover && flags_ok ) {
				Debug( LDAP_DEBUG_ANY,
					"bdb_db_open: Database cannot be recovered. "
					"Restore from backup!\n", 0, 0, 0);
				return -1;
			}
			/* We need to recover, and we had TXN support before:
			 * Close this env, open a new one with recovery flags.
			 */
			if ( do_recover ) {
				bdb->bi_dbenv->close( bdb->bi_dbenv, 0 );
				bdb->bi_dbenv = NULL;
				rc = db_env_create( &bdb->bi_dbenv, 0 );
				if( rc != 0 ) {
					Debug( LDAP_DEBUG_ANY,
						"bdb_db_open: db_env_create failed: %s (%d)\n",
						db_strerror(rc), rc, 0 );
					return rc;
				}
				bdb->bi_dbenv->set_errpfx( bdb->bi_dbenv,
					be->be_suffix[0].bv_val );
				bdb->bi_dbenv->set_errcall( bdb->bi_dbenv, bdb_errcall );
				rc = bdb->bi_dbenv->open( bdb->bi_dbenv, dbhome,
					flags | DB_RECOVER, bdb->bi_dbenv_mode );
				if( rc != 0 ) {
					Debug( LDAP_DEBUG_ANY,
						"bdb_db_open: recovery failed: %s (%d)\n",
						db_strerror(rc), rc, 0 );
					return rc;
				}
				do_recover = 0;
			}
			/* Prev environment had TXN support, get rid of it */
			if ( !flags_ok ) {
281
282
283
284
285
286
287
288
289
				bdb->bi_dbenv->close( bdb->bi_dbenv, 0 );
				bdb->bi_dbenv = NULL;
				rc = db_env_create( &bdb->bi_dbenv, 0 );
				if( rc != 0 ) {
					Debug( LDAP_DEBUG_ANY,
						"bdb_db_open: db_env_create failed: %s (%d)\n",
						db_strerror(rc), rc, 0 );
					return rc;
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
				bdb->bi_dbenv->remove( bdb->bi_dbenv, dbhome, 0 );
				bdb->bi_dbenv = NULL;
			}
		/* Normal TXN mode */
		} else {
			/* If we need to recover but we had no TXNs, just fail */
			if ( do_recover && !flags_ok ) {
				Debug( LDAP_DEBUG_ANY,
					"bdb_db_open: Database cannot be recovered. "
					"Restore from backup!\n", 0, 0, 0);
				return -1;
			}
			/* Prev environment had no TXN support, close it */
			if ( !flags_ok ) {
				bdb->bi_dbenv->close( bdb->bi_dbenv, 0 );
				bdb->bi_dbenv = NULL;
				do_recover = 1;
			}
		}

		if ( flags_ok && !do_recover ) {
			/* This environment is fine, don't reopen it */
			open_env = 0;
		} else {
			/* Create a new env that can take the desired settings */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
315
316
317
318
			if ( bdb->bi_dbenv != NULL ) {
				bdb->bi_dbenv->close( bdb->bi_dbenv, 0 );
				bdb->bi_dbenv = NULL;
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
			rc = db_env_create( &bdb->bi_dbenv, 0 );
			if( rc != 0 ) {
				Debug( LDAP_DEBUG_ANY,
					"bdb_db_open: db_env_create failed: %s (%d)\n",
					db_strerror(rc), rc, 0 );
				return rc;
			}

			bdb->bi_dbenv->set_errpfx( bdb->bi_dbenv, be->be_suffix[0].bv_val );
			bdb->bi_dbenv->set_errcall( bdb->bi_dbenv, bdb_errcall );
			bdb->bi_dbenv->set_lk_detect( bdb->bi_dbenv, bdb->bi_lock_detect );

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

			if( bdb->bi_dbenv_xflags != 0 ) {
				rc = bdb->bi_dbenv->set_flags( bdb->bi_dbenv,
					bdb->bi_dbenv_xflags, 1);
				if( rc != 0 ) {
					Debug( LDAP_DEBUG_ANY,
						"bdb_db_open: dbenv_set_flags failed: %s (%d)\n",
						db_strerror(rc), rc, 0 );
					return rc;
				}
			}
		}
	}

	/* If we need to recover but there was no existing environment,
	 * then we assume that someone has already manually recovered using
	 * db_recover. Just ignore it.
	 */
	if ( do_recover && !got_env ) {
		do_recover = 0;
		Debug( LDAP_DEBUG_TRACE,
			"bdb_db_open: Recovery needed but environment is missing - "
			"assuming recovery was done manually...\n", 0, 0, 0 );
	}

	if ( open_env ) {
		flags = DB_INIT_MPOOL | DB_THREAD | DB_CREATE;
		if ( !( slapMode & SLAP_TOOL_QUICK ))
			flags |= BDB_TXN_FLAGS;

		if ( do_recover )
			flags |= DB_RECOVER;

		/* 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;
		}

		rc = bdb->bi_dbenv->open( bdb->bi_dbenv, dbhome,
			flags, bdb->bi_dbenv_mode );
		if( rc != 0 ) {
			Debug( LDAP_DEBUG_ANY,
				"bdb_db_open: dbenv_open failed: %s (%d)\n",
				db_strerror(rc), rc, 0 );
			return rc;
		}
	}

	if ( do_alock_recover && alock_recover (&bdb->bi_alock_info) != 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
383
		Debug( LDAP_DEBUG_ANY,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
			"bdb_db_open: alock_recover failed\n",
			0, 0, 0 );
		return -1;
	}

#ifdef SLAP_ZONE_ALLOC
	if ( bdb->bi_cache.c_maxsize ) {
		bdb->bi_cache.c_zctx = slap_zn_mem_create(
								SLAP_ZONE_INITSIZE,
								SLAP_ZONE_MAXSIZE,
								SLAP_ZONE_DELTA,
								SLAP_ZONE_SIZE);
	}
#endif

	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
402
403
	}

404
	flags = DB_THREAD | bdb->bi_db_opflags;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
405

Kurt Zeilenga's avatar
Kurt Zeilenga committed
406
407
408
409
410
#ifdef DB_AUTO_COMMIT
	if ( !( slapMode & SLAP_TOOL_QUICK ))
		flags |= DB_AUTO_COMMIT;
#endif

411
412
413
	bdb->bi_databases = (struct bdb_db_info **) ch_malloc(
		BDB_INDICES * sizeof(struct bdb_db_info *) );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
414
	/* open (and create) main database */
415
	for( i = 0; bdbi_databases[i].name; i++ ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
416
417
418
419
420
421
422
		struct bdb_db_info *db;

		db = (struct bdb_db_info *) ch_calloc(1, sizeof(struct bdb_db_info));

		rc = db_create( &db->bdi_db, bdb->bi_dbenv, 0 );
		if( rc != 0 ) {
			Debug( LDAP_DEBUG_ANY,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
423
				"bdb_db_open: db_create(%s) failed: %s (%d)\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
424
425
426
427
				bdb->bi_dbenv_home, db_strerror(rc), rc );
			return rc;
		}

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

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
474
475
476
477
478
		if ( rc != 0 ) {
			char	buf[SLAP_TEXT_BUFLEN];

			snprintf( buf, sizeof(buf), "%s/%s", 
				bdb->bi_dbenv_home, bdbi_databases[i].file );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
479
			Debug( LDAP_DEBUG_ANY,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
480
				"bdb_db_open: db_open(%s) failed: %s (%d)\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
481
				buf, db_strerror(rc), rc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
482
483
			return rc;
		}
484

Kurt Zeilenga's avatar
Kurt Zeilenga committed
485
486
487
488
489
490
491
#if 0
		if( i == BDB_ID2ENTRY && ( slapMode & SLAP_TOOL_MODE )) {
			db->bdi_db->mpf->set_priority( db->bdi_db->mpf,
				DB_PRIORITY_VERY_LOW );
		}
#endif

492
		flags &= ~(DB_CREATE | DB_RDONLY);
493
		db->bdi_name = bdbi_databases[i].name;
494
		bdb->bi_databases[i] = db;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
495
496
	}

497
498
499
	bdb->bi_databases[i] = NULL;
	bdb->bi_ndatabases = i;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
500
501
502
503
504
505
506
507
508
	/* get nextid */
	rc = bdb_last_id( be, NULL );
	if( rc != 0 ) {
		Debug( LDAP_DEBUG_ANY,
			"bdb_db_open: last_id(%s) failed: %s (%d)\n",
			bdb->bi_dbenv_home, db_strerror(rc), rc );
		return rc;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
509
510
511
	if ( !( slapMode & SLAP_TOOL_QUICK )) {
		XLOCK_ID(bdb->bi_dbenv, &bdb->bi_cache.c_locker);
	}
512

513
	bdb->bi_flags |= BDB_IS_OPEN;
514

Kurt Zeilenga's avatar
Kurt Zeilenga committed
515
516
517
	return 0;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
518
static int
Kurt Zeilenga's avatar
Kurt Zeilenga committed
519
bdb_db_close( BackendDB *be )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
520
521
{
	int rc;
522
	struct bdb_info *bdb = (struct bdb_info *) be->be_private;
Howard Chu's avatar
Howard Chu committed
523
	struct bdb_db_info *db;
524
	bdb_idl_cache_entry_t *entry, *next_entry;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
525

Kurt Zeilenga's avatar
Kurt Zeilenga committed
526
527
528
529
	/* backend_shutdown closes everything, even if not all were opened */
	if ( !( bdb->bi_flags & BDB_IS_OPEN ))
		return 0;

530
531
532
533
534
535
	bdb->bi_flags &= ~BDB_IS_OPEN;

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

	while( bdb->bi_databases && bdb->bi_ndatabases-- ) {
Howard Chu's avatar
Howard Chu committed
536
537
		db = bdb->bi_databases[bdb->bi_ndatabases];
		rc = db->bdi_db->close( db->bdi_db, 0 );
538
539
		/* Lower numbered names are not strdup'd */
		if( bdb->bi_ndatabases >= BDB_NDB )
Howard Chu's avatar
Howard Chu committed
540
541
			free( db->bdi_name );
		free( db );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
542
	}
Howard Chu's avatar
Howard Chu committed
543
	free( bdb->bi_databases );
544
	bdb->bi_databases = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
545

546
547
	bdb_cache_release_all (&bdb->bi_cache);

548
549
	if ( bdb->bi_idl_cache_max_size ) {
		ldap_pvt_thread_rdwr_wlock ( &bdb->bi_idl_tree_rwlock );
550
		avl_free( bdb->bi_idl_tree, NULL );
551
		bdb->bi_idl_tree = NULL;
552
553
554
		entry = bdb->bi_idl_lru_head;
		while ( entry != NULL ) {
			next_entry = entry->idl_lru_next;
555
556
			if ( entry->idl )
				free( entry->idl );
557
558
559
560
			free( entry->kstr.bv_val );
			free( entry );
			entry = next_entry;
		}
561
		bdb->bi_idl_lru_head = bdb->bi_idl_lru_tail = NULL;
562
		ldap_pvt_thread_rdwr_wunlock ( &bdb->bi_idl_tree_rwlock );
563
564
	}

565
	if ( !( slapMode & SLAP_TOOL_QUICK ) && bdb->bi_dbenv ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
566
		XLOCK_ID_FREE(bdb->bi_dbenv, bdb->bi_cache.c_locker);
567
		bdb->bi_cache.c_locker = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
568
	}
Howard Chu's avatar
Howard Chu committed
569

570
	/* close db environment */
571
	if( bdb->bi_dbenv ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
572
573
574
575
		/* 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 ))) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
576
577
578
			rc = TXN_CHECKPOINT( bdb->bi_dbenv, 0, 0, DB_FORCE );
			if( rc != 0 ) {
				Debug( LDAP_DEBUG_ANY,
579
					"bdb_db_close: txn_checkpoint failed: %s (%d)\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
580
581
					db_strerror(rc), rc, 0 );
			}
582
583
		}

584
585
586
587
		rc = bdb->bi_dbenv->close( bdb->bi_dbenv, 0 );
		bdb->bi_dbenv = NULL;
		if( rc != 0 ) {
			Debug( LDAP_DEBUG_ANY,
588
				"bdb_db_close: close failed: %s (%d)\n",
589
590
591
				db_strerror(rc), rc, 0 );
			return rc;
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
592
593
	}

594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
	rc = alock_close( &bdb->bi_alock_info );
	if( rc != 0 ) {
		Debug( LDAP_DEBUG_ANY,
			"bdb_db_close: alock_close failed\n", 0, 0, 0 );
		return -1;
	}

	return 0;
}

static int
bdb_db_destroy( BackendDB *be )
{
	struct bdb_info *bdb = (struct bdb_info *) be->be_private;

Howard Chu's avatar
Howard Chu committed
609
	if( bdb->bi_dbenv_home ) ch_free( bdb->bi_dbenv_home );
610
611
612
	if( bdb->bi_db_config_path ) ch_free( bdb->bi_db_config_path );

	bdb_attr_index_destroy( bdb->bi_attrs );
Howard Chu's avatar
Howard Chu committed
613

614
615
	ldap_pvt_thread_rdwr_destroy ( &bdb->bi_cache.c_rwlock );
	ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.lru_mutex );
Howard Chu's avatar
Howard Chu committed
616
	ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.c_dntree.bei_kids_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
617
618
619
#ifdef BDB_HIER
	ldap_pvt_thread_mutex_destroy( &bdb->bi_modrdns_mutex );
#endif
620
	ldap_pvt_thread_mutex_destroy( &bdb->bi_lastid_mutex );
Howard Chu's avatar
Howard Chu committed
621
	ldap_pvt_thread_mutex_destroy( &bdb->bi_database_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
622
623
	ldap_pvt_thread_rdwr_destroy( &bdb->bi_idl_tree_rwlock );
	ldap_pvt_thread_mutex_destroy( &bdb->bi_idl_tree_lrulock );
624

Howard Chu's avatar
Howard Chu committed
625
626
627
	ch_free( bdb );
	be->be_private = NULL;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
628
629
	return 0;
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
630
631

int
632
bdb_back_initialize(
633
	BackendInfo	*bi )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
634
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
635
636
	int rc;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
637
	static char *controls[] = {
638
		LDAP_CONTROL_ASSERT,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
639
640
		LDAP_CONTROL_MANAGEDSAIT,
		LDAP_CONTROL_NOOP,
641
642
643
		LDAP_CONTROL_PAGEDRESULTS,
#ifdef LDAP_CONTROL_SUBENTRIES
		LDAP_CONTROL_SUBENTRIES,
644
#endif
645
646
647
#ifdef LDAP_CONTROL_X_PERMISSIVE_MODIFY
		LDAP_CONTROL_X_PERMISSIVE_MODIFY,
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
648
649
650
651
		NULL
	};

	/* initialize the underlying database system */
652
653
654
	Debug( LDAP_DEBUG_TRACE,
		LDAP_XSTRING(bdb_back_initialize) ": initialize " 
		BDB_UCTYPE " backend\n", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
655

656
657
658
659
660
661
662
663
664
665
	bi->bi_flags |=
		SLAP_BFLAG_INCREMENT |
#ifdef BDB_SUBENTRIES
		SLAP_BFLAG_SUBENTRIES |
#endif
		SLAP_BFLAG_ALIASES |
		SLAP_BFLAG_REFERRALS;

	bi->bi_controls = controls;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
666
	{	/* version check */
667
		int major, minor, patch, ver;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
668
		char *version = db_version( &major, &minor, &patch );
Howard Chu's avatar
Howard Chu committed
669
670
671
672
673
674
675
676
677
678
679
#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
680

681
		ver = (major << 24) | (minor << 16) | patch;
682
683
		if( ver != DB_VERSION_FULL ) {
			/* fail if a versions don't match */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
684
			Debug( LDAP_DEBUG_ANY,
685
				LDAP_XSTRING(bdb_back_initialize) ": "
Pierangelo Masarati's avatar
Pierangelo Masarati committed
686
				"BDB library version mismatch:"
687
688
				" expected " DB_VERSION_STRING ","
				" got %s\n", version, 0, 0 );
689
			return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
690
691
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
692
		Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_back_initialize)
693
			": %s\n", version, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
694
695
	}

Howard Chu's avatar
Howard Chu committed
696
697
698
	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 );
699
700
701
702
#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
703
	db_env_set_func_yield( ldap_pvt_thread_yield );
704
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
705
706

	bi->bi_open = 0;
707
	bi->bi_close = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
708
	bi->bi_config = 0;
709
	bi->bi_destroy = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
710

Kurt Zeilenga's avatar
Kurt Zeilenga committed
711
	bi->bi_db_init = bdb_db_init;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
712
	bi->bi_db_config = config_generic_wrapper;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
713
714
715
	bi->bi_db_open = bdb_db_open;
	bi->bi_db_close = bdb_db_close;
	bi->bi_db_destroy = bdb_db_destroy;
716

Kurt Zeilenga's avatar
Kurt Zeilenga committed
717
	bi->bi_op_add = bdb_add;
718
	bi->bi_op_bind = bdb_bind;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
719
720
	bi->bi_op_compare = bdb_compare;
	bi->bi_op_delete = bdb_delete;
721
722
	bi->bi_op_modify = bdb_modify;
	bi->bi_op_modrdn = bdb_modrdn;
723
724
	bi->bi_op_search = bdb_search;

Howard Chu's avatar
Howard Chu committed
725
	bi->bi_op_unbind = 0;
726

727
	bi->bi_extended = bdb_extended;
Howard Chu's avatar
Howard Chu committed
728

729
	bi->bi_chk_referrals = bdb_referrals;
730
	bi->bi_operational = bdb_operational;
731
	bi->bi_has_subordinates = bdb_hasSubordinates;
732
	bi->bi_entry_release_rw = bdb_entry_release;
733
	bi->bi_entry_get_rw = bdb_entry_get;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
734
735
736
737

	/*
	 * hooks for slap tools
	 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
738
739
740
741
742
743
	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
744
	bi->bi_tool_entry_reindex = bdb_tool_entry_reindex;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
745
	bi->bi_tool_sync = 0;
746
747
748
	bi->bi_tool_dn2id_get = bdb_tool_dn2id_get;
	bi->bi_tool_id2entry_get = bdb_tool_id2entry_get;
	bi->bi_tool_entry_modify = bdb_tool_entry_modify;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
749
750
751
752

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

753
	rc = bdb_back_init_cf( bi );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
754
755

	return rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
756
}
757
758
759
760

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

Pierangelo Masarati's avatar
Pierangelo Masarati committed
761
/* conditionally define the init_module() function */
762
#ifdef BDB_HIER
Pierangelo Masarati's avatar
Pierangelo Masarati committed
763
764
765
766
SLAP_BACKEND_INIT_MODULE( hdb )
#else /* !BDB_HIER */
SLAP_BACKEND_INIT_MODULE( bdb )
#endif /* !BDB_HIER */
767

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