+ if (!quiet)
+ printf("done\n");
+
+ if (end.tv_usec < start.tv_usec) {
+ end.tv_usec += 1000000;
+ end.tv_sec--;
+ }
+ diff.tv_sec = end.tv_sec - start.tv_sec;
+ diff.tv_usec = end.tv_usec - start.tv_usec;
+ return diff;
+}
+
+static void init_tdb(struct tdb_context *master_tdb,
+ const char *name, unsigned int hashsize)
+{
+ TDB_DATA key, data;
+ struct tdb_context *tdb;
+
+ tdb = tdb_open(name, hashsize, TDB_CLEAR_IF_FIRST|TDB_NOSYNC,
+ O_CREAT|O_TRUNC|O_RDWR, 0600);
+ if (!tdb)
+ errx(1, "opening tdb %s", name);
+
+ for (key = tdb_firstkey(master_tdb);
+ key.dptr;
+ key = tdb_nextkey(master_tdb, key)) {
+ data = tdb_fetch(master_tdb, key);
+ if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
+ errx(1, "Failed to store initial key");
+ }
+ tdb_close(tdb);
+}
+
+int main(int argc, char *argv[])
+{
+ struct timeval diff;
+ unsigned int i, num_ops[argc], hashsize[argc], tdb_flags[argc], open_flags[argc];
+ struct op *op[argc];
+ int fds[2];
+ struct tdb_context *master;
+ unsigned int runs = 1;
+
+ if (argc < 3)
+ errx(1, "Usage: %s [--quiet] [-n <number>] <tdbfile> <tracefile>...", argv[0]);
+
+ if (streq(argv[1], "--quiet")) {
+ quiet = true;
+ argv++;
+ argc--;
+ }
+ if (streq(argv[1], "-n")) {
+ runs = atoi(argv[2]);
+ argv += 2;
+ argc -= 2;
+ }
+
+ pipes = talloc_array(NULL, struct pipe, argc - 1);
+ for (i = 0; i < argc - 2; i++) {
+ if (!quiet)
+ printf("Loading tracefile %s...", argv[2+i]);
+ fflush(stdout);
+ op[i] = load_tracefile(argv+2, i, &num_ops[i], &hashsize[i],
+ &tdb_flags[i], &open_flags[i]);
+ if (pipe(pipes[i].fd) != 0)
+ err(1, "creating pipe");
+ /* Don't truncate, or clear if first: we do that. */
+ open_flags[i] &= ~(O_TRUNC);
+ tdb_flags[i] &= ~(TDB_CLEAR_IF_FIRST);
+ /* Open NOSYNC, to save time. */
+ tdb_flags[i] |= TDB_NOSYNC;
+ if (!quiet)
+ printf("done\n");
+ }
+
+ /* Dependency may figure we need to create seed records. */
+ master = tdb_open(NULL, 0, TDB_INTERNAL, O_RDWR, 0);
+ if (!quiet) {
+ printf("Calculating inter-dependencies...");
+ fflush(stdout);
+ }
+ derive_dependencies(master, argv+2, op, num_ops, i);
+ if (!quiet)
+ printf("done\n");
+
+ for (i = 0; i < runs; i++) {
+ init_tdb(master, argv[1], hashsize[0]);
+
+ /* Don't fork for single arg case: simple debugging. */
+ if (argc == 3) {
+ struct timeval start, end;
+ struct tdb_context *tdb;
+
+ tdb = tdb_open(argv[1], hashsize[0], tdb_flags[0],
+ open_flags[0], 0600);
+ if (!quiet) {
+ printf("Single threaded run...");
+ fflush(stdout);
+ }
+ gettimeofday(&start, NULL);
+
+ run_ops(tdb, pipes[0].fd[0], argv+2, op, 0, 1,
+ num_ops[0], false);
+ gettimeofday(&end, NULL);
+ if (!quiet)
+ printf("done\n");
+ tdb_close(tdb);
+
+ check_deps(argv[2], op[0], num_ops[0]);
+ if (end.tv_usec < start.tv_usec) {
+ end.tv_usec += 1000000;
+ end.tv_sec--;
+ }
+ diff.tv_sec = end.tv_sec - start.tv_sec;
+ diff.tv_usec = end.tv_usec - start.tv_usec;
+ goto print_time;
+ }
+
+ if (pipe(fds) != 0)
+ err(1, "creating pipe");
+
+#if TRAVERSALS_TAKE_TRANSACTION_LOCK
+ if (pipe(pipes[argc-2].fd) != 0)
+ err(1, "creating pipe");
+ backoff_fd = pipes[argc-2].fd[1];
+ set_nonblock(pipes[argc-2].fd[1]);
+ set_nonblock(pipes[argc-2].fd[0]);
+#endif
+
+ do {
+ diff = run_test(argv, num_ops, hashsize, tdb_flags,
+ open_flags, op, fds);
+ } while (handle_backoff(op, pipes[argc-2].fd[0]));
+
+ print_time:
+ if (!quiet)
+ printf("Time replaying: ");
+ printf("%lu usec\n", diff.tv_sec * 1000000UL + diff.tv_usec);
+ }