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