]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/init.c
Fix previous commit
[openldap] / servers / slapd / back-bdb / init.c
1 /* init.c - initialize bdb backend */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11 #include <ac/string.h>
12 #include <ac/unistd.h>
13 #include <ac/stdlib.h>
14
15 #include "back-bdb.h"
16 #include "external.h"
17
18 static struct bdbi_database {
19         char *file;
20         char *name;
21         int type;
22         int flags;
23 } bdbi_databases[] = {
24         { "id2entry" BDB_SUFFIX, "id2entry", DB_BTREE, 0 },
25 #ifdef BDB_HIER
26         { "id2parent" BDB_SUFFIX, "id2parent", DB_BTREE, 0 },
27 #else
28         { "dn2id" BDB_SUFFIX, "dn2id", DB_BTREE, 0 },
29 #endif
30         { NULL, NULL, 0, 0 }
31 };
32
33 #if 0
34 static int
35 bdb_destroy( BackendInfo *bi )
36 {
37         return 0;
38 }
39
40 static int
41 bdb_open( BackendInfo *bi )
42 {
43         /* initialize the underlying database system */
44         Debug( LDAP_DEBUG_TRACE, "bdb_open: initialize BDB backend\n",
45                 0, 0, 0 );
46
47         return 0;
48 }
49
50 static int
51 bdb_close( BackendInfo *bi )
52 {
53         /* terminate the underlying database system */
54         return 0;
55 }
56 #endif
57
58 static int
59 bdb_db_init( BackendDB *be )
60 {
61         struct bdb_info *bdb;
62
63         Debug( LDAP_DEBUG_ANY,
64                 "bdb_db_init: Initializing BDB database\n",
65                 0, 0, 0 );
66
67         /* indicate system schema supported */
68         be->be_flags |= SLAP_BFLAG_ALIASES
69                 | SLAP_BFLAG_REFERRALS
70                 | SLAP_BFLAG_SUBENTRIES;
71
72         /* allocate backend-database-specific stuff */
73         bdb = (struct bdb_info *) ch_calloc( 1, sizeof(struct bdb_info) );
74
75         /* DBEnv parameters */
76         bdb->bi_dbenv_home = ch_strdup( BDB_DBENV_HOME );
77         bdb->bi_dbenv_xflags = 0;
78         bdb->bi_dbenv_mode = DEFAULT_MODE;
79         bdb->bi_txn = 1;        /* default to using transactions */
80
81         bdb->bi_cache.c_maxsize = DEFAULT_CACHE_SIZE;
82
83 #ifndef NO_THREADS
84 #if 0
85         bdb->bi_lock_detect = DB_LOCK_NORUN;
86 #else
87         bdb->bi_lock_detect = DB_LOCK_DEFAULT;
88 #endif
89 #endif
90
91         ldap_pvt_thread_mutex_init( &bdb->bi_database_mutex );
92         ldap_pvt_thread_mutex_init( &bdb->bi_lastid_mutex );
93         ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_mutex );
94 #ifdef BDB_HIER
95         ldap_pvt_thread_rdwr_init( &bdb->bi_tree_rdwr );
96 #endif
97
98         be->be_private = bdb;
99         return 0;
100 }
101
102 #if 0 /* ifndef NO_THREADS */
103 static void *lock_detect_task( void *arg )
104 {
105         struct bdb_info *bdb = (struct bdb_info *) arg;
106
107         while( bdb->bi_dbenv != NULL ) {
108                 int rc;
109                 int aborted;
110                 sleep( bdb->bi_lock_detect_seconds );
111
112                 rc = LOCK_DETECT( bdb->bi_dbenv, 0,
113                         bdb->bi_lock_detect, &aborted );
114
115                 if( rc != 0 ) {
116                         break;
117                 }
118
119                 Debug( LDAP_DEBUG_ANY,
120                         "bdb_lock_detect: aborted %d locks\n",
121                         aborted, 0, 0 );
122         }
123
124         return NULL;
125 }
126 #endif
127
128 int
129 bdb_bt_compare(
130         DB *db, 
131         const DBT *usrkey,
132         const DBT *curkey
133 )
134 {
135         unsigned char *u, *c;
136         int i;
137
138         u = usrkey->data;
139         c = curkey->data;
140
141 #ifdef WORDS_BIGENDIAN
142         for( i = 0; i < sizeof(ID); i++)
143 #else
144         for( i = sizeof(ID)-1; i >= 0; i--)
145 #endif
146         {
147                 if( u[i] - c[i] )
148                         return u[i] - c[i];
149         }
150         return 0;
151 }
152
153 static int
154 bdb_db_open( BackendDB *be )
155 {
156         int rc, i;
157         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
158         u_int32_t flags;
159
160         Debug( LDAP_DEBUG_ARGS,
161                 "bdb_db_open: %s\n",
162                 be->be_suffix[0]->bv_val, 0, 0 );
163
164         /* we should check existance of dbenv_home and db_directory */
165
166         rc = db_env_create( &bdb->bi_dbenv, 0 );
167         if( rc != 0 ) {
168                 Debug( LDAP_DEBUG_ANY,
169                         "bdb_db_open: db_env_create failed: %s (%d)\n",
170                         db_strerror(rc), rc, 0 );
171                 return rc;
172         }
173
174         flags = DB_INIT_MPOOL | DB_THREAD | DB_CREATE;
175
176         if( bdb->bi_txn ) {
177                 flags |= DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN | DB_RECOVER;
178
179         } else {
180                 flags |= DB_INIT_CDB;
181                 bdb->bi_txn_cp = 0;
182         }
183
184         bdb->bi_dbenv->set_errpfx( bdb->bi_dbenv, be->be_suffix[0]->bv_val );
185         bdb->bi_dbenv->set_errcall( bdb->bi_dbenv, bdb_errcall );
186 #ifndef NO_THREADS
187         bdb->bi_dbenv->set_lk_detect( bdb->bi_dbenv, bdb->bi_lock_detect );
188 #endif
189
190 #ifdef BDB_SUBDIRS
191         {
192                 char dir[MAXPATHLEN];
193                 size_t len = strlen( bdb->bi_dbenv_home );
194
195                 strcpy( dir, bdb->bi_dbenv_home );
196                 strcat( &dir[len], BDB_TMP_SUBDIR );
197                 
198                 rc = bdb->bi_dbenv->set_tmp_dir( bdb->bi_dbenv, dir );
199                 if( rc != 0 ) {
200                         Debug( LDAP_DEBUG_ANY,
201                                 "bdb_db_open: set_tmp_dir(%s) failed: %s (%d)\n",
202                                 dir, db_strerror(rc), rc );
203                         return rc;
204                 }
205
206                 strcat( &dir[len], BDB_LG_SUBDIR );
207
208                 rc = bdb->bi_dbenv->set_lg_dir( bdb->bi_dbenv, dir );
209                 if( rc != 0 ) {
210                         Debug( LDAP_DEBUG_ANY,
211                                 "bdb_db_open: set_lg_dir(%s) failed: %s (%d)\n",
212                                 dir, db_strerror(rc), rc );
213                         return rc;
214                 }
215
216                 strcat( &dir[len], BDB_DATA_SUBDIR );
217
218                 rc = bdb->bi_dbenv->set_data_dir( bdb->bi_dbenv, dir );
219                 if( rc != 0 ) {
220                         Debug( LDAP_DEBUG_ANY,
221                                 "bdb_db_open: set_data_dir(%s) failed: %s (%d)\n",
222                                 dir, db_strerror(rc), rc );
223                         return rc;
224                 }
225         }
226 #endif
227
228         Debug( LDAP_DEBUG_TRACE,
229                 "bdb_db_open: dbenv_open(%s)\n",
230                 bdb->bi_dbenv_home, 0, 0);
231
232         rc = bdb->bi_dbenv->open( bdb->bi_dbenv,
233                 bdb->bi_dbenv_home,
234                 flags,
235                 bdb->bi_dbenv_mode );
236         if( rc != 0 ) {
237                 Debug( LDAP_DEBUG_ANY,
238                         "bdb_db_open: dbenv_open failed: %s (%d)\n",
239                         db_strerror(rc), rc, 0 );
240                 return rc;
241         }
242
243         if( bdb->bi_dbenv_xflags != 0 ) {
244                 rc = bdb->bi_dbenv->set_flags( bdb->bi_dbenv,
245                         bdb->bi_dbenv_xflags, 1);
246                 if( rc != 0 ) {
247                         Debug( LDAP_DEBUG_ANY,
248                                 "bdb_db_open: dbenv_set_flags failed: %s (%d)\n",
249                                 db_strerror(rc), rc, 0 );
250                         return rc;
251                 }
252         }
253
254         flags = DB_THREAD | DB_CREATE | bdb->bi_db_opflags;
255
256         bdb->bi_databases = (struct bdb_db_info **) ch_malloc(
257                 BDB_INDICES * sizeof(struct bdb_db_info *) );
258
259         /* open (and create) main database */
260         for( i = 0; bdbi_databases[i].name; i++ ) {
261                 struct bdb_db_info *db;
262
263                 db = (struct bdb_db_info *) ch_calloc(1, sizeof(struct bdb_db_info));
264
265                 rc = db_create( &db->bdi_db, bdb->bi_dbenv, 0 );
266                 if( rc != 0 ) {
267                         Debug( LDAP_DEBUG_ANY,
268                                 "bdb_db_open: db_create(%s) failed: %s (%d)\n",
269                                 bdb->bi_dbenv_home, db_strerror(rc), rc );
270                         return rc;
271                 }
272
273                 if( i == BDB_ID2ENTRY ) {
274                         rc = db->bdi_db->set_bt_compare( db->bdi_db,
275                                 bdb_bt_compare );
276                         rc = db->bdi_db->set_pagesize( db->bdi_db,
277                                 BDB_ID2ENTRY_PAGESIZE );
278                 } else {
279 #ifdef BDB_HIER
280                         rc = db->bdi_db->set_bt_compare( db->bdi_db,
281                                 bdb_bt_compare );
282 #elif defined(BDB_IDL_MULTI)
283                         rc = db->bdi_db->set_flags( db->bdi_db, 
284                                 DB_DUP | DB_DUPSORT );
285                         rc = db->bdi_db->set_dup_compare( db->bdi_db,
286                                 bdb_bt_compare );
287 #endif
288                         rc = db->bdi_db->set_pagesize( db->bdi_db,
289                                 BDB_PAGESIZE );
290                 }
291
292                 rc = db->bdi_db->open( db->bdi_db,
293                         bdbi_databases[i].file,
294                 /*      bdbi_databases[i].name, */ NULL,
295                         bdbi_databases[i].type,
296                         bdbi_databases[i].flags | flags,
297                         bdb->bi_dbenv_mode );
298
299                 if( rc != 0 ) {
300                         Debug( LDAP_DEBUG_ANY,
301                                 "bdb_db_open: db_open(%s) failed: %s (%d)\n",
302                                 bdb->bi_dbenv_home, db_strerror(rc), rc );
303                         return rc;
304                 }
305
306                 db->bdi_name = bdbi_databases[i].name;
307                 bdb->bi_databases[i] = db;
308         }
309
310         bdb->bi_databases[i] = NULL;
311         bdb->bi_ndatabases = i;
312
313         /* get nextid */
314         rc = bdb_last_id( be, NULL );
315         if( rc != 0 ) {
316                 Debug( LDAP_DEBUG_ANY,
317                         "bdb_db_open: last_id(%s) failed: %s (%d)\n",
318                         bdb->bi_dbenv_home, db_strerror(rc), rc );
319                 return rc;
320         }
321
322         /* <insert> open (and create) index databases */
323 #ifdef BDB_HIER
324         rc = bdb_build_tree( be );
325 #endif
326
327 #if 0 /* ifndef NO_THREADS */
328         if( bdb->bi_lock_detect != DB_LOCK_NORUN ) {
329                 /* listener as a separate THREAD */
330                 rc = ldap_pvt_thread_create( &bdb->bi_lock_detect_tid,
331                         1, lock_detect_task, bdb );
332         }
333 #endif
334         return 0;
335 }
336
337 static int
338 bdb_db_close( BackendDB *be )
339 {
340         int rc;
341         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
342         struct bdb_db_info *db;
343
344         while( bdb->bi_ndatabases-- ) {
345                 db = bdb->bi_databases[bdb->bi_ndatabases];
346                 rc = db->bdi_db->close( db->bdi_db, 0 );
347                 /* Lower numbered names are not strdup'd */
348                 if( bdb->bi_ndatabases >= BDB_NDB )
349                         free( db->bdi_name );
350                 free( db );
351         }
352         free( bdb->bi_databases );
353         bdb_attr_index_destroy( bdb->bi_attrs );
354
355         bdb_cache_release_all (&bdb->bi_cache);
356
357         return 0;
358 }
359
360 static int
361 bdb_db_destroy( BackendDB *be )
362 {
363         int rc;
364         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
365
366         /* close db environment */
367         if( bdb->bi_dbenv ) {
368                 /* force a checkpoint */
369                 if( bdb->bi_txn ) {
370                         rc = TXN_CHECKPOINT( bdb->bi_dbenv, 0, 0, DB_FORCE );
371                         if( rc != 0 ) {
372                                 Debug( LDAP_DEBUG_ANY,
373                                         "bdb_db_destroy: txn_checkpoint failed: %s (%d)\n",
374                                         db_strerror(rc), rc, 0 );
375                         }
376                 }
377
378                 bdb_cache_release_all (&bdb->bi_cache);
379
380                 rc = bdb->bi_dbenv->close( bdb->bi_dbenv, 0 );
381                 bdb->bi_dbenv = NULL;
382                 if( rc != 0 ) {
383                         Debug( LDAP_DEBUG_ANY,
384                                 "bdb_db_destroy: close failed: %s (%d)\n",
385                                 db_strerror(rc), rc, 0 );
386                         return rc;
387                 }
388         }
389
390         return 0;
391 }
392
393 #ifdef SLAPD_BDB_DYNAMIC
394 int back_bdb_LTX_init_module( int argc, char *argv[] ) {
395         BackendInfo bi;
396
397         memset( &bi, '\0', sizeof(bi) );
398         bi.bi_type = "bdb";
399         bi.bi_init = bdb_initialize;
400
401         backend_add( &bi );
402         return 0;
403 }
404 #endif /* SLAPD_BDB_DYNAMIC */
405
406 int
407 bdb_initialize(
408         BackendInfo     *bi
409 )
410 {
411         static char *controls[] = {
412                 LDAP_CONTROL_MANAGEDSAIT,
413                 LDAP_CONTROL_SUBENTRIES,
414                 NULL
415         };
416
417         {       /* version check */
418                 int major, minor, patch;
419                 char *version = db_version( &major, &minor, &patch );
420
421                 if( major != DB_VERSION_MAJOR ||
422                         minor != DB_VERSION_MINOR ||
423                         patch < DB_VERSION_PATCH )
424                 {
425                         Debug( LDAP_DEBUG_ANY,
426                                 "bi_back_initialize: version mismatch\n"
427                                 "\texpected: " DB_VERSION_STRING "\n"
428                                 "\tgot: %s \n", version, 0, 0 );
429                 }
430
431                 Debug( LDAP_DEBUG_ANY, "bdb_initialize: %s\n",
432                         version, 0, 0 );
433         }
434
435 #if 0
436         db_env_set_func_malloc( ch_malloc );
437         db_env_set_func_realloc( ch_realloc );
438         db_env_set_func_free( ch_free );
439 #endif
440
441         db_env_set_func_yield( ldap_pvt_thread_yield );
442
443         bi->bi_controls = controls;
444
445         bi->bi_open = 0;
446         bi->bi_close = 0;
447         bi->bi_config = 0;
448         bi->bi_destroy = 0;
449
450         bi->bi_db_init = bdb_db_init;
451         bi->bi_db_config = bdb_db_config;
452         bi->bi_db_open = bdb_db_open;
453         bi->bi_db_close = bdb_db_close;
454         bi->bi_db_destroy = bdb_db_destroy;
455
456         bi->bi_op_add = bdb_add;
457         bi->bi_op_bind = bdb_bind;
458         bi->bi_op_compare = bdb_compare;
459         bi->bi_op_delete = bdb_delete;
460         bi->bi_op_modify = bdb_modify;
461         bi->bi_op_modrdn = bdb_modrdn;
462         bi->bi_op_search = bdb_search;
463
464         bi->bi_op_unbind = 0;
465         bi->bi_op_abandon = 0;
466
467         bi->bi_extended = bdb_extended;
468
469 #if 0
470         /*
471          * these routines (and their callers) are not yet designed
472          * to work with transaction.  Using them may cause deadlock.
473          */
474         bi->bi_acl_group = bdb_group;
475         bi->bi_acl_attribute = bdb_attribute;
476 #else
477         bi->bi_acl_group = 0;
478         bi->bi_acl_attribute = 0;
479 #endif
480
481         bi->bi_chk_referrals = bdb_referrals;
482         bi->bi_entry_release_rw = bdb_entry_release;
483
484         /*
485          * hooks for slap tools
486          */
487         bi->bi_tool_entry_open = bdb_tool_entry_open;
488         bi->bi_tool_entry_close = bdb_tool_entry_close;
489         bi->bi_tool_entry_first = bdb_tool_entry_next;
490         bi->bi_tool_entry_next = bdb_tool_entry_next;
491         bi->bi_tool_entry_get = bdb_tool_entry_get;
492         bi->bi_tool_entry_put = bdb_tool_entry_put;
493         bi->bi_tool_entry_reindex = bdb_tool_entry_reindex;
494         bi->bi_tool_sync = 0;
495
496         bi->bi_connection_init = 0;
497         bi->bi_connection_destroy = 0;
498
499         return 0;
500 }