]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb2/txn.c
slap_set_time() is no longer necessary.
[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
320                 Debug( LDAP_DEBUG_ANY,
321         "bdb2i_check_additional_attr_index(): ERROR while opening datadir: %s\n",
322                                 strerror( errno ), 0, 0 );
323                 return( 1 );
324
325         }
326
327         for ( file = readdir( datadir ); file; file = readdir( datadir )) {
328                 char  filename[MAXPATHLEN];
329                 int   namelen;
330
331                 strcpy( filename, file->d_name );
332                 namelen = strlen( filename );
333
334                 if ( namelen > strlen( BDB2_SUFFIX )) {
335
336                         if ( !strcasecmp( filename + namelen - strlen( BDB2_SUFFIX ),
337                                                         BDB2_SUFFIX )) {
338
339                                 *(filename + namelen - strlen( BDB2_SUFFIX )) = '\0';
340                                 bdb2i_txn_attr_config( li, filename, 0 );
341
342                                 Debug( LDAP_DEBUG_TRACE, "INDEX FILE: %s\n", filename, 0, 0 );
343
344                         }
345
346                 }
347
348         }
349
350         closedir( datadir );
351
352         return 0;
353 }
354
355
356 /*  check for the addition of new attribute indexes during add  */
357 /*  this is called after startup of the slapd server  */
358 /*  DON'T WORRY ABOUT ACCESS RIGHTS, THAT MIGHT PREVENT US
359         FROM ADDING ATTRIBUTES LATER ON  */
360 void
361 bdb2i_check_default_attr_index_add( struct ldbminfo *li, Entry *e )
362 {
363         BDB2_TXN_HEAD  *head = &li->li_txn_head;
364
365         if ( head->withDefIDX == BDB2_WITH_DEF_IDX ) {
366                 Attribute   *ap;
367
368                 for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
369                         if ( strcasecmp( ap->a_type, "objectclass" ))
370                                 bdb2i_txn_attr_config( li, ap->a_type, 1 );
371                 }
372         }
373 }
374
375
376 /*  check for the addition of new attribute indexes during modify  */
377 /*  this is called after startup of the slapd server  */
378 /*  DON'T WORRY ABOUT ACCESS RIGHTS, THAT MIGHT PREVENT US
379         FROM ADDING ATTRIBUTES LATER ON  */
380 void
381 bdb2i_check_default_attr_index_mod( struct ldbminfo *li, LDAPModList *modlist )
382 {
383         BDB2_TXN_HEAD  *head = &li->li_txn_head;
384
385         if ( head->withDefIDX == BDB2_WITH_DEF_IDX ) {
386                 LDAPModList *ml;
387                 char  *default_attrs[] = { "modifytimestamp", "modifiersname", NULL };
388                 int   attr;
389
390                 for ( ml = modlist; ml != NULL; ml = ml->ml_next ) {
391                         LDAPMod *mod = &ml->ml_mod;
392
393                         if (( mod->mod_op & ~LDAP_MOD_BVALUES ) == LDAP_MOD_ADD )
394                                 if ( strcasecmp( mod->mod_type, "objectclass" ))
395                                         bdb2i_txn_attr_config( li, mod->mod_type, 1 );
396                 }
397
398                 /*  these attributes are default when modifying  */
399                 for ( attr = 0; default_attrs[attr]; attr++ ) {
400                         bdb2i_txn_attr_config( li, default_attrs[attr], 1 );
401                 }
402         }
403 }
404
405
406 /*  get the next ID from the NEXTID file  */
407 ID
408 bdb2i_get_nextid( BackendDB *be )
409 {
410         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
411         BDB2_TXN_HEAD   *head = &li->li_txn_head;
412         ID                              id;
413         Datum                   key;
414         Datum                   data;
415         db_recno_t              rec = NEXTID_RECNO;
416
417         ldbm_datum_init( key );
418         ldbm_datum_init( data );
419
420         key.data = &rec;
421         key.size = sizeof( rec );
422
423         data = bdb2i_db_fetch( head->nextidFile, key );
424         if ( data.data == NULL ) {
425                 Debug( LDAP_DEBUG_ANY,
426                         "next_id_read: could not get nextid from \"%s\"\n",
427                         NEXTID_NAME, 0, 0 );
428                 return NOID;
429         }
430
431         id = atol( data.data );
432         ldbm_datum_free( head->nextidFile, data );
433
434         if ( id < 1 ) {
435                 Debug( LDAP_DEBUG_ANY,
436                         "next_id_read %ld: return non-positive integer\n",
437                         id, 0, 0 );
438                 return NOID;
439         }
440
441         return( id );
442 }
443
444
445 int
446 bdb2i_put_nextid( BackendDB *be, ID id )
447 {
448         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
449         BDB2_TXN_HEAD   *head = &li->li_txn_head;
450         int                             rc, flags;
451         Datum                   key;
452         Datum                   data;
453         db_recno_t              rec = NEXTID_RECNO;
454         char                    buf[20];
455
456         sprintf( buf, "%ld\n", id );
457
458         ldbm_datum_init( key );
459         ldbm_datum_init( data );
460
461         key.data = &rec;
462         key.size = sizeof( rec );
463
464         data.data = &buf;
465         data.size = sizeof( buf );
466
467         flags = LDBM_REPLACE;
468         if ( li->li_dbcachewsync ) flags |= LDBM_SYNC;
469
470         if (( rc = bdb2i_db_store( head->nextidFile, key, data, flags )) != 0 ) {
471                 Debug( LDAP_DEBUG_ANY, "next_id_write(%ld): store failed (%d)\n",
472                         id, rc, 0 );
473                 return( -1 );
474         }
475
476         return( rc );
477 }
478
479
480 /*  BDB2 backend-private functions of libldbm  */
481 LDBM
482 bdb2i_db_open(
483         char *name,
484         int type,
485         int rw,
486         int mode,
487         int dbcachesize )
488 {
489         LDBM            ret = NULL;
490         DB_INFO         dbinfo;
491
492         memset( &dbinfo, 0, sizeof( dbinfo ));
493         if ( bdb2i_dbEnv.mp_info == NULL )
494                 dbinfo.db_cachesize = dbcachesize;
495         dbinfo.db_pagesize  = DEFAULT_DB_PAGE_SIZE;
496         dbinfo.db_malloc    = ldbm_malloc;
497
498         (void) db_open( name, type, rw, mode, &bdb2i_dbEnv, &dbinfo, &ret );
499
500         return( ret );
501 }
502
503
504 int
505 bdb2i_db_store( LDBM ldbm, Datum key, Datum data, int flags )
506 {
507         int     rc;
508
509         rc = (*ldbm->put)( ldbm, txnid, &key, &data, flags & ~LDBM_SYNC );
510         rc = (-1 ) * rc;
511
512         if ( txnid != NULL ) {
513
514                 /*  if the store was OK, set the dirty flag,
515                         otherwise set the abort flag  */
516                 if ( rc == 0 ) {
517
518                         txn_dirty = 1;
519
520                 } else {
521
522                         Debug( LDAP_DEBUG_ANY,
523                                 "bdb2i_db_store: transaction failed: aborted.\n",
524                                 0, 0, 0 );
525                         txn_do_abort = 1;
526
527                 }
528         }
529
530         return( rc );
531 }
532
533
534 int
535 bdb2i_db_delete( LDBM ldbm, Datum key )
536 {
537         int     rc;
538
539         rc = (*ldbm->del)( ldbm, txnid, &key, 0 );
540         rc = (-1 ) * rc;
541
542         if ( txnid != NULL ) {
543
544                 /*  if the delete was OK, set the dirty flag,
545                         otherwise set the abort flag  */
546                 if ( rc == 0 ) {
547
548                         txn_dirty = 1;
549
550                 } else {
551
552                         Debug( LDAP_DEBUG_ANY,
553                                 "bdb2i_db_delete: transaction failed: aborted.\n",
554                                 0, 0, 0 );
555                         txn_do_abort = 1;
556
557                 }
558         }
559
560         return( rc );
561 }
562
563
564 Datum
565 bdb2i_db_fetch( LDBM ldbm, Datum key )
566 {
567         Datum   data;
568         int     rc;
569
570         ldbm_datum_init( data );
571         data.flags = DB_DBT_MALLOC;
572
573         if ( (rc = (*ldbm->get)( ldbm, txnid, &key, &data, 0 )) != 0 ) {
574                 if (( txnid != NULL ) && ( rc != DB_NOTFOUND )) {
575
576                         Debug( LDAP_DEBUG_ANY,
577                                 "bdb2i_db_fetch: transaction failed: aborted.\n",
578                                 0, 0, 0 );
579                         txn_do_abort = 1;
580
581                 }
582                 if ( data.dptr ) free( data.dptr );
583                 data.dptr = NULL;
584                 data.dsize = 0;
585         }
586
587         return( data );
588 }
589
590
591 Datum
592 bdb2i_db_firstkey( LDBM ldbm, DBC **dbch )
593 {
594         Datum   key, data;
595         int             rc;
596         DBC             *dbci;
597
598         ldbm_datum_init( key );
599         ldbm_datum_init( data );
600
601         key.flags = data.flags = DB_DBT_MALLOC;
602
603 #if defined( DB_VERSION_MAJOR ) && defined( DB_VERSION_MINOR ) && \
604    DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6
605
606         if ( (*ldbm->cursor)( ldbm, txnid, &dbci ))
607
608 #else
609
610         if ( (*ldbm->cursor)( ldbm, txnid, &dbci, 0 ))
611
612 #endif
613         {
614                 if ( txnid != NULL ) {
615
616                         Debug( LDAP_DEBUG_ANY,
617                                 "bdb2i_db_firstkey: transaction failed: aborted.\n",
618                                 0, 0, 0 );
619                         txn_do_abort = 1;
620
621                 }
622                 key.flags = 0;
623                 return( key );
624         } else {
625                 *dbch = dbci;
626                 if ( (*dbci->c_get)( dbci, &key, &data, DB_NEXT ) == 0 ) {
627                         ldbm_datum_free( ldbm, data );
628                 } else {
629                         if ( txnid != NULL ) {
630
631                                 Debug( LDAP_DEBUG_ANY,
632                                         "bdb2i_db_firstkey: transaction failed: aborted.\n",
633                                         0, 0, 0 );
634                                 txn_do_abort = 1;
635
636                         }
637                         ldbm_datum_free( ldbm, key );
638                         key.flags = 0;
639                         key.dptr = NULL;
640                         key.dsize = 0;
641                 }
642         }
643
644         return( key );
645 }
646
647
648 Datum
649 bdb2i_db_nextkey( LDBM ldbm, Datum key, DBC *dbcp )
650 {
651         Datum   data;
652         int             rc;
653
654         ldbm_datum_init( data );
655         key.flags = data.flags = DB_DBT_MALLOC;
656
657         if ( (*dbcp->c_get)( dbcp, &key, &data, DB_NEXT ) == 0 ) {
658                 ldbm_datum_free( ldbm, data );
659         } else {
660                 if ( txnid != NULL ) {
661
662                         Debug( LDAP_DEBUG_ANY,
663                                 "bdb2i_db_nextkey: transaction failed: aborted.\n",
664                                 0, 0, 0 );
665                         txn_do_abort = 1;
666
667                 }
668                 key.flags = 0;
669                 key.dptr = NULL;
670                 key.dsize = 0;
671         }
672
673         return( key );
674 }
675
676
677 /*  Transaction control of write access  */
678 /*  Since these functions are only used by one writer at a time,
679         we do not have any concurrency (locking) problem  */
680
681 /*  initialize a new transaction  */
682 int
683 bdb2i_start_transction( DB_TXNMGR *txmgr )
684 {
685         int             rc;
686
687         txnid        = NULL;
688         txn_do_abort = 0;
689
690         if (( rc = txn_begin( txmgr, NULL, &txnid )) != 0 ) {
691                 Debug( LDAP_DEBUG_ANY, "bdb2i_start_transction failed: %d: errno=%s\n",
692                                         rc, strerror( errno ), 0 );
693
694                 if ( txnid != NULL )
695                         (void) txn_abort( txnid );
696                 return( -1 );
697         }
698
699         Debug( LDAP_DEBUG_TRACE,
700                         "bdb2i_start_transaction: transaction started.\n",
701                         0, 0, 0 );
702
703         return( 0 );
704 }
705
706
707 /*  finish the transaction  */
708 int
709 bdb2i_finish_transaction()
710 {
711         int             rc = 0;
712
713         /*  if transaction was NOT selected, just return  */
714         if ( txnid == NULL ) return( 0 );
715
716         /*  if nothing was wrong so far, we can try to commit the transaction  */
717         /*  complain, if the commit fails  */
718         if (( txn_do_abort == 0 ) && ( txn_commit( txnid )) != 0 ) {
719                 Debug( LDAP_DEBUG_ANY,
720                         "bdb2i_finish_transaction: transaction commit failed: aborted.\n",
721                         0, 0, 0 );
722                 txn_do_abort = 1;
723         }
724
725         /*  if anything went wrong, we have to abort the transaction  */
726         if ( txn_do_abort ) {
727                 Debug( LDAP_DEBUG_ANY,
728                         "bdb2i_finish_transaction: transaction aborted.\n",
729                         0, 0, 0 );
730                 (void) txn_abort( txnid );
731                 rc = -1;
732         } else {
733                 Debug( LDAP_DEBUG_TRACE,
734                         "bdb2i_finish_transaction: transaction commited.\n",
735                         0, 0, 0 );
736         }
737
738         /*  XXX do NOT free the txnid memory !!!  */
739         txnid        = NULL;
740         txn_do_abort = 0;
741
742         return( rc );
743 }
744
745
746 /*  set a checkpoint
747         either forced (during shutdown) or when logsize or time are exceeded
748         (is called by reader and writer, so protect txn_dirty)
749 */
750 int
751 bdb2i_set_txn_checkpoint( DB_TXNMGR *txmgr, int forced )
752 {
753         int   rc = 0;
754
755         /*  set dirty mutex  */
756         ldap_pvt_thread_mutex_lock( &txn_dirty_mutex );
757
758         if ( txn_dirty ) {
759                 int  rc;
760                 u_int32_t   logsize;
761                 u_int32_t   mins;
762                 time_t      now;
763
764                 logsize = forced ? (u_int32_t) 0 : txn_max_pending_log;
765                 mins    = forced ? (u_int32_t) 0 : txn_max_pending_time;
766
767                 now = slap_get_time();
768
769                 rc = txn_checkpoint( txmgr, logsize, mins );
770
771                 /*  if checkpointing was successful, reset txn_dirty  */
772                 if ( rc == 0 ) {
773                         DB_TXN_STAT  *statp = NULL;
774
775                         /*  check whether the checkpoint was actually written;
776                                 if so, unset the txn_dirty flag  */
777                         if (( rc = txn_stat( txmgr, &statp, ldbm_malloc )) == 0 ) {
778
779                                 if ( statp && ( statp->st_time_ckp >= now )) {
780
781                                         Debug( LDAP_DEBUG_TRACE,
782                                                 "bdb2i_set_txn_checkpoint succeded.\n",
783                                                 0, 0, 0 );
784                                         txn_dirty = 0;
785
786                                 }
787
788                                 if ( statp ) free( statp );
789
790                         } else {
791                                 Debug( LDAP_DEBUG_ANY,
792                                                 "bdb2i_set_txn_checkpoint: txn_stat failed: %d\n",
793                                                 rc, 0, 0 );
794                         }
795                 } else {
796                         Debug( LDAP_DEBUG_ANY, "bdb2i_set_txn_checkpoint failed: %d\n",
797                                         rc, 0, 0 );
798                 }
799         }
800
801         /*  release dirty mutex  */
802         ldap_pvt_thread_mutex_unlock( &txn_dirty_mutex );
803
804         return( rc );
805 }
806
807