]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb2/txn.c
Use #ifdef, not #if
[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 (( rc = bdb2i_db_store( head->nextidFile, key, data, flags )) != 0 ) {
485                 Debug( LDAP_DEBUG_ANY, "next_id_write(%ld): store failed (%d)\n",
486                         id, rc, 0 );
487                 return( -1 );
488         }
489
490         return( rc );
491 }
492
493
494 /*  BDB2 backend-private functions of libldbm  */
495 LDBM
496 bdb2i_db_open(
497         char *name,
498         int type,
499         int rw,
500         int mode,
501         int dbcachesize )
502 {
503         LDBM            ret = NULL;
504         DB_INFO         dbinfo;
505
506         memset( &dbinfo, 0, sizeof( dbinfo ));
507         if ( bdb2i_dbEnv.mp_info == NULL )
508                 dbinfo.db_cachesize = dbcachesize;
509         dbinfo.db_pagesize  = DEFAULT_DB_PAGE_SIZE;
510         dbinfo.db_malloc    = ldbm_malloc;
511
512         (void) db_open( name, type, rw, mode, &bdb2i_dbEnv, &dbinfo, &ret );
513
514         return( ret );
515 }
516
517
518 int
519 bdb2i_db_store( LDBM ldbm, Datum key, Datum data, int flags )
520 {
521         int     rc;
522
523         rc = (*ldbm->put)( ldbm, txnid, &key, &data, flags );
524         rc = (-1 ) * rc;
525
526         if ( txnid != NULL ) {
527
528                 /*  if the store was OK, set the dirty flag,
529                         otherwise set the abort flag  */
530                 if ( rc == 0 ) {
531
532                         txn_dirty = 1;
533
534                 } else {
535
536                         Debug( LDAP_DEBUG_ANY,
537                                 "bdb2i_db_store: transaction failed: aborted.\n",
538                                 0, 0, 0 );
539                         txn_do_abort = 1;
540
541                 }
542         }
543
544         return( rc );
545 }
546
547
548 int
549 bdb2i_db_delete( LDBM ldbm, Datum key )
550 {
551         int     rc;
552
553         rc = (*ldbm->del)( ldbm, txnid, &key, 0 );
554         rc = (-1 ) * rc;
555
556         if ( txnid != NULL ) {
557
558                 /*  if the delete was OK, set the dirty flag,
559                         otherwise set the abort flag  */
560                 if ( rc == 0 ) {
561
562                         txn_dirty = 1;
563
564                 } else {
565
566                         Debug( LDAP_DEBUG_ANY,
567                                 "bdb2i_db_delete: transaction failed: aborted.\n",
568                                 0, 0, 0 );
569                         txn_do_abort = 1;
570
571                 }
572         }
573
574         return( rc );
575 }
576
577
578 Datum
579 bdb2i_db_fetch( LDBM ldbm, Datum key )
580 {
581         Datum   data;
582         int     rc;
583
584         ldbm_datum_init( data );
585         data.flags = DB_DBT_MALLOC;
586
587         if ( (rc = (*ldbm->get)( ldbm, txnid, &key, &data, 0 )) != 0 ) {
588                 if (( txnid != NULL ) && ( rc != DB_NOTFOUND )) {
589
590                         Debug( LDAP_DEBUG_ANY,
591                                 "bdb2i_db_fetch: transaction failed: aborted.\n",
592                                 0, 0, 0 );
593                         txn_do_abort = 1;
594
595                 }
596                 if ( data.dptr ) free( data.dptr );
597                 data.dptr = NULL;
598                 data.dsize = 0;
599         }
600
601         return( data );
602 }
603
604
605 Datum
606 bdb2i_db_firstkey( LDBM ldbm, DBC **dbch )
607 {
608         Datum   key, data;
609         int             rc;
610         DBC             *dbci;
611
612         ldbm_datum_init( key );
613         ldbm_datum_init( data );
614
615         key.flags = data.flags = DB_DBT_MALLOC;
616
617 #if defined( DB_VERSION_MAJOR ) && defined( DB_VERSION_MINOR ) && \
618    DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6
619
620         if ( (*ldbm->cursor)( ldbm, txnid, &dbci ))
621
622 #else
623
624         if ( (*ldbm->cursor)( ldbm, txnid, &dbci, 0 ))
625
626 #endif
627         {
628                 if ( txnid != NULL ) {
629
630                         Debug( LDAP_DEBUG_ANY,
631                                 "bdb2i_db_firstkey: transaction failed: aborted.\n",
632                                 0, 0, 0 );
633                         txn_do_abort = 1;
634
635                 }
636                 key.flags = 0;
637                 return( key );
638         } else {
639                 *dbch = dbci;
640                 if ( (*dbci->c_get)( dbci, &key, &data, DB_NEXT ) == 0 ) {
641                         ldbm_datum_free( ldbm, data );
642                 } else {
643                         if ( txnid != NULL ) {
644
645                                 Debug( LDAP_DEBUG_ANY,
646                                         "bdb2i_db_firstkey: transaction failed: aborted.\n",
647                                         0, 0, 0 );
648                                 txn_do_abort = 1;
649
650                         }
651                         ldbm_datum_free( ldbm, key );
652                         key.flags = 0;
653                         key.dptr = NULL;
654                         key.dsize = 0;
655                 }
656         }
657
658         return( key );
659 }
660
661
662 Datum
663 bdb2i_db_nextkey( LDBM ldbm, Datum key, DBC *dbcp )
664 {
665         Datum   data;
666         int             rc;
667
668         ldbm_datum_init( data );
669         ldbm_datum_free( ldbm, key );
670         key.flags = data.flags = DB_DBT_MALLOC;
671
672         if ( (*dbcp->c_get)( dbcp, &key, &data, DB_NEXT ) == 0 ) {
673                 ldbm_datum_free( ldbm, data );
674         } else {
675                 if ( txnid != NULL ) {
676
677                         Debug( LDAP_DEBUG_ANY,
678                                 "bdb2i_db_nextkey: transaction failed: aborted.\n",
679                                 0, 0, 0 );
680                         txn_do_abort = 1;
681
682                 }
683                 key.flags = 0;
684                 key.dptr = NULL;
685                 key.dsize = 0;
686         }
687
688         return( key );
689 }
690
691
692 /*  Transaction control of write access  */
693 /*  Since these functions are only used by one writer at a time,
694         we do not have any concurrency (locking) problem  */
695
696 /*  initialize a new transaction  */
697 int
698 bdb2i_start_transction( DB_TXNMGR *txmgr )
699 {
700         int             rc;
701
702         txnid        = NULL;
703         txn_do_abort = 0;
704
705         if (( rc = txn_begin( txmgr, NULL, &txnid )) != 0 ) {
706                 int err = errno;
707                 Debug( LDAP_DEBUG_ANY, "bdb2i_start_transction failed: %d: errno=%s\n",
708                                         rc, strerror( err ), 0 );
709
710                 if ( txnid != NULL )
711                         (void) txn_abort( txnid );
712                 return( -1 );
713         }
714
715         Debug( LDAP_DEBUG_TRACE,
716                         "bdb2i_start_transaction: transaction started.\n",
717                         0, 0, 0 );
718
719         return( 0 );
720 }
721
722
723 /*  finish the transaction  */
724 int
725 bdb2i_finish_transaction()
726 {
727         int             rc = 0;
728
729         /*  if transaction was NOT selected, just return  */
730         if ( txnid == NULL ) return( 0 );
731
732         /*  if nothing was wrong so far, we can try to commit the transaction  */
733         /*  complain, if the commit fails  */
734         if (( txn_do_abort == 0 ) && ( txn_commit( txnid )) != 0 ) {
735                 Debug( LDAP_DEBUG_ANY,
736                         "bdb2i_finish_transaction: transaction commit failed: aborted.\n",
737                         0, 0, 0 );
738                 txn_do_abort = 1;
739         }
740
741         /*  if anything went wrong, we have to abort the transaction  */
742         if ( txn_do_abort ) {
743                 Debug( LDAP_DEBUG_ANY,
744                         "bdb2i_finish_transaction: transaction aborted.\n",
745                         0, 0, 0 );
746                 (void) txn_abort( txnid );
747                 rc = -1;
748         } else {
749                 Debug( LDAP_DEBUG_TRACE,
750                         "bdb2i_finish_transaction: transaction commited.\n",
751                         0, 0, 0 );
752         }
753
754         /*  XXX do NOT free the txnid memory !!!  */
755         txnid        = NULL;
756         txn_do_abort = 0;
757
758         return( rc );
759 }
760
761
762 /*  set a checkpoint
763         either forced (during shutdown) or when logsize or time are exceeded
764         (is called by reader and writer, so protect txn_dirty)
765 */
766 int
767 bdb2i_set_txn_checkpoint( DB_TXNMGR *txmgr, int forced )
768 {
769         int   rc = 0;
770
771         /*  set dirty mutex  */
772         ldap_pvt_thread_mutex_lock( &txn_dirty_mutex );
773
774         if ( txn_dirty ) {
775                 int  rc;
776                 u_int32_t   logsize;
777                 u_int32_t   mins;
778                 time_t      now;
779
780                 logsize = forced ? (u_int32_t) 0 : txn_max_pending_log;
781                 mins    = forced ? (u_int32_t) 0 : txn_max_pending_time;
782
783                 now = slap_get_time();
784
785                 rc = txn_checkpoint( txmgr, logsize, mins );
786
787                 /*  if checkpointing was successful, reset txn_dirty  */
788                 if ( rc == 0 ) {
789                         DB_TXN_STAT  *statp = NULL;
790
791                         /*  check whether the checkpoint was actually written;
792                                 if so, unset the txn_dirty flag  */
793                         if (( rc = txn_stat( txmgr, &statp, ldbm_malloc )) == 0 ) {
794
795                                 if ( statp && ( statp->st_time_ckp >= now )) {
796
797                                         Debug( LDAP_DEBUG_TRACE,
798                                                 "bdb2i_set_txn_checkpoint succeded.\n",
799                                                 0, 0, 0 );
800                                         txn_dirty = 0;
801
802                                 }
803
804                                 if ( statp ) free( statp );
805
806                         } else {
807                                 Debug( LDAP_DEBUG_ANY,
808                                                 "bdb2i_set_txn_checkpoint: txn_stat failed: %d\n",
809                                                 rc, 0, 0 );
810                         }
811                 } else {
812                         Debug( LDAP_DEBUG_ANY, "bdb2i_set_txn_checkpoint failed: %d\n",
813                                         rc, 0, 0 );
814                 }
815         }
816
817         /*  release dirty mutex  */
818         ldap_pvt_thread_mutex_unlock( &txn_dirty_mutex );
819
820         return( rc );
821 }
822
823