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