]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb2/txn.c
More errno handling changes for FreeBSD LinuxThreads.
[openldap] / servers / slapd / back-bdb2 / txn.c
1 /* txn.c - TP support functions of the bdb2 backend */
2
3 #include "txn.h"
4
5
6 int
7 bdb2i_txn_head_init( BDB2_TXN_HEAD *head )
8 {
9         int             dbFile;
10         BDB2_TXN_FILES  **fileNodeH;
11
12         /*  for each fixed DB file allocate a file descriptor node and
13         initialize the file's name  */
14         fileNodeH = &head->dbFiles;
15         for ( dbFile = BDB2_DB_DN_FILE; dbFile <= BDB2_DB_OC_IDX_FILE; dbFile++ ) {
16
17                 char fileName[MAXPATHLEN];
18
19                 *fileNodeH = (BDB2_TXN_FILES *) ch_calloc( 1, sizeof( BDB2_TXN_FILES ));
20                 if ( *fileNodeH == NULL ) {
21
22                         Debug( LDAP_DEBUG_ANY, "bdb2i_txn_head_init(): out of memory!\n",
23                                         0, 0, 0 );
24                         return( 1 );
25
26                 }
27
28                 sprintf( fileName, "%s%s", bdb2i_fixed_filenames[dbFile], BDB2_SUFFIX );
29                 (*fileNodeH)->dbc_name = ch_strdup( fileName );
30
31                 fileNodeH = &(*fileNodeH)->next;
32
33         }
34
35         /*  set defaults for checkpointing  */
36         head->txn_log  = BDB2_TXN_CHKP_MAX_LOG;
37         head->txn_time = BDB2_TXN_CHKP_MAX_TIME;
38
39         /*  initialize the txn_dirty_mutex  */
40         ldap_pvt_thread_mutex_init( &txn_dirty_mutex );
41
42         return 0;
43 }
44
45
46 static void
47 bdb2i_init_db_file_cache( struct ldbminfo *li, BDB2_TXN_FILES *fileinfo )
48 {
49         struct stat st;
50         char        buf[MAXPATHLEN];
51
52         fileinfo->dbc_refcnt = 1;
53
54         sprintf( buf, "%s%s%s", li->li_directory, DEFAULT_DIRSEP,
55                                         fileinfo->dbc_name );
56         if ( stat( buf, &st ) == 0 ) {
57                 fileinfo->dbc_blksize = st.st_blksize;
58         } else {
59                 fileinfo->dbc_blksize = DEFAULT_BLOCKSIZE;
60         }
61
62         fileinfo->dbc_maxids = ( fileinfo->dbc_blksize / sizeof( ID )) -
63                         ID_BLOCK_IDS_OFFSET;
64         fileinfo->dbc_maxindirect = ( SLAPD_LDBM_MIN_MAXIDS /
65                 fileinfo->dbc_maxids ) + 1;
66
67 }
68
69
70 /*  create a DB file cache entry for a specified index attribute
71         (if not already done); the function is called during config
72         file read for all index'ed attributes; if "default" index with
73         a non-none selection is given, this is remembered for run-time
74         extension of the list of index files; the function is also
75         called before add or modify operations to check for putative
76         new "default" index files; at that time, files are also opened
77 */
78 void
79 bdb2i_txn_attr_config(
80         struct ldbminfo  *li,
81         char             *attr,
82         int              open )
83 {
84         BDB2_TXN_HEAD  *head = &li->li_txn_head;
85
86         /*  the "attribute" 'default' is special  */
87         if ( strcasecmp( attr, "default" )) {
88
89                 /*  create a new index file node, if the index is not known  already  */
90                 BDB2_TXN_FILES  **fileNodeH;
91                 char            fileName[MAXPATHLEN];
92
93                 sprintf( fileName, "%s%s", attr,  BDB2_SUFFIX );
94
95                 /*  search for the end of the list or a node describing
96                         the current attribute  */
97                 for ( fileNodeH = &head->dbFiles;
98                                 ( *fileNodeH && strcasecmp( (*fileNodeH)->dbc_name, fileName ));
99                                 fileNodeH = &(*fileNodeH)->next ) {
100
101                 }
102
103                 /*  unless we have that attribute already...  */
104                 if ( *fileNodeH == NULL ) {
105                         BDB2_TXN_FILES *p;
106
107                         Debug( LDAP_DEBUG_TRACE,
108                                         "bdb2i_txn_attr_config(): adding node for \"%s\"\n",
109                                         fileName, 0, 0 );
110
111                         /*  if we're out of memory, we have to see, how to exit...  */
112                         if ( ( *fileNodeH = p = (BDB2_TXN_FILES *)
113                                         ch_calloc( 1, sizeof( BDB2_TXN_FILES )) ) == NULL ) {
114
115                                 Debug( LDAP_DEBUG_ANY,
116                                                 "bdb2i_txn_attr_config(): out of memory -- FATAL.\n",
117                                                 0, 0, 0 );
118
119                                 /*  during configuration (no files are opened)
120                                         we can just exit, otherwise we kill ourself and
121                                         hope to shutdown cleanly...  */
122                                 if ( open ) {
123                                         pthread_kill( pthread_self(), LDAP_SIGUSR1 );
124                                 } else {
125                                         exit( 1 );
126                                 }
127                         }
128
129                         p->dbc_name = ch_strdup( fileName );
130
131                         /*  if requested for, we have to open the DB file  */
132                         /*  BUT NOT "objectclass", 'cause that's a default index !  */
133                         if ( open && strcasecmp( fileName, "objectclass" )) {
134
135                                 /*  re-use filename to get the complete path  */
136                                 sprintf( fileName, "%s%s%s",
137                                                         li->li_directory, DEFAULT_DIRSEP, p->dbc_name );
138
139                                 /*  since we have an mpool, we should not define a cache size */
140                                 p->dbc_db = bdb2i_db_open( fileName, DB_TYPE,
141                                                                         LDBM_WRCREAT, li->li_mode, 0 );
142
143                                 /*  if the files could not be opened, something is wrong;
144                                         complain  */
145                                 if ( p->dbc_db == NULL ) {
146
147                                         Debug( LDAP_DEBUG_ANY,
148                                 "bdb2i_txn_open_files(): couldn't open file \"%s\" -- FATAL.\n",
149                                                 p->dbc_name, 0, 0 );
150                                         pthread_kill( pthread_self(), LDAP_SIGUSR1 );
151
152                                 }
153
154                                 bdb2i_init_db_file_cache( li, p );
155
156                                 Debug( LDAP_DEBUG_TRACE,
157                                         "bdb2i_txn_attr_config(): NEW INDEX FILE \"%s\"\n",
158                                         p->dbc_name, 0, 0 );
159
160                         }
161                 }
162
163         } else {  /*  it is "attribute" 'default'  */
164
165                 head->withDefIDX = BDB2_WITH_DEF_IDX;
166
167         }
168 }
169
170
171 /*  open the NEXTID file for read/write; if it does not exist,
172         create it (access to the file must be preceeded by a rewind)
173 */
174 static int
175 bdb2i_open_nextid( BackendDB *be )
176 {
177         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
178         BDB2_TXN_HEAD   *head = &li->li_txn_head;
179         LDBM            db = NULL;
180         DB_INFO                 dbinfo;
181         char            fileName[MAXPATHLEN];
182
183         sprintf( fileName, "%s%s%s",
184                                 li->li_directory, DEFAULT_DIRSEP, NEXTID_NAME );
185
186         /*  try to open the file for read and write  */
187         memset( &dbinfo, 0, sizeof( dbinfo ));
188         dbinfo.db_pagesize  = DEFAULT_DB_PAGE_SIZE;
189         dbinfo.db_malloc    = ldbm_malloc;
190
191         (void) db_open( fileName, DB_RECNO, DB_CREATE | DB_THREAD,
192                                         li->li_mode, &bdb2i_dbEnv, &dbinfo, &db );
193
194         if ( db == NULL ) {
195
196                         Debug( LDAP_DEBUG_ANY,
197                                 "bdb2i_open_nextid: could not open \"%s\"\n",
198                                 NEXTID_NAME, 0, 0 );
199                         return( -1 );
200
201         }
202
203         /*  the file is open for read/write  */
204         head->nextidFile = db;
205
206         return( 0 );
207 }
208
209
210 /*  open all DB during startup of the backend (necessary due to TP)
211         additional files may be opened during slapd life-time due to
212         default indexes (must be configured in slapd.conf;
213         see bdb2i_txn_attr_config)
214         also, set the counter and timer for TP checkpointing
215 */
216 int
217 bdb2i_txn_open_files( BackendDB *be )
218 {
219         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
220         BDB2_TXN_HEAD   *head = &li->li_txn_head;
221         BDB2_TXN_FILES  *dbFile;
222         int             rc;
223
224         for ( dbFile = head->dbFiles; dbFile; dbFile = dbFile->next ) {
225                 char   fileName[MAXPATHLEN];
226
227                 sprintf( fileName, "%s%s%s",
228                                         li->li_directory, DEFAULT_DIRSEP, dbFile->dbc_name );
229
230                 /*  since we have an mpool, we should not define a cache size */
231                 dbFile->dbc_db = bdb2i_db_open( fileName, DB_TYPE,
232                                                         LDBM_WRCREAT, li->li_mode, 0 );
233
234                 /*  if the files could not be opened, something is wrong; complain  */
235                 if ( dbFile->dbc_db == NULL ) {
236
237                         Debug( LDAP_DEBUG_ANY,
238                                 "bdb2i_txn_open_files(): couldn't open file \"%s\" -- FATAL.\n",
239                                 dbFile->dbc_name, 0, 0 );
240                         return( -1 );
241
242                 }
243
244                 /*  initialize the file info  */
245                 bdb2i_init_db_file_cache( li, dbFile );
246
247                 Debug( LDAP_DEBUG_TRACE, "bdb2i_txn_open_files(): OPEN INDEX \"%s\"\n",
248                                 dbFile->dbc_name, 0, 0 );
249
250         }
251
252         rc = bdb2i_open_nextid( be );
253
254         txn_max_pending_log  = head->txn_log;
255         txn_max_pending_time = head->txn_time;
256
257         return rc;
258 }
259
260
261 /*  close all DB files during shutdown of the backend  */
262 void
263 bdb2i_txn_close_files( BackendDB *be )
264 {
265         struct ldbminfo  *li = (struct ldbminfo *) be->be_private;
266         BDB2_TXN_HEAD    *head = &li->li_txn_head;
267         BDB2_TXN_FILES   *dbFile;
268
269         for ( dbFile = head->dbFiles; dbFile; dbFile = dbFile->next ) {
270
271                 ldbm_close( dbFile->dbc_db );
272
273         }
274
275         ldbm_close( head->nextidFile );
276
277 }
278
279
280 /*  get the db_cache structure associated with a specified
281         DB file (replaces the on-the-fly opening of files in cache_open()
282 */
283 BDB2_TXN_FILES *
284 bdb2i_get_db_file_cache( struct ldbminfo *li, char *name )
285 {
286         BDB2_TXN_HEAD  *head = &li->li_txn_head;
287         BDB2_TXN_FILES *dbFile;
288         int            dbFileNum;
289
290         Debug( LDAP_DEBUG_TRACE, "bdb2i_get_db_file_cache(): looking for file %s\n",
291                         name, 0, 0 );
292
293         for ( dbFile = head->dbFiles; dbFile; dbFile = dbFile->next ) {
294
295                 /*  we've got it  */
296                 if ( !strcasecmp( dbFile->dbc_name, name )) return( dbFile );
297
298         }
299
300         Debug( LDAP_DEBUG_ANY,
301                 "bdb2i_get_db_file_cache(): UPS, could't find \"%s\" \n", name, 0, 0 );
302
303         /*  ups, we couldn't find the file  */
304         return( NULL );
305
306 }
307
308
309 /*  check for new attribute indexes, that might have been created
310     during former runs of slapd  */
311 /*  this is called during startup of the slapd server  */
312 int
313 bdb2i_check_additional_attr_index( struct ldbminfo *li )
314 {
315         DIR            *datadir;
316         struct dirent  *file;
317
318         if ( ( datadir = opendir( li->li_directory ) ) == NULL ) {
319                 int err = errno;
320
321                 Debug( LDAP_DEBUG_ANY,
322         "bdb2i_check_additional_attr_index(): ERROR while opening datadir: %s\n",
323                                 strerror( err ), 0, 0 );
324                 return( 1 );
325
326         }
327
328         for ( file = readdir( datadir ); file; file = readdir( datadir )) {
329                 char  filename[MAXPATHLEN];
330                 int   namelen;
331
332                 strcpy( filename, file->d_name );
333                 namelen = strlen( filename );
334
335                 if ( namelen > strlen( BDB2_SUFFIX )) {
336
337                         if ( !strcasecmp( filename + namelen - strlen( BDB2_SUFFIX ),
338                                                         BDB2_SUFFIX )) {
339
340                                 *(filename + namelen - strlen( BDB2_SUFFIX )) = '\0';
341                                 bdb2i_txn_attr_config( li, filename, 0 );
342
343                                 Debug( LDAP_DEBUG_TRACE, "INDEX FILE: %s\n", filename, 0, 0 );
344
345                         }
346
347                 }
348
349         }
350
351         closedir( datadir );
352
353         return 0;
354 }
355
356
357 /*  check for the addition of new attribute indexes during add  */
358 /*  this is called after startup of the slapd server  */
359 /*  DON'T WORRY ABOUT ACCESS RIGHTS, THAT MIGHT PREVENT US
360         FROM ADDING ATTRIBUTES LATER ON  */
361 void
362 bdb2i_check_default_attr_index_add( struct ldbminfo *li, Entry *e )
363 {
364         BDB2_TXN_HEAD  *head = &li->li_txn_head;
365
366         if ( head->withDefIDX == BDB2_WITH_DEF_IDX ) {
367                 Attribute   *ap;
368
369                 for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
370                         if ( strcasecmp( ap->a_type, "objectclass" ))
371                                 bdb2i_txn_attr_config( li, ap->a_type, 1 );
372                 }
373         }
374 }
375
376
377 /*  check for the addition of new attribute indexes during modify  */
378 /*  this is called after startup of the slapd server  */
379 /*  DON'T WORRY ABOUT ACCESS RIGHTS, THAT MIGHT PREVENT US
380         FROM ADDING ATTRIBUTES LATER ON  */
381 void
382 bdb2i_check_default_attr_index_mod( struct ldbminfo *li, LDAPModList *modlist )
383 {
384         BDB2_TXN_HEAD  *head = &li->li_txn_head;
385
386         if ( head->withDefIDX == BDB2_WITH_DEF_IDX ) {
387                 LDAPModList *ml;
388                 char  *default_attrs[] = { "modifytimestamp", "modifiersname", NULL };
389                 int   attr;
390
391                 for ( ml = modlist; ml != NULL; ml = ml->ml_next ) {
392                         LDAPMod *mod = &ml->ml_mod;
393
394                         if (( mod->mod_op & ~LDAP_MOD_BVALUES ) == LDAP_MOD_ADD )
395                                 if ( strcasecmp( mod->mod_type, "objectclass" ))
396                                         bdb2i_txn_attr_config( li, mod->mod_type, 1 );
397                 }
398
399                 /*  these attributes are default when modifying  */
400                 for ( attr = 0; default_attrs[attr]; attr++ ) {
401                         bdb2i_txn_attr_config( li, default_attrs[attr], 1 );
402                 }
403         }
404 }
405
406
407 /*  get the next ID from the NEXTID file  */
408 ID
409 bdb2i_get_nextid( BackendDB *be )
410 {
411         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
412         BDB2_TXN_HEAD   *head = &li->li_txn_head;
413         ID                              id;
414         Datum                   key;
415         Datum                   data;
416         db_recno_t              rec = NEXTID_RECNO;
417
418         ldbm_datum_init( key );
419         ldbm_datum_init( data );
420
421         key.data = &rec;
422         key.size = sizeof( rec );
423
424         data = bdb2i_db_fetch( head->nextidFile, key );
425         if ( data.data == NULL ) {
426                 Debug( LDAP_DEBUG_ANY,
427                         "next_id_read: could not get nextid from \"%s\"\n",
428                         NEXTID_NAME, 0, 0 );
429                 return NOID;
430         }
431
432         id = atol( data.data );
433         ldbm_datum_free( head->nextidFile, data );
434
435         if ( id < 1 ) {
436                 Debug( LDAP_DEBUG_ANY,
437                         "next_id_read %ld: return non-positive integer\n",
438                         id, 0, 0 );
439                 return NOID;
440         }
441
442         return( id );
443 }
444
445
446 int
447 bdb2i_put_nextid( BackendDB *be, ID id )
448 {
449         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
450         BDB2_TXN_HEAD   *head = &li->li_txn_head;
451         int                             rc, flags;
452         Datum                   key;
453         Datum                   data;
454         db_recno_t              rec = NEXTID_RECNO;
455         char                    buf[20];
456
457         sprintf( buf, "%ld\n", id );
458
459         ldbm_datum_init( key );
460         ldbm_datum_init( data );
461
462         key.data = &rec;
463         key.size = sizeof( rec );
464
465         data.data = &buf;
466         data.size = sizeof( buf );
467
468         flags = LDBM_REPLACE;
469         if ( li->li_dbcachewsync ) flags |= LDBM_SYNC;
470
471         if (( rc = bdb2i_db_store( head->nextidFile, key, data, flags )) != 0 ) {
472                 Debug( LDAP_DEBUG_ANY, "next_id_write(%ld): store failed (%d)\n",
473                         id, rc, 0 );
474                 return( -1 );
475         }
476
477         return( rc );
478 }
479
480
481 /*  BDB2 backend-private functions of libldbm  */
482 LDBM
483 bdb2i_db_open(
484         char *name,
485         int type,
486         int rw,
487         int mode,
488         int dbcachesize )
489 {
490         LDBM            ret = NULL;
491         DB_INFO         dbinfo;
492
493         memset( &dbinfo, 0, sizeof( dbinfo ));
494         if ( bdb2i_dbEnv.mp_info == NULL )
495                 dbinfo.db_cachesize = dbcachesize;
496         dbinfo.db_pagesize  = DEFAULT_DB_PAGE_SIZE;
497         dbinfo.db_malloc    = ldbm_malloc;
498
499         (void) db_open( name, type, rw, mode, &bdb2i_dbEnv, &dbinfo, &ret );
500
501         return( ret );
502 }
503
504
505 int
506 bdb2i_db_store( LDBM ldbm, Datum key, Datum data, int flags )
507 {
508         int     rc;
509
510         rc = (*ldbm->put)( ldbm, txnid, &key, &data, flags & ~LDBM_SYNC );
511         rc = (-1 ) * rc;
512
513         if ( txnid != NULL ) {
514
515                 /*  if the store was OK, set the dirty flag,
516                         otherwise set the abort flag  */
517                 if ( rc == 0 ) {
518
519                         txn_dirty = 1;
520
521                 } else {
522
523                         Debug( LDAP_DEBUG_ANY,
524                                 "bdb2i_db_store: transaction failed: aborted.\n",
525                                 0, 0, 0 );
526                         txn_do_abort = 1;
527
528                 }
529         }
530
531         return( rc );
532 }
533
534
535 int
536 bdb2i_db_delete( LDBM ldbm, Datum key )
537 {
538         int     rc;
539
540         rc = (*ldbm->del)( ldbm, txnid, &key, 0 );
541         rc = (-1 ) * rc;
542
543         if ( txnid != NULL ) {
544
545                 /*  if the delete was OK, set the dirty flag,
546                         otherwise set the abort flag  */
547                 if ( rc == 0 ) {
548
549                         txn_dirty = 1;
550
551                 } else {
552
553                         Debug( LDAP_DEBUG_ANY,
554                                 "bdb2i_db_delete: transaction failed: aborted.\n",
555                                 0, 0, 0 );
556                         txn_do_abort = 1;
557
558                 }
559         }
560
561         return( rc );
562 }
563
564
565 Datum
566 bdb2i_db_fetch( LDBM ldbm, Datum key )
567 {
568         Datum   data;
569         int     rc;
570
571         ldbm_datum_init( data );
572         data.flags = DB_DBT_MALLOC;
573
574         if ( (rc = (*ldbm->get)( ldbm, txnid, &key, &data, 0 )) != 0 ) {
575                 if (( txnid != NULL ) && ( rc != DB_NOTFOUND )) {
576
577                         Debug( LDAP_DEBUG_ANY,
578                                 "bdb2i_db_fetch: transaction failed: aborted.\n",
579                                 0, 0, 0 );
580                         txn_do_abort = 1;
581
582                 }
583                 if ( data.dptr ) free( data.dptr );
584                 data.dptr = NULL;
585                 data.dsize = 0;
586         }
587
588         return( data );
589 }
590
591
592 Datum
593 bdb2i_db_firstkey( LDBM ldbm, DBC **dbch )
594 {
595         Datum   key, data;
596         int             rc;
597         DBC             *dbci;
598
599         ldbm_datum_init( key );
600         ldbm_datum_init( data );
601
602         key.flags = data.flags = DB_DBT_MALLOC;
603
604 #if defined( DB_VERSION_MAJOR ) && defined( DB_VERSION_MINOR ) && \
605    DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6
606
607         if ( (*ldbm->cursor)( ldbm, txnid, &dbci ))
608
609 #else
610
611         if ( (*ldbm->cursor)( ldbm, txnid, &dbci, 0 ))
612
613 #endif
614         {
615                 if ( txnid != NULL ) {
616
617                         Debug( LDAP_DEBUG_ANY,
618                                 "bdb2i_db_firstkey: transaction failed: aborted.\n",
619                                 0, 0, 0 );
620                         txn_do_abort = 1;
621
622                 }
623                 key.flags = 0;
624                 return( key );
625         } else {
626                 *dbch = dbci;
627                 if ( (*dbci->c_get)( dbci, &key, &data, DB_NEXT ) == 0 ) {
628                         ldbm_datum_free( ldbm, data );
629                 } else {
630                         if ( txnid != NULL ) {
631
632                                 Debug( LDAP_DEBUG_ANY,
633                                         "bdb2i_db_firstkey: transaction failed: aborted.\n",
634                                         0, 0, 0 );
635                                 txn_do_abort = 1;
636
637                         }
638                         ldbm_datum_free( ldbm, key );
639                         key.flags = 0;
640                         key.dptr = NULL;
641                         key.dsize = 0;
642                 }
643         }
644
645         return( key );
646 }
647
648
649 Datum
650 bdb2i_db_nextkey( LDBM ldbm, Datum key, DBC *dbcp )
651 {
652         Datum   data;
653         int             rc;
654
655         ldbm_datum_init( data );
656         ldbm_datum_free( ldbm, key );
657         key.flags = data.flags = DB_DBT_MALLOC;
658
659         if ( (*dbcp->c_get)( dbcp, &key, &data, DB_NEXT ) == 0 ) {
660                 ldbm_datum_free( ldbm, data );
661         } else {
662                 if ( txnid != NULL ) {
663
664                         Debug( LDAP_DEBUG_ANY,
665                                 "bdb2i_db_nextkey: transaction failed: aborted.\n",
666                                 0, 0, 0 );
667                         txn_do_abort = 1;
668
669                 }
670                 key.flags = 0;
671                 key.dptr = NULL;
672                 key.dsize = 0;
673         }
674
675         return( key );
676 }
677
678
679 /*  Transaction control of write access  */
680 /*  Since these functions are only used by one writer at a time,
681         we do not have any concurrency (locking) problem  */
682
683 /*  initialize a new transaction  */
684 int
685 bdb2i_start_transction( DB_TXNMGR *txmgr )
686 {
687         int             rc;
688
689         txnid        = NULL;
690         txn_do_abort = 0;
691
692         if (( rc = txn_begin( txmgr, NULL, &txnid )) != 0 ) {
693                 int err = errno;
694                 Debug( LDAP_DEBUG_ANY, "bdb2i_start_transction failed: %d: errno=%s\n",
695                                         rc, strerror( err ), 0 );
696
697                 if ( txnid != NULL )
698                         (void) txn_abort( txnid );
699                 return( -1 );
700         }
701
702         Debug( LDAP_DEBUG_TRACE,
703                         "bdb2i_start_transaction: transaction started.\n",
704                         0, 0, 0 );
705
706         return( 0 );
707 }
708
709
710 /*  finish the transaction  */
711 int
712 bdb2i_finish_transaction()
713 {
714         int             rc = 0;
715
716         /*  if transaction was NOT selected, just return  */
717         if ( txnid == NULL ) return( 0 );
718
719         /*  if nothing was wrong so far, we can try to commit the transaction  */
720         /*  complain, if the commit fails  */
721         if (( txn_do_abort == 0 ) && ( txn_commit( txnid )) != 0 ) {
722                 Debug( LDAP_DEBUG_ANY,
723                         "bdb2i_finish_transaction: transaction commit failed: aborted.\n",
724                         0, 0, 0 );
725                 txn_do_abort = 1;
726         }
727
728         /*  if anything went wrong, we have to abort the transaction  */
729         if ( txn_do_abort ) {
730                 Debug( LDAP_DEBUG_ANY,
731                         "bdb2i_finish_transaction: transaction aborted.\n",
732                         0, 0, 0 );
733                 (void) txn_abort( txnid );
734                 rc = -1;
735         } else {
736                 Debug( LDAP_DEBUG_TRACE,
737                         "bdb2i_finish_transaction: transaction commited.\n",
738                         0, 0, 0 );
739         }
740
741         /*  XXX do NOT free the txnid memory !!!  */
742         txnid        = NULL;
743         txn_do_abort = 0;
744
745         return( rc );
746 }
747
748
749 /*  set a checkpoint
750         either forced (during shutdown) or when logsize or time are exceeded
751         (is called by reader and writer, so protect txn_dirty)
752 */
753 int
754 bdb2i_set_txn_checkpoint( DB_TXNMGR *txmgr, int forced )
755 {
756         int   rc = 0;
757
758         /*  set dirty mutex  */
759         ldap_pvt_thread_mutex_lock( &txn_dirty_mutex );
760
761         if ( txn_dirty ) {
762                 int  rc;
763                 u_int32_t   logsize;
764                 u_int32_t   mins;
765                 time_t      now;
766
767                 logsize = forced ? (u_int32_t) 0 : txn_max_pending_log;
768                 mins    = forced ? (u_int32_t) 0 : txn_max_pending_time;
769
770                 now = slap_get_time();
771
772                 rc = txn_checkpoint( txmgr, logsize, mins );
773
774                 /*  if checkpointing was successful, reset txn_dirty  */
775                 if ( rc == 0 ) {
776                         DB_TXN_STAT  *statp = NULL;
777
778                         /*  check whether the checkpoint was actually written;
779                                 if so, unset the txn_dirty flag  */
780                         if (( rc = txn_stat( txmgr, &statp, ldbm_malloc )) == 0 ) {
781
782                                 if ( statp && ( statp->st_time_ckp >= now )) {
783
784                                         Debug( LDAP_DEBUG_TRACE,
785                                                 "bdb2i_set_txn_checkpoint succeded.\n",
786                                                 0, 0, 0 );
787                                         txn_dirty = 0;
788
789                                 }
790
791                                 if ( statp ) free( statp );
792
793                         } else {
794                                 Debug( LDAP_DEBUG_ANY,
795                                                 "bdb2i_set_txn_checkpoint: txn_stat failed: %d\n",
796                                                 rc, 0, 0 );
797                         }
798                 } else {
799                         Debug( LDAP_DEBUG_ANY, "bdb2i_set_txn_checkpoint failed: %d\n",
800                                         rc, 0, 0 );
801                 }
802         }
803
804         /*  release dirty mutex  */
805         ldap_pvt_thread_mutex_unlock( &txn_dirty_mutex );
806
807         return( rc );
808 }
809
810