X-Git-Url: https://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Ftdb%2Ftransaction.c;h=e55285f94cc6609a2afa720d39fe66d2261a36fe;hp=1086c5f037793d9df00269ff78b14ae2ad126e72;hb=1bc7c4367132a36c05ac1b3afcbec70a6e26540d;hpb=c5316eef05ab024c44224a165282e8df8ad30285 diff --git a/ccan/tdb/transaction.c b/ccan/tdb/transaction.c index 1086c5f0..e55285f9 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. */ @@ -127,6 +129,9 @@ struct tdb_transaction { /* old file size before transaction */ tdb_len_t old_map_size; + + /* we should re-pack on commit */ + bool need_repack; }; @@ -382,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; } /* @@ -397,6 +403,8 @@ static int transaction_expand_file(struct tdb_context *tdb, tdb_off_t size, return -1; } + tdb->transaction->need_repack = true; + return 0; } @@ -527,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) { @@ -993,6 +1000,7 @@ int tdb_transaction_commit(struct tdb_context *tdb) { const struct tdb_methods *methods; int i; + bool need_repack; if (tdb->transaction == NULL) { TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: no transaction\n")); @@ -1092,10 +1100,16 @@ int tdb_transaction_commit(struct tdb_context *tdb) utime(tdb->name, NULL); #endif + need_repack = tdb->transaction->need_repack; + /* use a transaction cancel to free memory and remove the transaction locks */ tdb_transaction_cancel_internal(tdb); + if (need_repack) { + return tdb_repack(tdb); + } + return 0; }