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 @@
/* Avoid mod by zero */
static unsigned int total_keys = 1;
/* #define DEBUG_DEPS 1 */
#define DEBUG_DEPS 1
/* Traversals block transactions in the current implementation. */
#define TRAVERSALS_TAKE_TRANSACTION_LOCK 1
......@@ -404,23 +404,26 @@ static void check_deps(const char *filename, struct op op[], unsigned int num)
#endif
}
static void dump_pre(char *filename[], unsigned int file,
struct op op[], unsigned int i)
static void dump_pre(char *filename[], struct op *op[],
unsigned int file, unsigned int i)
{
struct depend *dep;
printf("%s:%u still waiting for:\n", filename[file], i+1);
list_for_each(&op[i].pre, dep, pre_list)
printf(" %s:%u\n",
filename[dep->satisfies_file], dep->satisfies_opnum+1);
check_deps(filename[file], op, i);
printf("%s:%u (%u) still waiting for:\n", filename[file], i+1,
op[file][i].serial);
list_for_each(&op[file][i].pre, dep, pre_list)
printf(" %s:%u (%u)\n",
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. */
static void do_pre(char *filename[], unsigned int file, int pre_fd,
struct op op[], unsigned int i)
static void do_pre(struct tdb_context *tdb,
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;
#if DEBUG_DEPS
......@@ -430,7 +433,7 @@ static void do_pre(char *filename[], unsigned int file, int pre_fd,
alarm(10);
while (read(pre_fd, &dep, sizeof(dep)) != sizeof(dep)) {
if (errno == EINTR) {
dump_pre(filename, file, op, i);
dump_pre(filename, op, file, i);
exit(1);
} else
errx(1, "Reading from pipe");
......@@ -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,
const struct op op[], unsigned int i)
static void do_post(char *filename[], struct op *op[],
unsigned int file, unsigned int i)
{
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
printf("%s:%u:sending to file %s:%u\n", filename[file], i+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)
static unsigned run_ops(struct tdb_context *tdb,
int pre_fd,
char *filename[],
struct op *op[],
unsigned int file,
struct op op[],
unsigned int start, unsigned int stop);
struct traverse_info {
struct op *op;
struct op **op;
char **filename;
unsigned file;
int pre_fd;
......@@ -492,7 +495,7 @@ static int nontrivial_traverse(struct tdb_context *tdb,
void *_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) {
/* This can happen if traverse expects to be empty. */
......@@ -502,13 +505,13 @@ static int nontrivial_traverse(struct tdb_context *tdb,
"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,
"%s:%u:traverse terminated early");
/* Run any normal ops. */
tinfo->i = run_ops(tdb, tinfo->pre_fd, tinfo->filename, tinfo->file,
tinfo->op, tinfo->i+1, tinfo->start + trav_len);
tinfo->i = run_ops(tdb, tinfo->pre_fd, tinfo->filename, tinfo->op,
tinfo->file, tinfo->i+1, tinfo->start + trav_len);
if (tinfo->i == tinfo->start + trav_len)
return 1;
......@@ -522,7 +525,7 @@ static unsigned op_traverse(struct tdb_context *tdb,
unsigned int file,
int (*traversefn)(struct tdb_context *,
tdb_traverse_func, void *),
struct op op[],
struct op *op[],
unsigned int start)
{
struct traverse_info tinfo = { op, filename, file, pre_fd,
......@@ -533,12 +536,13 @@ static unsigned op_traverse(struct tdb_context *tdb,
/* Traversing in wrong order can have strange effects: eg. if
* original traverse went A (delete A), B, we might do B
* (delete A). So if we have ops left over, we do it now. */
while (tinfo.i != start + op[start].group_len) {
if (op[tinfo.i].op == OP_TDB_TRAVERSE)
while (tinfo.i != start + op[file][start].group_len) {
if (op[file][tinfo.i].op == OP_TDB_TRAVERSE)
tinfo.i++;
else
tinfo.i = run_ops(tdb, pre_fd, filename, file, op,
tinfo.i, start + op[start].group_len);
tinfo.i = run_ops(tdb, pre_fd, filename, op, file,
tinfo.i,
start + op[file][start].group_len);
}
return tinfo.i;
......@@ -552,8 +556,9 @@ static __attribute__((noinline))
unsigned run_ops(struct tdb_context *tdb,
int pre_fd,
char *filename[],
struct op *op[],
unsigned int file,
struct op op[], unsigned int start, unsigned int stop)
unsigned int start, unsigned int stop)
{
unsigned int i;
struct sigaction sa;
......@@ -563,88 +568,98 @@ unsigned run_ops(struct tdb_context *tdb,
sigaction(SIGALRM, &sa, NULL);
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:
try(tdb_lockall(tdb), op[i].ret);
try(tdb_lockall(tdb), op[file][i].ret);
break;
case OP_TDB_LOCKALL_MARK:
try(tdb_lockall_mark(tdb), op[i].ret);
try(tdb_lockall_mark(tdb), op[file][i].ret);
break;
case OP_TDB_LOCKALL_UNMARK:
try(tdb_lockall_unmark(tdb), op[i].ret);
try(tdb_lockall_unmark(tdb), op[file][i].ret);
break;
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));
break;
case OP_TDB_UNLOCKALL:
try(tdb_unlockall(tdb), op[i].ret);
try(tdb_unlockall(tdb), op[file][i].ret);
break;
case OP_TDB_LOCKALL_READ:
try(tdb_lockall_read(tdb), op[i].ret);
try(tdb_lockall_read(tdb), op[file][i].ret);
break;
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_unlockall_read(tdb));
break;
case OP_TDB_UNLOCKALL_READ:
try(tdb_unlockall_read(tdb), op[i].ret);
try(tdb_unlockall_read(tdb), op[file][i].ret);
break;
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;
case OP_TDB_CHAINLOCK_NONBLOCK:
unreliable(tdb_chainlock_nonblock(tdb, op[i].key),
op[i].ret,
tdb_chainlock(tdb, op[i].key),
tdb_chainunlock(tdb, op[i].key));
unreliable(tdb_chainlock_nonblock(tdb, op[file][i].key),
op[file][i].ret,
tdb_chainlock(tdb, op[file][i].key),
tdb_chainunlock(tdb, op[file][i].key));
break;
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;
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;
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;
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;
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;
case OP_TDB_PARSE_RECORD:
try(tdb_parse_record(tdb, op[i].key, get_len, NULL),
op[i].ret);
try(tdb_parse_record(tdb, op[file][i].key, get_len,
NULL),
op[file][i].ret);
break;
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;
case OP_TDB_STORE:
try(tdb_store(tdb, op[i].key, op[i].data, op[i].flag),
op[i].ret);
try(tdb_store(tdb, op[file][i].key, op[file][i].data,
op[file][i].flag),
op[file][i].ret);
break;
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;
case OP_TDB_GET_SEQNUM:
try(tdb_get_seqnum(tdb), op[i].ret);
try(tdb_get_seqnum(tdb), op[file][i].ret);
break;
case OP_TDB_WIPE_ALL:
try(tdb_wipe_all(tdb), op[i].ret);
try(tdb_wipe_all(tdb), op[file][i].ret);
break;
case OP_TDB_TRANSACTION_START:
try(tdb_transaction_start(tdb), op[i].ret);
try(tdb_transaction_start(tdb), op[file][i].ret);
break;
case OP_TDB_TRANSACTION_CANCEL:
try(tdb_transaction_cancel(tdb), op[i].ret);
try(tdb_transaction_cancel(tdb), op[file][i].ret);
break;
case OP_TDB_TRANSACTION_COMMIT:
try(tdb_transaction_commit(tdb), op[i].ret);
try(tdb_transaction_commit(tdb), op[file][i].ret);
break;
case OP_TDB_TRAVERSE_READ_START:
i = op_traverse(tdb, pre_fd, filename, file,
......@@ -662,25 +677,26 @@ unsigned run_ops(struct tdb_context *tdb,
fail(filename[file], i+1, "unexpected end traverse");
/* FIXME: These must be treated like traverse. */
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");
break;
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");
break;
case OP_TDB_FETCH: {
TDB_DATA f = tdb_fetch(tdb, op[i].key);
if (!key_eq(f, op[i].data))
TDB_DATA f = tdb_fetch(tdb, op[file][i].key);
if (!key_eq(f, op[file][i].data))
fail(filename[file], i+1, "bad fetch %u",
f.dsize);
break;
}
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;
}
do_post(filename, file, op, i);
do_post(filename, op, file, i);
}
return i;
}
......@@ -1132,7 +1148,8 @@ struct traverse_dep {
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[],
struct op *op[], unsigned int num_ops[],
unsigned int num)
......@@ -1160,7 +1177,7 @@ static void make_traverse_depends(char *filename[],
/* Count them. */
for (i = 0; i < num; i++) {
for (j = 1; j < num_ops[i]; j++) {
/* Transaction on traverse start. */
/* Transaction or traverse start. */
if (op[i][j].group_start == j) {
dep = talloc_realloc(NULL, dep,
struct traverse_dep,
......@@ -1358,7 +1375,7 @@ int main(int argc, char *argv[])
printf("Single threaded run...");
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]);
printf("done\n");
......@@ -1385,7 +1402,7 @@ int main(int argc, char *argv[])
/* This catches parent exiting. */
if (read(fds[0], &c, 1) != 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]);
check_deps(argv[2+i], op[i], num_ops[i]);
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