fsync/msync calls are made.
- if TDB_ALLOW_NESTING is passed to flags in tdb open, or added using
- tdb_add_flags() transaction is enabled.
- The default is that transaction nesting is not allowed and an attempt
- to create a nested transaction will fail with TDB_ERR_NESTING.
+ tdb_add_flags() transaction nesting is enabled.
+ It resets the TDB_DISALLOW_NESTING flag, as both cannot be used together.
+ The default is that transaction nesting is allowed.
+ Note: this default may change in future versions of tdb.
Beware. when transactions are nested a transaction successfully
completed with tdb_transaction_commit() can be silently unrolled later.
+
+ - if TDB_DISALLOW_NESTING is passed to flags in tdb open, or added using
+ tdb_add_flags() transaction nesting is disabled.
+ It resets the TDB_ALLOW_NESTING flag, as both cannot be used together.
+ An attempt create a nested transaction will fail with TDB_ERR_NESTING.
+ The default is that transaction nesting is allowed.
+ Note: this default may change in future versions of tdb.
*/
bool prepared;
tdb_off_t magic_offset;
+ /* set when the GLOBAL_LOCK has been taken */
+ bool global_lock_taken;
+
/* old file size before transaction */
tdb_len_t old_map_size;
}
}
+ if (tdb->transaction->global_lock_taken) {
+ tdb_brunlock(tdb, F_WRLCK, GLOBAL_LOCK, 1);
+ tdb->transaction->global_lock_taken = false;
+ }
+
/* remove any global lock created during the transaction */
if (tdb->global_lock.count != 0) {
tdb_brunlock(tdb, tdb->global_lock.ltype,
tdb_off_t *recovery_offset,
tdb_len_t *recovery_max_size)
{
- struct list_struct rec;
+ struct tdb_record rec;
const struct tdb_methods *methods = tdb->transaction->io_methods;
tdb_off_t recovery_head;
tdb_len_t recovery_size;
unsigned char *data, *p;
const struct tdb_methods *methods = tdb->transaction->io_methods;
- struct list_struct *rec;
+ struct tdb_record *rec;
tdb_off_t recovery_offset, recovery_max_size;
tdb_off_t old_map_size = tdb->transaction->old_map_size;
uint32_t magic, tailer;
return -1;
}
- rec = (struct list_struct *)data;
+ rec = (struct tdb_record *)data;
memset(rec, 0, sizeof(*rec));
rec->magic = 0;
magic = TDB_RECOVERY_MAGIC;
CONVERT(magic);
- *magic_offset = recovery_offset + offsetof(struct list_struct, magic);
+ *magic_offset = recovery_offset + offsetof(struct tdb_record, magic);
if (methods->tdb_write(tdb, *magic_offset, &magic, sizeof(magic)) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write recovery magic\n"));
return 0;
}
-#ifdef TDB_TRACE
- /* store seqnum now, before reading becomes illegal. */
- tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &tdb->transaction_prepare_seqnum);
-#endif
-
/* check for a null transaction */
if (tdb->transaction->blocks == NULL) {
return 0;
return -1;
}
+ tdb->transaction->global_lock_taken = true;
+
if (!(tdb->flags & TDB_NOSYNC)) {
/* write the recovery data to the end of the file */
if (transaction_setup_recovery(tdb, &tdb->transaction->magic_offset) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: failed to setup recovery data\n"));
- tdb_brunlock(tdb, F_WRLCK, GLOBAL_LOCK, 1);
_tdb_transaction_cancel(tdb, F_WRLCK);
return -1;
}
tdb->transaction->old_map_size) == -1) {
tdb->ecode = TDB_ERR_IO;
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: expansion failed\n"));
- tdb_brunlock(tdb, F_WRLCK, GLOBAL_LOCK, 1);
_tdb_transaction_cancel(tdb, F_WRLCK);
return -1;
}
return -1;
}
- /* If we've prepared, can't read seqnum. */
- if (tdb->transaction->prepared) {
- tdb_trace_seqnum(tdb, tdb->transaction_prepare_seqnum,
- "tdb_transaction_commit");
- } else {
- tdb_trace(tdb, "tdb_transaction_commit");
- }
+ tdb_trace(tdb, "tdb_transaction_commit");
if (tdb->transaction->transaction_error) {
tdb->ecode = TDB_ERR_IO;
tdb_transaction_recover(tdb);
_tdb_transaction_cancel(tdb, F_WRLCK);
- tdb_brunlock(tdb, F_WRLCK, GLOBAL_LOCK, 1);
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed\n"));
return -1;
return -1;
}
- tdb_brunlock(tdb, F_WRLCK, GLOBAL_LOCK, 1);
-
/*
TODO: maybe write to some dummy hdr field, or write to magic
offset without mmap, before the last sync, instead of the
tdb_off_t recovery_head, recovery_eof;
unsigned char *data, *p;
uint32_t zero = 0;
- struct list_struct rec;
+ struct tdb_record rec;
/* find the recovery area */
if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
}
/* remove the recovery magic */
- if (tdb_ofs_write(tdb, recovery_head + offsetof(struct list_struct, magic),
+ if (tdb_ofs_write(tdb, recovery_head + offsetof(struct tdb_record, magic),
&zero) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery magic\n"));
tdb->ecode = TDB_ERR_IO;