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