Browse Source

Print seq numbers on timeout dump
(Invasive: means passing full op array all the way through).

Rusty Russell 16 years ago
parent
commit
42145b9270
1 changed files with 85 additions and 68 deletions
  1. 85 68
      ccan/tdb/tools/replay_trace.c

+ 85 - 68
ccan/tdb/tools/replay_trace.c

@@ -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)
 #endif
 #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;
 	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. */
 /* 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;
 		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,
 		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,
 	}
 	}
 }
 }
 
 
-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;
 	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)
 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,
 			       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,
 		     "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->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)
 	if (tinfo->i == tinfo->start + trav_len)
 		return 1;
 		return 1;
@@ -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,
 	/* 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) {
-		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++;
 			tinfo.i++;
 		else
 		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;
 	return tinfo.i;
@@ -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,
 
 
 	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),
-				   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;
 			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),
-			    op[i].ret);
+			try(tdb_parse_record(tdb, op[file][i].key, get_len,
+					     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),
-			    op[i].ret);
+			try(tdb_store(tdb, op[file][i].key, op[file][i].data,
+				      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,
 			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);
-			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",
 				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 {
 	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[],
 	/* 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[])
 		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[])
 			/* 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);