X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Ftdb%2Ftest%2Frun-die-during-transaction.c;h=fb5da455ebf023a2d626acaa41a97b5c7e1986ce;hp=7e61b4818c97133ecb119addb975c7cf70daf3ce;hb=233e3055c46ba2ed8fea326ac40ea0545eb0444f;hpb=b86f8688feef575cb0c69b964a47fa1167cde528 diff --git a/ccan/tdb/test/run-die-during-transaction.c b/ccan/tdb/test/run-die-during-transaction.c index 7e61b481..fb5da455 100644 --- a/ccan/tdb/test/run-die-during-transaction.c +++ b/ccan/tdb/test/run-die-during-transaction.c @@ -1,13 +1,13 @@ #define _XOPEN_SOURCE 500 #include +#include "lock-tracking.h" static ssize_t pwrite_check(int fd, const void *buf, size_t count, off_t offset); static ssize_t write_check(int fd, const void *buf, size_t count); -static int fcntl_check(int fd, int cmd, ... /* arg */ ); static int ftruncate_check(int fd, off_t length); #define pwrite pwrite_check #define write write_check -#define fcntl fcntl_check +#define fcntl fcntl_with_lockcheck #define ftruncate ftruncate_check #include @@ -26,7 +26,8 @@ static int ftruncate_check(int fd, off_t length); #include #include #include -#include "external-transaction.h" +#include "external-agent.h" +#include "logging.h" #undef write #undef pwrite @@ -34,40 +35,14 @@ static int ftruncate_check(int fd, off_t length); #undef ftruncate static bool in_transaction; -static bool suppress_logging; static int target, current; static jmp_buf jmpbuf; -#define TEST_DBNAME "/tmp/test7.tdb" - -/* We save the locks so we can reaquire them. */ -struct lock { - struct lock *next; - off_t off; - unsigned int len; - int type; -}; -static struct lock *locks; - -static void taplog(struct tdb_context *tdb, - enum tdb_debug_level level, - const char *fmt, ...) -{ - va_list ap; - char line[200]; - - if (suppress_logging) - return; - - va_start(ap, fmt); - vsprintf(line, fmt, ap); - va_end(ap); - - diag("%s", line); -} +#define TEST_DBNAME "run-die-during-transaction.tdb" +#define KEY_STRING "helloworld" -static void check_file_contents(int fd) +static void maybe_die(int fd) { - if (current++ == target) { + if (in_transaction && current++ == target) { longjmp(jmpbuf, 1); } } @@ -77,15 +52,13 @@ static ssize_t pwrite_check(int fd, { ssize_t ret; - if (in_transaction) - check_file_contents(fd); + maybe_die(fd); ret = pwrite(fd, buf, count, offset); if (ret != count) return ret; - if (in_transaction) - check_file_contents(fd); + maybe_die(fd); return ret; } @@ -93,68 +66,13 @@ static ssize_t write_check(int fd, const void *buf, size_t count) { ssize_t ret; - if (in_transaction) - check_file_contents(fd); + maybe_die(fd); ret = write(fd, buf, count); if (ret != count) return ret; - if (in_transaction) - check_file_contents(fd); - return ret; -} - -extern int fcntl(int fd, int cmd, ... /* arg */ ); - -static int fcntl_check(int fd, int cmd, ... /* arg */ ) -{ - va_list ap; - int ret, arg3; - struct flock *fl; - - if (cmd != F_SETLK && cmd != F_SETLKW) { - /* This may be totally bogus, but we don't know in general. */ - va_start(ap, cmd); - arg3 = va_arg(ap, int); - va_end(ap); - - return fcntl(fd, cmd, arg3); - } - - va_start(ap, cmd); - fl = va_arg(ap, struct flock *); - va_end(ap); - - ret = fcntl(fd, cmd, fl); - if (ret == 0) { - if (fl->l_type == F_UNLCK) { - struct lock **l; - struct lock *old = NULL; - - for (l = &locks; *l; l = &(*l)->next) { - if ((*l)->off == fl->l_start - && (*l)->len == fl->l_len) { - old = *l; - *l = (*l)->next; - free(old); - break; - } - } - if (!old) - errx(1, "Unknown lock"); - } else { - struct lock *new = malloc(sizeof *new); - new->off = fl->l_start; - new->len = fl->l_len; - new->type = fl->l_type; - new->next = locks; - locks = new; - } - } - - if (in_transaction && fl->l_type == F_UNLCK) - check_file_contents(fd); + maybe_die(fd); return ret; } @@ -162,21 +80,19 @@ static int ftruncate_check(int fd, off_t length) { int ret; - if (in_transaction) - check_file_contents(fd); + maybe_die(fd); ret = ftruncate(fd, length); - if (in_transaction) - check_file_contents(fd); + maybe_die(fd); return ret; } static bool test_death(enum operation op, struct agent *agent) { - struct tdb_context *tdb; - TDB_DATA key, data; - struct tdb_logging_context logctx = { taplog, NULL }; + struct tdb_context *tdb = NULL; + TDB_DATA key; + enum agent_return ret; int needed_recovery = 0; current = target = 0; @@ -184,34 +100,53 @@ reset: if (setjmp(jmpbuf) != 0) { /* We're partway through. Simulate our death. */ close(tdb->fd); + forget_locking(); in_transaction = false; - if (external_agent_operation(agent, NEEDS_RECOVERY_KEEP_OPENED, - "")) + ret = external_agent_operation(agent, NEEDS_RECOVERY, ""); + if (ret == SUCCESS) needed_recovery++; + else if (ret != FAILED) { + diag("Step %u agent NEEDS_RECOVERY = %s", current, + agent_return_name(ret)); + return false; + } - if (external_agent_operation(agent, op, "") != 1) { - diag("Step %u op failed", current); + ret = external_agent_operation(agent, op, KEY_STRING); + if (ret != SUCCESS) { + diag("Step %u op %s failed = %s", current, + operation_name(op), + agent_return_name(ret)); return false; } - if (external_agent_operation(agent, NEEDS_RECOVERY_KEEP_OPENED, - "")) { - diag("Still needs recovery after step %u", current); + ret = external_agent_operation(agent, NEEDS_RECOVERY, ""); + if (ret != FAILED) { + diag("Still needs recovery after step %u = %s", + current, agent_return_name(ret)); return false; } - if (external_agent_operation(agent, CHECK_KEEP_OPENED, "") - != 1) { - diag("Step %u check failed", current); + ret = external_agent_operation(agent, CHECK, ""); + if (ret != SUCCESS) { + diag("Step %u check failed = %s", current, + agent_return_name(ret)); + return false; + } + + ret = external_agent_operation(agent, CLOSE, ""); + if (ret != SUCCESS) { + diag("Step %u close failed = %s", current, + agent_return_name(ret)); return false; } - external_agent_operation(agent, CLOSE, ""); /* Suppress logging as this tries to use closed fd. */ suppress_logging = true; + suppress_lockcheck = true; tdb_close(tdb); suppress_logging = false; + suppress_lockcheck = false; target++; current = 0; goto reset; @@ -219,22 +154,32 @@ reset: unlink(TEST_DBNAME); tdb = tdb_open_ex(TEST_DBNAME, 1024, TDB_NOMMAP, - O_CREAT|O_TRUNC|O_RDWR, 0600, &logctx, NULL); - - if (external_agent_operation(agent, KEEP_OPENED, TEST_DBNAME) != 0) - errx(1, "Agent failed to open?"); + O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL); - if (tdb_transaction_start(tdb) != 0) + /* Put key for agent to fetch. */ + key.dsize = strlen(KEY_STRING); + key.dptr = (void *)KEY_STRING; + if (tdb_store(tdb, key, key, TDB_INSERT) != 0) return false; + /* This is the key we insert in transaction. */ + key.dsize--; + + ret = external_agent_operation(agent, OPEN, TEST_DBNAME); + if (ret != SUCCESS) + errx(1, "Agent failed to open: %s", agent_return_name(ret)); + + ret = external_agent_operation(agent, FETCH, KEY_STRING); + if (ret != SUCCESS) + errx(1, "Agent failed find key: %s", agent_return_name(ret)); + in_transaction = true; - key.dsize = strlen("hi"); - key.dptr = (void *)"hi"; - data.dptr = (void *)"world"; - data.dsize = strlen("world"); + if (tdb_transaction_start(tdb) != 0) + return false; - if (tdb_store(tdb, key, data, TDB_INSERT) != 0) + if (tdb_store(tdb, key, key, TDB_INSERT) != 0) return false; + if (tdb_transaction_commit(tdb) != 0) return false; @@ -243,36 +188,35 @@ reset: /* We made it! */ diag("Completed %u runs", current); tdb_close(tdb); - external_agent_operation(agent, CLOSE, ""); + ret = external_agent_operation(agent, CLOSE, ""); + if (ret != SUCCESS) { + diag("Step %u close failed = %s", current, + agent_return_name(ret)); + return false; + } ok1(needed_recovery); + ok1(locking_errors == 0); + ok1(forget_locking() == 0); + locking_errors = 0; return true; } int main(int argc, char *argv[]) { - enum operation ops[] = { FETCH_KEEP_OPENED, - STORE_KEEP_OPENED, - TRANSACTION_KEEP_OPENED }; + enum operation ops[] = { FETCH, STORE, TRANSACTION_START }; struct agent *agent; int i; - plan_tests(6); + plan_tests(12); + unlock_callback = maybe_die; + agent = prepare_external_agent(); if (!agent) err(1, "preparing agent"); - /* Nice ourselves down: we can't tell the difference between agent - * blocking on lock, and agent not scheduled. */ - nice(15); - for (i = 0; i < sizeof(ops)/sizeof(ops[0]); i++) { - diag("Testing %s after death", - ops[i] == TRANSACTION_KEEP_OPENED ? "transaction" - : ops[i] == FETCH_KEEP_OPENED ? "fetch" - : ops[i] == STORE_KEEP_OPENED ? "store" - : NULL); - + diag("Testing %s after death", operation_name(ops[i])); ok1(test_death(ops[i], agent)); }