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