X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;ds=sidebyside;f=ccan%2Ftdb%2Ftransaction.c;h=7e8ac34dd5bc7e93a9a20cd9ac7e127716d3e504;hb=91ddc0b7f90986495f014217451361c07fdcd856;hp=0944bb36e98a6a3af4e32ac2052e512483bc4311;hpb=059678ec4216112f96d8ad992ec7c0b8a6e3b80b;p=ccan diff --git a/ccan/tdb/transaction.c b/ccan/tdb/transaction.c index 0944bb36..7e8ac34d 100644 --- a/ccan/tdb/transaction.c +++ b/ccan/tdb/transaction.c @@ -85,11 +85,13 @@ still available, but no transaction recovery area is used and no fsync/msync calls are made. - - if TDB_NO_NESTING is passed to flags in tdb open then transaction - nesting is disabled. tdb_transaction_start() will then implicitely - cancel any pending transactions and always start a new transaction - context instead of nesting. + - 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. + Beware. when transactions are nested a transaction successfully + completed with tdb_transaction_commit() can be silently unrolled later. */ @@ -385,7 +387,8 @@ static int transaction_oob(struct tdb_context *tdb, tdb_off_t len, int probe) if (len <= tdb->map_size) { return 0; } - return TDB_ERRCODE(TDB_ERR_IO, -1); + tdb->ecode = TDB_ERR_IO; + return -1; } /* @@ -452,7 +455,7 @@ static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t return 0; } -int tdb_transaction_cancel_internal(struct tdb_context *tdb) +int _tdb_transaction_cancel(struct tdb_context *tdb) { int i, ret = 0; @@ -532,16 +535,15 @@ int tdb_transaction_start(struct tdb_context *tdb) /* cope with nested tdb_transaction_start() calls */ if (tdb->transaction != NULL) { - tdb_trace(tdb, "tdb_transaction_start"); - if (!tdb->flags & TDB_NO_NESTING) { - tdb->transaction->nesting++; - TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_start: nesting %d\n", - tdb->transaction->nesting)); - return 0; - } else { - tdb_transaction_cancel_internal(tdb); - TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_start: cancelling previous transaction\n")); + if (!(tdb->flags & TDB_ALLOW_NESTING)) { + tdb->ecode = TDB_ERR_NESTING; + return -1; } + tdb_trace(tdb, "tdb_transaction_start"); + tdb->transaction->nesting++; + TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_start: nesting %d\n", + tdb->transaction->nesting)); + return 0; } if (tdb->num_locks != 0 || tdb->global_lock.count) { @@ -634,7 +636,7 @@ fail: int tdb_transaction_cancel(struct tdb_context *tdb) { tdb_trace(tdb, "tdb_transaction_cancel"); - return tdb_transaction_cancel_internal(tdb); + return _tdb_transaction_cancel(tdb); } /* @@ -883,7 +885,7 @@ static int transaction_setup_recovery(struct tdb_context *tdb, return 0; } -static int tdb_transaction_prepare_commit_internal(struct tdb_context *tdb) +static int _tdb_transaction_prepare_commit(struct tdb_context *tdb) { const struct tdb_methods *methods; @@ -894,14 +896,14 @@ static int tdb_transaction_prepare_commit_internal(struct tdb_context *tdb) if (tdb->transaction->prepared) { tdb->ecode = TDB_ERR_EINVAL; - tdb_transaction_cancel(tdb); + _tdb_transaction_cancel(tdb); TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction already prepared\n")); return -1; } if (tdb->transaction->transaction_error) { tdb->ecode = TDB_ERR_IO; - tdb_transaction_cancel_internal(tdb); + _tdb_transaction_cancel(tdb); TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction error pending\n")); return -1; } @@ -929,7 +931,7 @@ static int tdb_transaction_prepare_commit_internal(struct tdb_context *tdb) if (tdb->num_locks || tdb->global_lock.count) { tdb->ecode = TDB_ERR_LOCK; TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: locks pending on commit\n")); - tdb_transaction_cancel_internal(tdb); + _tdb_transaction_cancel(tdb); return -1; } @@ -937,7 +939,7 @@ static int tdb_transaction_prepare_commit_internal(struct tdb_context *tdb) if (tdb_brlock_upgrade(tdb, FREELIST_TOP, 0) == -1) { TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to upgrade hash locks\n")); tdb->ecode = TDB_ERR_LOCK; - tdb_transaction_cancel_internal(tdb); + _tdb_transaction_cancel(tdb); return -1; } @@ -946,7 +948,7 @@ static int tdb_transaction_prepare_commit_internal(struct tdb_context *tdb) if (tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) { TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to get global lock\n")); tdb->ecode = TDB_ERR_LOCK; - tdb_transaction_cancel_internal(tdb); + _tdb_transaction_cancel(tdb); return -1; } @@ -955,7 +957,7 @@ static int tdb_transaction_prepare_commit_internal(struct tdb_context *tdb) 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_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1); - tdb_transaction_cancel_internal(tdb); + _tdb_transaction_cancel(tdb); return -1; } } @@ -970,7 +972,7 @@ static int tdb_transaction_prepare_commit_internal(struct tdb_context *tdb) tdb->ecode = TDB_ERR_IO; TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: expansion failed\n")); tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1); - tdb_transaction_cancel_internal(tdb); + _tdb_transaction_cancel(tdb); return -1; } tdb->map_size = tdb->transaction->old_map_size; @@ -988,7 +990,7 @@ static int tdb_transaction_prepare_commit_internal(struct tdb_context *tdb) int tdb_transaction_prepare_commit(struct tdb_context *tdb) { tdb_trace(tdb, "tdb_transaction_prepare_commit"); - return tdb_transaction_prepare_commit_internal(tdb); + return _tdb_transaction_prepare_commit(tdb); } /* @@ -1028,12 +1030,12 @@ int tdb_transaction_commit(struct tdb_context *tdb) /* check for a null transaction */ if (tdb->transaction->blocks == NULL) { - tdb_transaction_cancel_internal(tdb); + _tdb_transaction_cancel(tdb); return 0; } if (!tdb->transaction->prepared) { - int ret = tdb_transaction_prepare_commit_internal(tdb); + int ret = _tdb_transaction_prepare_commit(tdb); if (ret) return ret; } @@ -1064,7 +1066,7 @@ int tdb_transaction_commit(struct tdb_context *tdb) tdb->methods = methods; tdb_transaction_recover(tdb); - tdb_transaction_cancel_internal(tdb); + _tdb_transaction_cancel(tdb); tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1); TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed\n")); @@ -1102,7 +1104,7 @@ int tdb_transaction_commit(struct tdb_context *tdb) /* use a transaction cancel to free memory and remove the transaction locks */ - tdb_transaction_cancel_internal(tdb); + _tdb_transaction_cancel(tdb); if (need_repack) { return tdb_repack(tdb);