]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/init.c
Tweak log msg in prev commit
[openldap] / servers / slapd / back-bdb / init.c
1 /* init.c - initialize bdb backend */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2005 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
24 #include "back-bdb.h"
25 #include <lutil.h>
26 #include <ldap_rq.h>
27
28 static const struct bdbi_database {
29         char *file;
30         char *name;
31         int type;
32         int flags;
33 } bdbi_databases[] = {
34         { "id2entry" BDB_SUFFIX, "id2entry", DB_BTREE, 0 },
35         { "dn2id" BDB_SUFFIX, "dn2id", DB_BTREE, 0 },
36         { NULL, NULL, 0, 0 }
37 };
38
39 typedef void * db_malloc(size_t);
40 typedef void * db_realloc(void *, size_t);
41
42 static int
43 bdb_db_init( BackendDB *be )
44 {
45         struct bdb_info *bdb;
46
47         Debug( LDAP_DEBUG_TRACE,
48                 LDAP_XSTRING(bdb_db_init) ": Initializing " BDB_UCTYPE " database\n",
49                 0, 0, 0 );
50
51         /* allocate backend-database-specific stuff */
52         bdb = (struct bdb_info *) ch_calloc( 1, sizeof(struct bdb_info) );
53
54         /* DBEnv parameters */
55         bdb->bi_dbenv_home = ch_strdup( SLAPD_DEFAULT_DB_DIR );
56         bdb->bi_dbenv_xflags = 0;
57         bdb->bi_dbenv_mode = SLAPD_DEFAULT_DB_MODE;
58
59         bdb->bi_cache.c_maxsize = DEFAULT_CACHE_SIZE;
60
61         bdb->bi_lock_detect = DB_LOCK_DEFAULT;
62         bdb->bi_search_stack_depth = DEFAULT_SEARCH_STACK_DEPTH;
63         bdb->bi_search_stack = NULL;
64
65         ldap_pvt_thread_mutex_init( &bdb->bi_database_mutex );
66         ldap_pvt_thread_mutex_init( &bdb->bi_lastid_mutex );
67         ldap_pvt_thread_mutex_init( &bdb->bi_cache.lru_mutex );
68         ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_dntree.bei_kids_mutex );
69         ldap_pvt_thread_rdwr_init ( &bdb->bi_cache.c_rwlock );
70
71         be->be_private = bdb;
72         be->be_cf_table = be->bd_info->bi_cf_table;
73
74         return 0;
75 }
76
77 static void *
78 bdb_checkpoint( void *ctx, void *arg )
79 {
80         struct re_s *rtask = arg;
81         struct bdb_info *bdb = rtask->arg;
82         
83         TXN_CHECKPOINT( bdb->bi_dbenv, bdb->bi_txn_cp_kbyte,
84                 bdb->bi_txn_cp_min, 0 );
85         return NULL;
86 }
87
88 static int
89 bdb_db_open( BackendDB *be )
90 {
91         int rc, i;
92         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
93         u_int32_t flags;
94 #ifdef HAVE_EBCDIC
95         char path[MAXPATHLEN];
96 #endif
97
98         Debug( LDAP_DEBUG_ARGS,
99                 "bdb_db_open: %s\n",
100                 be->be_suffix[0].bv_val, 0, 0 );
101
102 #ifndef BDB_MULTIPLE_SUFFIXES
103         if ( be->be_suffix[1].bv_val ) {
104         Debug( LDAP_DEBUG_ANY,
105                 "bdb_db_open: only one suffix allowed\n", 0, 0, 0 );
106                 return -1;
107         }
108 #endif
109         /* we should check existance of dbenv_home and db_directory */
110
111         rc = db_env_create( &bdb->bi_dbenv, 0 );
112         if( rc != 0 ) {
113                 Debug( LDAP_DEBUG_ANY,
114                         "bdb_db_open: db_env_create failed: %s (%d)\n",
115                         db_strerror(rc), rc, 0 );
116                 return rc;
117         }
118
119         flags = DB_INIT_MPOOL | DB_THREAD | DB_CREATE;
120
121         if ( !( slapMode & SLAP_TOOL_QUICK ))
122                 flags |= DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN;
123         
124 #if 0
125         /* Never do automatic recovery, must perform it manually.
126          * Otherwise restarting with gentlehup will corrupt the
127          * database.
128          */
129         if( !(slapMode & SLAP_TOOL_MODE) ) flags |= DB_RECOVER;
130 #endif
131
132         /* If a key was set, use shared memory for the BDB environment */
133         if ( bdb->bi_shm_key ) {
134                 bdb->bi_dbenv->set_shm_key( bdb->bi_dbenv, bdb->bi_shm_key );
135                 flags |= DB_SYSTEM_MEM;
136         }
137
138         bdb->bi_dbenv->set_errpfx( bdb->bi_dbenv, be->be_suffix[0].bv_val );
139         bdb->bi_dbenv->set_errcall( bdb->bi_dbenv, bdb_errcall );
140         bdb->bi_dbenv->set_lk_detect( bdb->bi_dbenv, bdb->bi_lock_detect );
141
142         /* One long-lived TXN per thread, two TXNs per write op */
143         bdb->bi_dbenv->set_tx_max( bdb->bi_dbenv, connection_pool_max * 3 );
144
145 #ifdef SLAP_ZONE_ALLOC
146         if ( bdb->bi_cache.c_maxsize ) {
147                 bdb->bi_cache.c_zctx = slap_zn_mem_create(
148                                                                 SLAP_ZONE_INITSIZE,
149                                                                 SLAP_ZONE_MAXSIZE,
150                                                                 SLAP_ZONE_DELTA,
151                                                                 SLAP_ZONE_SIZE);
152         }
153 #endif
154
155         if ( bdb->bi_idl_cache_max_size ) {
156                 bdb->bi_idl_tree = NULL;
157                 ldap_pvt_thread_rdwr_init( &bdb->bi_idl_tree_rwlock );
158                 ldap_pvt_thread_mutex_init( &bdb->bi_idl_tree_lrulock );
159                 bdb->bi_idl_cache_size = 0;
160         }
161
162 #ifdef BDB_SUBDIRS
163         {
164                 char dir[MAXPATHLEN], *ptr;
165                 
166                 if (bdb->bi_dbenv_home[0] == '.') {
167                         /* If home is a relative path, relative subdirs
168                          * are just concat'd by BDB. We don't want the
169                          * path to be concat'd twice, e.g.
170                          * ./test-db/./test-db/tmp
171                          */
172                         ptr = dir;
173                 } else {
174                         ptr = lutil_strcopy( dir, bdb->bi_dbenv_home );
175                         *ptr++ = LDAP_DIRSEP[0];
176 #ifdef HAVE_EBCDIC
177                         __atoe( dir );
178 #endif
179                 }
180
181                 strcpy( ptr, BDB_TMP_SUBDIR );
182 #ifdef HAVE_EBCDIC
183                 __atoe( ptr );
184 #endif
185                 rc = bdb->bi_dbenv->set_tmp_dir( bdb->bi_dbenv, dir );
186                 if( rc != 0 ) {
187                         Debug( LDAP_DEBUG_ANY,
188                                 "bdb_db_open: set_tmp_dir(%s) failed: %s (%d)\n",
189                                 dir, db_strerror(rc), rc );
190                         return rc;
191                 }
192
193                 strcpy( ptr, BDB_LG_SUBDIR );
194 #ifdef HAVE_EBCDIC
195                 __atoe( ptr );
196 #endif
197                 rc = bdb->bi_dbenv->set_lg_dir( bdb->bi_dbenv, dir );
198                 if( rc != 0 ) {
199                         Debug( LDAP_DEBUG_ANY,
200                                 "bdb_db_open: set_lg_dir(%s) failed: %s (%d)\n",
201                                 dir, db_strerror(rc), rc );
202                         return rc;
203                 }
204
205                 strcpy( ptr, BDB_DATA_SUBDIR );
206 #ifdef HAVE_EBCDIC
207                 __atoe( ptr );
208 #endif
209                 rc = bdb->bi_dbenv->set_data_dir( bdb->bi_dbenv, dir );
210                 if( rc != 0 ) {
211                         Debug( LDAP_DEBUG_ANY,
212                                 "bdb_db_open: set_data_dir(%s) failed: %s (%d)\n",
213                                 dir, db_strerror(rc), rc );
214                         return rc;
215                 }
216         }
217 #endif
218
219         if( bdb->bi_dbenv_xflags != 0 ) {
220                 rc = bdb->bi_dbenv->set_flags( bdb->bi_dbenv,
221                         bdb->bi_dbenv_xflags, 1);
222                 if( rc != 0 ) {
223                         Debug( LDAP_DEBUG_ANY,
224                                 "bdb_db_open: dbenv_set_flags failed: %s (%d)\n",
225                                 db_strerror(rc), rc, 0 );
226                         return rc;
227                 }
228         }
229
230         Debug( LDAP_DEBUG_TRACE,
231                 "bdb_db_open: dbenv_open(%s)\n",
232                 bdb->bi_dbenv_home, 0, 0);
233
234 #ifdef HAVE_EBCDIC
235         strcpy( path, bdb->bi_dbenv_home );
236         __atoe( path );
237         rc = bdb->bi_dbenv->open( bdb->bi_dbenv,
238                 path,
239                 flags,
240                 bdb->bi_dbenv_mode );
241 #else
242         rc = bdb->bi_dbenv->open( bdb->bi_dbenv,
243                 bdb->bi_dbenv_home,
244                 flags,
245                 bdb->bi_dbenv_mode );
246 #endif
247         if( rc != 0 ) {
248                 Debug( LDAP_DEBUG_ANY,
249                         "bdb_db_open: dbenv_open failed: %s (%d)\n",
250                         db_strerror(rc), rc, 0 );
251                 return rc;
252         }
253
254         flags = DB_THREAD | bdb->bi_db_opflags;
255
256 #ifdef DB_AUTO_COMMIT
257         if ( !( slapMode & SLAP_TOOL_QUICK ))
258                 flags |= DB_AUTO_COMMIT;
259 #endif
260
261         bdb->bi_databases = (struct bdb_db_info **) ch_malloc(
262                 BDB_INDICES * sizeof(struct bdb_db_info *) );
263
264         /* open (and create) main database */
265         for( i = 0; bdbi_databases[i].name; i++ ) {
266                 struct bdb_db_info *db;
267
268                 db = (struct bdb_db_info *) ch_calloc(1, sizeof(struct bdb_db_info));
269
270                 rc = db_create( &db->bdi_db, bdb->bi_dbenv, 0 );
271                 if( rc != 0 ) {
272                         Debug( LDAP_DEBUG_ANY,
273                                 "bdb_db_open: db_create(%s) failed: %s (%d)\n",
274                                 bdb->bi_dbenv_home, db_strerror(rc), rc );
275                         return rc;
276                 }
277
278                 if( i == BDB_ID2ENTRY ) {
279                         rc = db->bdi_db->set_pagesize( db->bdi_db,
280                                 BDB_ID2ENTRY_PAGESIZE );
281                         if ( slapMode & SLAP_TOOL_READMAIN ) {
282                                 flags |= DB_RDONLY;
283                         } else {
284                                 flags |= DB_CREATE;
285                         }
286                 } else {
287                         rc = db->bdi_db->set_flags( db->bdi_db, 
288                                 DB_DUP | DB_DUPSORT );
289 #ifndef BDB_HIER
290                         if ( slapMode & SLAP_TOOL_READONLY ) {
291                                 flags |= DB_RDONLY;
292                         } else {
293                                 flags |= DB_CREATE;
294                         }
295 #else
296                         if ( slapMode & (SLAP_TOOL_READONLY|SLAP_TOOL_READMAIN) ) {
297                                 flags |= DB_RDONLY;
298                         } else {
299                                 flags |= DB_CREATE;
300                         }
301 #endif
302                         rc = db->bdi_db->set_pagesize( db->bdi_db,
303                                 BDB_PAGESIZE );
304                 }
305
306 #ifdef HAVE_EBCDIC
307                 strcpy( path, bdbi_databases[i].file );
308                 __atoe( path );
309                 rc = DB_OPEN( db->bdi_db,
310                         path,
311                 /*      bdbi_databases[i].name, */ NULL,
312                         bdbi_databases[i].type,
313                         bdbi_databases[i].flags | flags,
314                         bdb->bi_dbenv_mode );
315 #else
316                 rc = DB_OPEN( db->bdi_db,
317                         bdbi_databases[i].file,
318                 /*      bdbi_databases[i].name, */ NULL,
319                         bdbi_databases[i].type,
320                         bdbi_databases[i].flags | flags,
321                         bdb->bi_dbenv_mode );
322 #endif
323
324                 if ( rc != 0 ) {
325                         char    buf[SLAP_TEXT_BUFLEN];
326
327                         snprintf( buf, sizeof(buf), "%s/%s", 
328                                 bdb->bi_dbenv_home, bdbi_databases[i].file );
329                         Debug( LDAP_DEBUG_ANY,
330                                 "bdb_db_open: db_open(%s) failed: %s (%d)\n",
331                                 buf, db_strerror(rc), rc );
332                         return rc;
333                 }
334
335                 flags &= ~(DB_CREATE | DB_RDONLY);
336                 db->bdi_name = bdbi_databases[i].name;
337                 bdb->bi_databases[i] = db;
338         }
339
340         bdb->bi_databases[i] = NULL;
341         bdb->bi_ndatabases = i;
342
343         /* get nextid */
344         rc = bdb_last_id( be, NULL );
345         if( rc != 0 ) {
346                 Debug( LDAP_DEBUG_ANY,
347                         "bdb_db_open: last_id(%s) failed: %s (%d)\n",
348                         bdb->bi_dbenv_home, db_strerror(rc), rc );
349                 return rc;
350         }
351
352         if ( !( slapMode & SLAP_TOOL_QUICK )) {
353                 XLOCK_ID(bdb->bi_dbenv, &bdb->bi_cache.c_locker);
354         }
355
356         /* If we're in server mode and time-based checkpointing is enabled,
357          * submit a task to perform periodic checkpoints.
358          */
359         if ( slapMode & SLAP_SERVER_MODE && bdb->bi_txn_cp &&
360                 bdb->bi_txn_cp_min )  {
361                 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
362                 ldap_pvt_runqueue_insert( &slapd_rq, bdb->bi_txn_cp_min*60,
363                         bdb_checkpoint, bdb );
364                 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
365         }
366
367         return 0;
368 }
369
370 static int
371 bdb_db_close( BackendDB *be )
372 {
373         int rc;
374         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
375         struct bdb_db_info *db;
376         bdb_idl_cache_entry_t *entry, *next_entry;
377
378         while( bdb->bi_ndatabases-- ) {
379                 db = bdb->bi_databases[bdb->bi_ndatabases];
380                 rc = db->bdi_db->close( db->bdi_db, 0 );
381                 /* Lower numbered names are not strdup'd */
382                 if( bdb->bi_ndatabases >= BDB_NDB )
383                         free( db->bdi_name );
384                 free( db );
385         }
386         free( bdb->bi_databases );
387         bdb_attr_index_destroy( bdb->bi_attrs );
388
389         bdb_cache_release_all (&bdb->bi_cache);
390
391         if ( bdb->bi_idl_cache_max_size ) {
392                 ldap_pvt_thread_rdwr_wlock ( &bdb->bi_idl_tree_rwlock );
393                 avl_free( bdb->bi_idl_tree, NULL );
394                 entry = bdb->bi_idl_lru_head;
395                 while ( entry != NULL ) {
396                         next_entry = entry->idl_lru_next;
397                         if ( entry->idl )
398                                 free( entry->idl );
399                         free( entry->kstr.bv_val );
400                         free( entry );
401                         entry = next_entry;
402                 }
403                 ldap_pvt_thread_rdwr_wunlock ( &bdb->bi_idl_tree_rwlock );
404         }
405
406         if ( !( slapMode & SLAP_TOOL_QUICK )) {
407                 XLOCK_ID_FREE(bdb->bi_dbenv, bdb->bi_cache.c_locker);
408         }
409
410         return 0;
411 }
412
413 static int
414 bdb_db_destroy( BackendDB *be )
415 {
416         int rc;
417         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
418
419         /* close db environment */
420         if( bdb->bi_dbenv ) {
421                 /* force a checkpoint */
422                 if ( !( slapMode & SLAP_TOOL_QUICK )) {
423                         rc = TXN_CHECKPOINT( bdb->bi_dbenv, 0, 0, DB_FORCE );
424                         if( rc != 0 ) {
425                                 Debug( LDAP_DEBUG_ANY,
426                                         "bdb_db_destroy: txn_checkpoint failed: %s (%d)\n",
427                                         db_strerror(rc), rc, 0 );
428                         }
429                 }
430
431                 rc = bdb->bi_dbenv->close( bdb->bi_dbenv, 0 );
432                 bdb->bi_dbenv = NULL;
433                 if( rc != 0 ) {
434                         Debug( LDAP_DEBUG_ANY,
435                                 "bdb_db_destroy: close failed: %s (%d)\n",
436                                 db_strerror(rc), rc, 0 );
437                         return rc;
438                 }
439         }
440
441         if( bdb->bi_dbenv_home ) ch_free( bdb->bi_dbenv_home );
442
443         ldap_pvt_thread_rdwr_destroy ( &bdb->bi_cache.c_rwlock );
444         ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.lru_mutex );
445         ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.c_dntree.bei_kids_mutex );
446         ldap_pvt_thread_mutex_destroy( &bdb->bi_lastid_mutex );
447         ldap_pvt_thread_mutex_destroy( &bdb->bi_database_mutex );
448         if ( bdb->bi_idl_cache_max_size ) {
449                 ldap_pvt_thread_rdwr_destroy( &bdb->bi_idl_tree_rwlock );
450                 ldap_pvt_thread_mutex_destroy( &bdb->bi_idl_tree_lrulock );
451         }
452
453         ch_free( bdb );
454         be->be_private = NULL;
455
456         return 0;
457 }
458
459 int
460 bdb_back_initialize(
461         BackendInfo     *bi )
462 {
463         int rc;
464
465         static char *controls[] = {
466                 LDAP_CONTROL_ASSERT,
467                 LDAP_CONTROL_MANAGEDSAIT,
468                 LDAP_CONTROL_NOOP,
469                 LDAP_CONTROL_PAGEDRESULTS,
470 #ifdef LDAP_CONTROL_SUBENTRIES
471                 LDAP_CONTROL_SUBENTRIES,
472 #endif
473 #ifdef LDAP_CONTROL_X_PERMISSIVE_MODIFY
474                 LDAP_CONTROL_X_PERMISSIVE_MODIFY,
475 #endif
476                 NULL
477         };
478
479         /* initialize the underlying database system */
480         Debug( LDAP_DEBUG_TRACE,
481                 LDAP_XSTRING(bdb_back_initialize) ": initialize " 
482                 BDB_UCTYPE " backend\n", 0, 0, 0 );
483
484         bi->bi_flags |=
485                 SLAP_BFLAG_INCREMENT |
486 #ifdef BDB_SUBENTRIES
487                 SLAP_BFLAG_SUBENTRIES |
488 #endif
489                 SLAP_BFLAG_ALIASES |
490                 SLAP_BFLAG_REFERRALS;
491
492         bi->bi_controls = controls;
493
494         {       /* version check */
495                 int major, minor, patch, ver;
496                 char *version = db_version( &major, &minor, &patch );
497 #ifdef HAVE_EBCDIC
498                 char v2[1024];
499
500                 /* All our stdio does an ASCII to EBCDIC conversion on
501                  * the output. Strings from the BDB library are already
502                  * in EBCDIC; we have to go back and forth...
503                  */
504                 strcpy( v2, version );
505                 __etoa( v2 );
506                 version = v2;
507 #endif
508
509                 ver = (major << 24) | (minor << 16) | patch;
510                 if( ver != DB_VERSION_FULL ) {
511                         /* fail if a versions don't match */
512                         Debug( LDAP_DEBUG_ANY,
513                                 LDAP_XSTRING(bdb_back_initialize) ": "
514                                 "BDB library version mismatch:"
515                                 " expected " DB_VERSION_STRING ","
516                                 " got %s\n", version, 0, 0 );
517                         return -1;
518                 }
519
520                 Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_back_initialize)
521                         ": %s\n", version, 0, 0 );
522         }
523
524         db_env_set_func_free( ber_memfree );
525         db_env_set_func_malloc( (db_malloc *)ber_memalloc );
526         db_env_set_func_realloc( (db_realloc *)ber_memrealloc );
527 #ifndef NO_THREAD
528         /* This is a no-op on a NO_THREAD build. Leave the default
529          * alone so that BDB will sleep on interprocess conflicts.
530          */
531         db_env_set_func_yield( ldap_pvt_thread_yield );
532 #endif
533
534         bi->bi_open = 0;
535         bi->bi_close = 0;
536         bi->bi_config = 0;
537         bi->bi_destroy = 0;
538
539         bi->bi_db_init = bdb_db_init;
540         bi->bi_db_config = config_generic_wrapper;
541         bi->bi_db_open = bdb_db_open;
542         bi->bi_db_close = bdb_db_close;
543         bi->bi_db_destroy = bdb_db_destroy;
544
545         bi->bi_op_add = bdb_add;
546         bi->bi_op_bind = bdb_bind;
547         bi->bi_op_compare = bdb_compare;
548         bi->bi_op_delete = bdb_delete;
549         bi->bi_op_modify = bdb_modify;
550         bi->bi_op_modrdn = bdb_modrdn;
551         bi->bi_op_search = bdb_search;
552
553         bi->bi_op_unbind = 0;
554
555         bi->bi_extended = bdb_extended;
556
557         bi->bi_chk_referrals = bdb_referrals;
558         bi->bi_operational = bdb_operational;
559         bi->bi_has_subordinates = bdb_hasSubordinates;
560         bi->bi_entry_release_rw = bdb_entry_release;
561         bi->bi_entry_get_rw = bdb_entry_get;
562
563         /*
564          * hooks for slap tools
565          */
566         bi->bi_tool_entry_open = bdb_tool_entry_open;
567         bi->bi_tool_entry_close = bdb_tool_entry_close;
568         bi->bi_tool_entry_first = bdb_tool_entry_next;
569         bi->bi_tool_entry_next = bdb_tool_entry_next;
570         bi->bi_tool_entry_get = bdb_tool_entry_get;
571         bi->bi_tool_entry_put = bdb_tool_entry_put;
572         bi->bi_tool_entry_reindex = bdb_tool_entry_reindex;
573         bi->bi_tool_sync = 0;
574         bi->bi_tool_dn2id_get = bdb_tool_dn2id_get;
575         bi->bi_tool_id2entry_get = bdb_tool_id2entry_get;
576         bi->bi_tool_entry_modify = bdb_tool_entry_modify;
577
578         bi->bi_connection_init = 0;
579         bi->bi_connection_destroy = 0;
580
581         rc = bdb_back_init_cf(bi);
582
583         return rc;
584 }
585
586 #if     (SLAPD_BDB == SLAPD_MOD_DYNAMIC && !defined(BDB_HIER)) || \
587         (SLAPD_HDB == SLAPD_MOD_DYNAMIC && defined(BDB_HIER))
588
589 /* conditionally define the init_module() function */
590 #ifdef BDB_HIER
591 SLAP_BACKEND_INIT_MODULE( hdb )
592 #else /* !BDB_HIER */
593 SLAP_BACKEND_INIT_MODULE( bdb )
594 #endif /* !BDB_HIER */
595
596 #endif /* SLAPD_[BH]DB == SLAPD_MOD_DYNAMIC */
597