Commit 42145b92 authored by Rusty Russell's avatar Rusty Russell

Print seq numbers on timeout dump

(Invasive: means passing full op array all the way through).
parent 010c8d46
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
/* Avoid mod by zero */ /* Avoid mod by zero */
static unsigned int total_keys = 1; static unsigned int total_keys = 1;
/* #define DEBUG_DEPS 1 */ #define DEBUG_DEPS 1
/* Traversals block transactions in the current implementation. */ /* Traversals block transactions in the current implementation. */
#define TRAVERSALS_TAKE_TRANSACTION_LOCK 1 #define TRAVERSALS_TAKE_TRANSACTION_LOCK 1
...@@ -404,23 +404,26 @@ static void check_deps(const char *filename, struct op op[], unsigned int num) ...@@ -404,23 +404,26 @@ static void check_deps(const char *filename, struct op op[], unsigned int num)
#endif #endif
} }
static void dump_pre(char *filename[], unsigned int file, static void dump_pre(char *filename[], struct op *op[],
struct op op[], unsigned int i) unsigned int file, unsigned int i)
{ {
struct depend *dep; struct depend *dep;
printf("%s:%u still waiting for:\n", filename[file], i+1); printf("%s:%u (%u) still waiting for:\n", filename[file], i+1,
list_for_each(&op[i].pre, dep, pre_list) op[file][i].serial);
printf(" %s:%u\n", list_for_each(&op[file][i].pre, dep, pre_list)
filename[dep->satisfies_file], dep->satisfies_opnum+1); printf(" %s:%u (%u)\n",
check_deps(filename[file], op, i); filename[dep->satisfies_file], dep->satisfies_opnum+1,
op[dep->satisfies_file][dep->satisfies_opnum].serial);
check_deps(filename[file], op[file], i);
} }
/* We simply read/write pointers, since we all are children. */ /* We simply read/write pointers, since we all are children. */
static void do_pre(char *filename[], unsigned int file, int pre_fd, static void do_pre(struct tdb_context *tdb,
struct op op[], unsigned int i) char *filename[], struct op *op[],
unsigned int file, int pre_fd, unsigned int i)
{ {
while (!list_empty(&op[i].pre)) { while (!list_empty(&op[file][i].pre)) {
struct depend *dep; struct depend *dep;
#if DEBUG_DEPS #if DEBUG_DEPS
...@@ -430,7 +433,7 @@ static void do_pre(char *filename[], unsigned int file, int pre_fd, ...@@ -430,7 +433,7 @@ static void do_pre(char *filename[], unsigned int file, int pre_fd,
alarm(10); alarm(10);
while (read(pre_fd, &dep, sizeof(dep)) != sizeof(dep)) { while (read(pre_fd, &dep, sizeof(dep)) != sizeof(dep)) {
if (errno == EINTR) { if (errno == EINTR) {
dump_pre(filename, file, op, i); dump_pre(filename, op, file, i);
exit(1); exit(1);
} else } else
errx(1, "Reading from pipe"); errx(1, "Reading from pipe");
...@@ -448,12 +451,12 @@ static void do_pre(char *filename[], unsigned int file, int pre_fd, ...@@ -448,12 +451,12 @@ static void do_pre(char *filename[], unsigned int file, int pre_fd,
} }
} }
static void do_post(char *filename[], unsigned int file, static void do_post(char *filename[], struct op *op[],
const struct op op[], unsigned int i) unsigned int file, unsigned int i)
{ {
struct depend *dep; struct depend *dep;
list_for_each(&op[i].post, dep, post_list) { list_for_each(&op[file][i].post, dep, post_list) {
#if DEBUG_DEPS #if DEBUG_DEPS
printf("%s:%u:sending to file %s:%u\n", filename[file], i+1, printf("%s:%u:sending to file %s:%u\n", filename[file], i+1,
filename[dep->needs_file], dep->needs_opnum+1); filename[dep->needs_file], dep->needs_opnum+1);
...@@ -473,12 +476,12 @@ static int get_len(TDB_DATA key, TDB_DATA data, void *private_data) ...@@ -473,12 +476,12 @@ static int get_len(TDB_DATA key, TDB_DATA data, void *private_data)
static unsigned run_ops(struct tdb_context *tdb, static unsigned run_ops(struct tdb_context *tdb,
int pre_fd, int pre_fd,
char *filename[], char *filename[],
struct op *op[],
unsigned int file, unsigned int file,
struct op op[],
unsigned int start, unsigned int stop); unsigned int start, unsigned int stop);
struct traverse_info { struct traverse_info {
struct op *op; struct op **op;
char **filename; char **filename;
unsigned file; unsigned file;
int pre_fd; int pre_fd;
...@@ -492,7 +495,7 @@ static int nontrivial_traverse(struct tdb_context *tdb, ...@@ -492,7 +495,7 @@ static int nontrivial_traverse(struct tdb_context *tdb,
void *_tinfo) void *_tinfo)
{ {
struct traverse_info *tinfo = _tinfo; struct traverse_info *tinfo = _tinfo;
unsigned int trav_len = tinfo->op[tinfo->start].group_len; unsigned int trav_len = tinfo->op[tinfo->file][tinfo->start].group_len;
if (tinfo->i == tinfo->start + trav_len) { if (tinfo->i == tinfo->start + trav_len) {
/* This can happen if traverse expects to be empty. */ /* This can happen if traverse expects to be empty. */
...@@ -502,13 +505,13 @@ static int nontrivial_traverse(struct tdb_context *tdb, ...@@ -502,13 +505,13 @@ static int nontrivial_traverse(struct tdb_context *tdb,
"traverse did not terminate"); "traverse did not terminate");
} }
if (tinfo->op[tinfo->i].op != OP_TDB_TRAVERSE) if (tinfo->op[tinfo->file][tinfo->i].op != OP_TDB_TRAVERSE)
fail(tinfo->filename[tinfo->file], tinfo->start + 1, fail(tinfo->filename[tinfo->file], tinfo->start + 1,
"%s:%u:traverse terminated early"); "%s:%u:traverse terminated early");
/* Run any normal ops. */ /* Run any normal ops. */
tinfo->i = run_ops(tdb, tinfo->pre_fd, tinfo->filename, tinfo->file, tinfo->i = run_ops(tdb, tinfo->pre_fd, tinfo->filename, tinfo->op,
tinfo->op, tinfo->i+1, tinfo->start + trav_len); tinfo->file, tinfo->i+1, tinfo->start + trav_len);
if (tinfo->i == tinfo->start + trav_len) if (tinfo->i == tinfo->start + trav_len)
return 1; return 1;
...@@ -522,7 +525,7 @@ static unsigned op_traverse(struct tdb_context *tdb, ...@@ -522,7 +525,7 @@ static unsigned op_traverse(struct tdb_context *tdb,
unsigned int file, unsigned int file,
int (*traversefn)(struct tdb_context *, int (*traversefn)(struct tdb_context *,
tdb_traverse_func, void *), tdb_traverse_func, void *),
struct op op[], struct op *op[],
unsigned int start) unsigned int start)
{ {
struct traverse_info tinfo = { op, filename, file, pre_fd, struct traverse_info tinfo = { op, filename, file, pre_fd,
...@@ -533,12 +536,13 @@ static unsigned op_traverse(struct tdb_context *tdb, ...@@ -533,12 +536,13 @@ static unsigned op_traverse(struct tdb_context *tdb,
/* Traversing in wrong order can have strange effects: eg. if /* Traversing in wrong order can have strange effects: eg. if
* original traverse went A (delete A), B, we might do B * original traverse went A (delete A), B, we might do B
* (delete A). So if we have ops left over, we do it now. */ * (delete A). So if we have ops left over, we do it now. */
while (tinfo.i != start + op[start].group_len) { while (tinfo.i != start + op[file][start].group_len) {
if (op[tinfo.i].op == OP_TDB_TRAVERSE) if (op[file][tinfo.i].op == OP_TDB_TRAVERSE)
tinfo.i++; tinfo.i++;
else else
tinfo.i = run_ops(tdb, pre_fd, filename, file, op, tinfo.i = run_ops(tdb, pre_fd, filename, op, file,
tinfo.i, start + op[start].group_len); tinfo.i,
start + op[file][start].group_len);
} }
return tinfo.i; return tinfo.i;
...@@ -552,8 +556,9 @@ static __attribute__((noinline)) ...@@ -552,8 +556,9 @@ static __attribute__((noinline))
unsigned run_ops(struct tdb_context *tdb, unsigned run_ops(struct tdb_context *tdb,
int pre_fd, int pre_fd,
char *filename[], char *filename[],
struct op *op[],
unsigned int file, unsigned int file,
struct op op[], unsigned int start, unsigned int stop) unsigned int start, unsigned int stop)
{ {
unsigned int i; unsigned int i;
struct sigaction sa; struct sigaction sa;
...@@ -563,88 +568,98 @@ unsigned run_ops(struct tdb_context *tdb, ...@@ -563,88 +568,98 @@ unsigned run_ops(struct tdb_context *tdb,
sigaction(SIGALRM, &sa, NULL); sigaction(SIGALRM, &sa, NULL);
for (i = start; i < stop; i++) { for (i = start; i < stop; i++) {
do_pre(filename, file, pre_fd, op, i); do_pre(tdb, filename, op, file, pre_fd, i);
switch (op[i].op) { switch (op[file][i].op) {
case OP_TDB_LOCKALL: case OP_TDB_LOCKALL:
try(tdb_lockall(tdb), op[i].ret); try(tdb_lockall(tdb), op[file][i].ret);
break; break;
case OP_TDB_LOCKALL_MARK: case OP_TDB_LOCKALL_MARK:
try(tdb_lockall_mark(tdb), op[i].ret); try(tdb_lockall_mark(tdb), op[file][i].ret);
break; break;
case OP_TDB_LOCKALL_UNMARK: case OP_TDB_LOCKALL_UNMARK:
try(tdb_lockall_unmark(tdb), op[i].ret); try(tdb_lockall_unmark(tdb), op[file][i].ret);
break; break;
case OP_TDB_LOCKALL_NONBLOCK: case OP_TDB_LOCKALL_NONBLOCK:
unreliable(tdb_lockall_nonblock(tdb), op[i].ret, unreliable(tdb_lockall_nonblock(tdb), op[file][i].ret,
tdb_lockall(tdb), tdb_unlockall(tdb)); tdb_lockall(tdb), tdb_unlockall(tdb));
break; break;
case OP_TDB_UNLOCKALL: case OP_TDB_UNLOCKALL:
try(tdb_unlockall(tdb), op[i].ret); try(tdb_unlockall(tdb), op[file][i].ret);
break; break;
case OP_TDB_LOCKALL_READ: case OP_TDB_LOCKALL_READ:
try(tdb_lockall_read(tdb), op[i].ret); try(tdb_lockall_read(tdb), op[file][i].ret);
break; break;
case OP_TDB_LOCKALL_READ_NONBLOCK: case OP_TDB_LOCKALL_READ_NONBLOCK:
unreliable(tdb_lockall_read_nonblock(tdb), op[i].ret, unreliable(tdb_lockall_read_nonblock(tdb),
op[file][i].ret,
tdb_lockall_read(tdb), tdb_lockall_read(tdb),
tdb_unlockall_read(tdb)); tdb_unlockall_read(tdb));
break; break;
case OP_TDB_UNLOCKALL_READ: case OP_TDB_UNLOCKALL_READ:
try(tdb_unlockall_read(tdb), op[i].ret); try(tdb_unlockall_read(tdb), op[file][i].ret);
break; break;
case OP_TDB_CHAINLOCK: case OP_TDB_CHAINLOCK:
try(tdb_chainlock(tdb, op[i].key), op[i].ret); try(tdb_chainlock(tdb, op[file][i].key),
op[file][i].ret);
break; break;
case OP_TDB_CHAINLOCK_NONBLOCK: case OP_TDB_CHAINLOCK_NONBLOCK:
unreliable(tdb_chainlock_nonblock(tdb, op[i].key), unreliable(tdb_chainlock_nonblock(tdb, op[file][i].key),
op[i].ret, op[file][i].ret,
tdb_chainlock(tdb, op[i].key), tdb_chainlock(tdb, op[file][i].key),
tdb_chainunlock(tdb, op[i].key)); tdb_chainunlock(tdb, op[file][i].key));
break; break;
case OP_TDB_CHAINLOCK_MARK: case OP_TDB_CHAINLOCK_MARK:
try(tdb_chainlock_mark(tdb, op[i].key), op[i].ret); try(tdb_chainlock_mark(tdb, op[file][i].key),
op[file][i].ret);
break; break;
case OP_TDB_CHAINLOCK_UNMARK: case OP_TDB_CHAINLOCK_UNMARK:
try(tdb_chainlock_unmark(tdb, op[i].key), op[i].ret); try(tdb_chainlock_unmark(tdb, op[file][i].key),
op[file][i].ret);
break; break;
case OP_TDB_CHAINUNLOCK: case OP_TDB_CHAINUNLOCK:
try(tdb_chainunlock(tdb, op[i].key), op[i].ret); try(tdb_chainunlock(tdb, op[file][i].key),
op[file][i].ret);
break; break;
case OP_TDB_CHAINLOCK_READ: case OP_TDB_CHAINLOCK_READ:
try(tdb_chainlock_read(tdb, op[i].key), op[i].ret); try(tdb_chainlock_read(tdb, op[file][i].key),
op[file][i].ret);
break; break;
case OP_TDB_CHAINUNLOCK_READ: case OP_TDB_CHAINUNLOCK_READ:
try(tdb_chainunlock_read(tdb, op[i].key), op[i].ret); try(tdb_chainunlock_read(tdb, op[file][i].key),
op[file][i].ret);
break; break;
case OP_TDB_PARSE_RECORD: case OP_TDB_PARSE_RECORD:
try(tdb_parse_record(tdb, op[i].key, get_len, NULL), try(tdb_parse_record(tdb, op[file][i].key, get_len,
op[i].ret); NULL),
op[file][i].ret);
break; break;
case OP_TDB_EXISTS: case OP_TDB_EXISTS:
try(tdb_exists(tdb, op[i].key), op[i].ret); try(tdb_exists(tdb, op[file][i].key), op[file][i].ret);
break; break;
case OP_TDB_STORE: case OP_TDB_STORE:
try(tdb_store(tdb, op[i].key, op[i].data, op[i].flag), try(tdb_store(tdb, op[file][i].key, op[file][i].data,
op[i].ret); op[file][i].flag),
op[file][i].ret);
break; break;
case OP_TDB_APPEND: case OP_TDB_APPEND:
try(tdb_append(tdb, op[i].key, op[i].data), op[i].ret); try(tdb_append(tdb, op[file][i].key, op[file][i].data),
op[file][i].ret);
break; break;
case OP_TDB_GET_SEQNUM: case OP_TDB_GET_SEQNUM:
try(tdb_get_seqnum(tdb), op[i].ret); try(tdb_get_seqnum(tdb), op[file][i].ret);
break; break;
case OP_TDB_WIPE_ALL: case OP_TDB_WIPE_ALL:
try(tdb_wipe_all(tdb), op[i].ret); try(tdb_wipe_all(tdb), op[file][i].ret);
break; break;
case OP_TDB_TRANSACTION_START: case OP_TDB_TRANSACTION_START:
try(tdb_transaction_start(tdb), op[i].ret); try(tdb_transaction_start(tdb), op[file][i].ret);
break; break;
case OP_TDB_TRANSACTION_CANCEL: case OP_TDB_TRANSACTION_CANCEL:
try(tdb_transaction_cancel(tdb), op[i].ret); try(tdb_transaction_cancel(tdb), op[file][i].ret);
break; break;
case OP_TDB_TRANSACTION_COMMIT: case OP_TDB_TRANSACTION_COMMIT:
try(tdb_transaction_commit(tdb), op[i].ret); try(tdb_transaction_commit(tdb), op[file][i].ret);
break; break;
case OP_TDB_TRAVERSE_READ_START: case OP_TDB_TRAVERSE_READ_START:
i = op_traverse(tdb, pre_fd, filename, file, i = op_traverse(tdb, pre_fd, filename, file,
...@@ -662,25 +677,26 @@ unsigned run_ops(struct tdb_context *tdb, ...@@ -662,25 +677,26 @@ unsigned run_ops(struct tdb_context *tdb,
fail(filename[file], i+1, "unexpected end traverse"); fail(filename[file], i+1, "unexpected end traverse");
/* FIXME: These must be treated like traverse. */ /* FIXME: These must be treated like traverse. */
case OP_TDB_FIRSTKEY: case OP_TDB_FIRSTKEY:
if (!key_eq(tdb_firstkey(tdb), op[i].data)) if (!key_eq(tdb_firstkey(tdb), op[file][i].data))
fail(filename[file], i+1, "bad firstkey"); fail(filename[file], i+1, "bad firstkey");
break; break;
case OP_TDB_NEXTKEY: case OP_TDB_NEXTKEY:
if (!key_eq(tdb_nextkey(tdb, op[i].key), op[i].data)) if (!key_eq(tdb_nextkey(tdb, op[file][i].key),
op[file][i].data))
fail(filename[file], i+1, "bad nextkey"); fail(filename[file], i+1, "bad nextkey");
break; break;
case OP_TDB_FETCH: { case OP_TDB_FETCH: {
TDB_DATA f = tdb_fetch(tdb, op[i].key); TDB_DATA f = tdb_fetch(tdb, op[file][i].key);
if (!key_eq(f, op[i].data)) if (!key_eq(f, op[file][i].data))
fail(filename[file], i+1, "bad fetch %u", fail(filename[file], i+1, "bad fetch %u",
f.dsize); f.dsize);
break; break;
} }
case OP_TDB_DELETE: case OP_TDB_DELETE:
try(tdb_delete(tdb, op[i].key), op[i].ret); try(tdb_delete(tdb, op[file][i].key), op[file][i].ret);
break; break;
} }
do_post(filename, file, op, i); do_post(filename, op, file, i);
} }
return i; return i;
} }
...@@ -1132,7 +1148,8 @@ struct traverse_dep { ...@@ -1132,7 +1148,8 @@ struct traverse_dep {
unsigned int op_num; unsigned int op_num;
}; };
/* Traversals can deadlock against each other. Force order. */ /* Traversals can deadlock against each other, and transactions. Force
* order. */
static void make_traverse_depends(char *filename[], static void make_traverse_depends(char *filename[],
struct op *op[], unsigned int num_ops[], struct op *op[], unsigned int num_ops[],
unsigned int num) unsigned int num)
...@@ -1160,7 +1177,7 @@ static void make_traverse_depends(char *filename[], ...@@ -1160,7 +1177,7 @@ static void make_traverse_depends(char *filename[],
/* Count them. */ /* Count them. */
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
for (j = 1; j < num_ops[i]; j++) { for (j = 1; j < num_ops[i]; j++) {
/* Transaction on traverse start. */ /* Transaction or traverse start. */
if (op[i][j].group_start == j) { if (op[i][j].group_start == j) {
dep = talloc_realloc(NULL, dep, dep = talloc_realloc(NULL, dep,
struct traverse_dep, struct traverse_dep,
...@@ -1358,7 +1375,7 @@ int main(int argc, char *argv[]) ...@@ -1358,7 +1375,7 @@ int main(int argc, char *argv[])
printf("Single threaded run..."); printf("Single threaded run...");
fflush(stdout); fflush(stdout);
run_ops(tdb, pipes[0].fd[0], argv+2, 0, op[0], 1, num_ops[0]); run_ops(tdb, pipes[0].fd[0], argv+2, op, 0, 1, num_ops[0]);
check_deps(argv[2], op[0], num_ops[0]); check_deps(argv[2], op[0], num_ops[0]);
printf("done\n"); printf("done\n");
...@@ -1385,7 +1402,7 @@ int main(int argc, char *argv[]) ...@@ -1385,7 +1402,7 @@ int main(int argc, char *argv[])
/* This catches parent exiting. */ /* This catches parent exiting. */
if (read(fds[0], &c, 1) != 1) if (read(fds[0], &c, 1) != 1)
exit(1); exit(1);
run_ops(tdb, pipes[i].fd[0], argv+2, i, op[i], 1, run_ops(tdb, pipes[i].fd[0], argv+2, op, i, 1,
num_ops[i]); num_ops[i]);
check_deps(argv[2+i], op[i], num_ops[i]); check_deps(argv[2+i], op[i], num_ops[i]);
exit(0); exit(0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment