From 010c8d465aa1e8810bd060ecf5d124ca2d990b0e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 14 Jul 2009 22:04:36 +0930 Subject: [PATCH] Fix early transaction unlock when traverse done inside transaction. Generalizes traverse in traverse fix from rusty@rustcorp.com.au-20090629073630-3eduhyypx2tp6u80 --- ccan/tdb/lock.c | 12 ++-- ccan/tdb/tdb_private.h | 2 +- ccan/tdb/test/run-traverse-in-transaction.c | 70 +++++++++++++++++++++ ccan/tdb/traverse.c | 13 ++-- 4 files changed, 79 insertions(+), 18 deletions(-) create mode 100644 ccan/tdb/test/run-traverse-in-transaction.c diff --git a/ccan/tdb/lock.c b/ccan/tdb/lock.c index 473a9bf5..6809ce37 100644 --- a/ccan/tdb/lock.c +++ b/ccan/tdb/lock.c @@ -302,6 +302,7 @@ int tdb_unlock(struct tdb_context *tdb, int list, int ltype) int tdb_transaction_lock(struct tdb_context *tdb, int ltype) { if (tdb->have_transaction_lock || tdb->global_lock.count) { + tdb->have_transaction_lock++; return 0; } if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, ltype, @@ -310,7 +311,7 @@ int tdb_transaction_lock(struct tdb_context *tdb, int ltype) tdb->ecode = TDB_ERR_LOCK; return -1; } - tdb->have_transaction_lock = 1; + tdb->have_transaction_lock++; return 0; } @@ -319,15 +320,10 @@ int tdb_transaction_lock(struct tdb_context *tdb, int ltype) */ int tdb_transaction_unlock(struct tdb_context *tdb) { - int ret; - if (!tdb->have_transaction_lock) { + if (--tdb->have_transaction_lock) { return 0; } - ret = tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1); - if (ret == 0) { - tdb->have_transaction_lock = 0; - } - return ret; + return tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1); } diff --git a/ccan/tdb/tdb_private.h b/ccan/tdb/tdb_private.h index 0ee5eb65..48364728 100644 --- a/ccan/tdb/tdb_private.h +++ b/ccan/tdb/tdb_private.h @@ -215,7 +215,7 @@ struct tdb_context { struct tdb_transaction *transaction; int page_size; int max_dead_records; - bool have_transaction_lock; + int have_transaction_lock; int tracefd; volatile sig_atomic_t *interrupt_sig_ptr; }; diff --git a/ccan/tdb/test/run-traverse-in-transaction.c b/ccan/tdb/test/run-traverse-in-transaction.c new file mode 100644 index 00000000..b184474f --- /dev/null +++ b/ccan/tdb/test/run-traverse-in-transaction.c @@ -0,0 +1,70 @@ +#define _XOPEN_SOURCE 500 +#include "tdb/tdb.h" +#include "tdb/io.c" +#include "tdb/tdb.c" +#include "tdb/lock.c" +#include "tdb/freelist.c" +#include "tdb/traverse.c" +#include "tdb/transaction.c" +#include "tdb/error.c" +#include "tdb/open.c" +#include "tap/tap.h" +#include +#include +#include + +static bool correct_key(TDB_DATA key) +{ + return key.dsize == strlen("hi") + && memcmp(key.dptr, "hi", key.dsize) == 0; +} + +static bool correct_data(TDB_DATA data) +{ + return data.dsize == strlen("world") + && memcmp(data.dptr, "world", data.dsize) == 0; +} + +static int traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, + void *p) +{ + ok1(correct_key(key)); + ok1(correct_data(data)); + return 0; +} + +int main(int argc, char *argv[]) +{ + struct tdb_context *tdb; + TDB_DATA key, data; + + plan_tests(12); + tdb = tdb_open("/tmp/test.tdb", 1024, TDB_CLEAR_IF_FIRST, + O_CREAT|O_TRUNC|O_RDWR, 0600); + ok1(tdb); + + /* Tickle bug on appending zero length buffer to zero length buffer. */ + key.dsize = strlen("hi"); + key.dptr = (void *)"hi"; + data.dptr = (void *)"world"; + data.dsize = strlen("world"); + + ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0); + + ok1(tdb_transaction_start(tdb) == 0); + ok(tdb->have_transaction_lock, "Transaction lock in transaction"); + tdb_traverse(tdb, traverse, NULL); + + /* That should *not* release the transaction lock! */ + ok(tdb->have_transaction_lock, "Transaction lock after traverse"); + tdb_traverse_read(tdb, traverse, NULL); + + /* That should *not* release the transaction lock! */ + ok(tdb->have_transaction_lock, "Transaction lock after traverse_read"); + ok1(tdb_transaction_commit(tdb) == 0); + ok(!tdb->have_transaction_lock, "Transaction unlock"); + + tdb_close(tdb); + + return exit_status(); +} diff --git a/ccan/tdb/traverse.c b/ccan/tdb/traverse.c index 3159b014..d8b15aff 100644 --- a/ccan/tdb/traverse.c +++ b/ccan/tdb/traverse.c @@ -211,7 +211,7 @@ int tdb_traverse_read(struct tdb_context *tdb, /* we need to get a read lock on the transaction lock here to cope with the lock ordering semantics of solaris10 */ - if (tdb->traverse_read == 0 && tdb_transaction_lock(tdb, F_RDLCK)) { + if (tdb_transaction_lock(tdb, F_RDLCK)) { return -1; } @@ -220,9 +220,7 @@ int tdb_traverse_read(struct tdb_context *tdb, ret = tdb_traverse_internal(tdb, fn, private_data, &tl); tdb->traverse_read--; - if (tdb->traverse_read == 0) { - tdb_transaction_unlock(tdb); - } + tdb_transaction_unlock(tdb); return ret; } @@ -244,8 +242,7 @@ int tdb_traverse(struct tdb_context *tdb, return tdb_traverse_read(tdb, fn, private_data); } - /* Nested traversals: transaction lock doesn't nest. */ - if (tdb->traverse_write == 0 && tdb_transaction_lock(tdb, F_WRLCK)) { + if (tdb_transaction_lock(tdb, F_WRLCK)) { return -1; } @@ -254,9 +251,7 @@ int tdb_traverse(struct tdb_context *tdb, ret = tdb_traverse_internal(tdb, fn, private_data, &tl); tdb->traverse_write--; - if (tdb->traverse_write == 0) { - tdb_transaction_unlock(tdb); - } + tdb_transaction_unlock(tdb); return ret; } -- 2.39.2