Пример #1
0
int
main(int argc, char *argv[])
{
	WT_SESSION *session;
	clock_t ce, cs;
	pthread_t idlist[100];
	uint64_t i, id;
	char buf[100];

	opts = &_opts;
	memset(opts, 0, sizeof(*opts));
	opts->table_type = TABLE_ROW;
	opts->n_append_threads = N_APPEND_THREADS;
	opts->nrecords = N_RECORDS;
	testutil_check(testutil_parse_opts(argc, argv, opts));
	testutil_make_work_dir(opts->home);

	snprintf(buf, sizeof(buf), 
	    "create,"
	    "cache_size=%s,"
	    "eviction=(threads_max=5),"
	    "statistics=(fast)",
	    opts->table_type == TABLE_FIX ? "500MB" : "2GB");
	testutil_check(wiredtiger_open(opts->home, NULL, buf, &opts->conn));
	testutil_check(
	    opts->conn->open_session(opts->conn, NULL, NULL, &session));
	snprintf(buf, sizeof(buf),
	    "key_format=r,value_format=%s,"
	    "allocation_size=4K,leaf_page_max=64K",
	    opts->table_type == TABLE_FIX ? "8t" : "S");
	testutil_check(session->create(session, opts->uri, buf));
	testutil_check(session->close(session, NULL));

	page_init(5000);

	/* Force to disk and re-open. */
	testutil_check(opts->conn->close(opts->conn, NULL));
	testutil_check(wiredtiger_open(opts->home, NULL, NULL, &opts->conn));

	(void)signal(SIGINT, onsig);

	cs = clock();
	id = 0;
	for (i = 0; i < opts->n_append_threads; ++i, ++id) {
		printf("append: %" PRIu64 "\n", id);
		testutil_check(pthread_create(
		    &idlist[id], NULL, thread_append, (void *)opts));
	}

	for (i = 0; i < id; ++i)
		testutil_check(pthread_join(idlist[i], NULL));

	ce = clock();
	printf("%" PRIu64 "M records: %.2lf processor seconds\n",
	    opts->max_inserted_id / MILLION,
	    (ce - cs) / (double)CLOCKS_PER_SEC);

	testutil_cleanup(opts);
	return (EXIT_SUCCESS);
}
Пример #2
0
int
main(int argc, char *argv[])
{
	TEST_OPTS *opts, _opts;
	TEST_PER_THREAD_OPTS thread_args[N_THREADS];
	pthread_t ckpt_thread, mon_thread, threads[N_THREADS];
	int i;

	/*
	 * This test should not run unless long tests flag is set. The test
	 * runs for 15 minutes.
	 */
	if (!testutil_is_flag_set("TESTUTIL_ENABLE_TIMING_TESTS"))
		return (EXIT_SUCCESS);

	opts = &_opts;
	opts->unique_id = 0;
	memset(opts, 0, sizeof(*opts));

	testutil_check(testutil_parse_opts(argc, argv, opts));
	testutil_make_work_dir(opts->home);

	testutil_check(wiredtiger_open(opts->home, &event_handler,
	    "create,cache_size=1G,timing_stress_for_test=[checkpoint_slow]",
	    &opts->conn));

	testutil_check(pthread_create(
	    &ckpt_thread, NULL, do_checkpoints, opts));

	for (i = 0; i < N_THREADS; ++i) {
		thread_args[i].testopts = opts;
		thread_args[i].thread_counter = 0;
		thread_args[i].threadnum = i;
		testutil_check(pthread_create(
		    &threads[i], NULL, do_ops, &thread_args[i]));
	}

	/*
	 * Pass the whole array of thread arguments to the monitoring thread.
	 * This thread will need to monitor each threads counter to track if it
	 * is stuck.
	 */
	testutil_check(pthread_create(&mon_thread, NULL, monitor, thread_args));

	for (i = 0; i < N_THREADS; ++i)
		testutil_check(pthread_join(threads[i], NULL));

	testutil_check(pthread_join(mon_thread, NULL));

	testutil_check(pthread_join(ckpt_thread, NULL));

	printf("Success\n");

	testutil_cleanup(opts);
	return (EXIT_SUCCESS);
}
Пример #3
0
/*
 * subtest_main --
 *	The main program for the subtest
 */
static void
subtest_main(int argc, char *argv[], bool close_test)
{
	struct rlimit rlim;
	TEST_OPTS *opts, _opts;
	WT_SESSION *session;
	char config[1024], filename[1024];

	opts = &_opts;
	memset(opts, 0, sizeof(*opts));
	memset(&rlim, 0, sizeof(rlim));

	/* No core files during fault injection tests. */
	testutil_check(setrlimit(RLIMIT_CORE, &rlim));
	testutil_check(testutil_parse_opts(argc, argv, opts));
	testutil_make_work_dir(opts->home);

	/* Redirect stderr, stdout. */
	testutil_check(__wt_snprintf(
	    filename, sizeof(filename), "%s/%s", opts->home, STDERR_FILE));
	testutil_assert(freopen(filename, "a", stderr) != NULL);
	testutil_check(__wt_snprintf(
	    filename, sizeof(filename), "%s/%s", opts->home, STDOUT_FILE));
	testutil_assert(freopen(filename, "a", stdout) != NULL);
	testutil_check(__wt_snprintf(config, sizeof(config),
	    "create,cache_size=250M,log=(enabled),"
	    "transaction_sync=(enabled,method=none),extensions=("
	    WT_FAIL_FS_LIB
	    "=(early_load,config={environment=true,verbose=true})]"));

	testutil_check(
	    wiredtiger_open(opts->home, &event_handler, config, &opts->conn));
	testutil_check(
	    opts->conn->open_session(opts->conn, NULL, NULL, &session));

	testutil_check(session->create(session, "table:subtest",
	    "key_format=i,value_format=iiiS,"
	    "columns=(id,v0,v1,v2,big)"));

	testutil_check(session->create(session, "table:subtest2",
	    "key_format=i,value_format=i"));

	testutil_check(session->create(session, "index:subtest:v0",
	    "columns=(v0)"));
	testutil_check(session->create(session, "index:subtest:v1",
	    "columns=(v1)"));
	testutil_check(session->create(session, "index:subtest:v2",
	    "columns=(v2)"));

	testutil_check(session->close(session, NULL));

	subtest_populate(opts, close_test);

	testutil_cleanup(opts);
}
Пример #4
0
/*
 * main --
 *	The main program for the test. When invoked with "subtest"
 *	argument, run the subtest. Otherwise, run a separate process
 *	for each needed subtest, and check the results.
 */
int
main(int argc, char *argv[])
{
	TEST_OPTS *opts, _opts;
	uint64_t nresults;
	const char *debugger;

	/* Ignore unless requested */
	if (!testutil_is_flag_set("TESTUTIL_ENABLE_LONG_TESTS"))
		return (EXIT_SUCCESS);

	opts = &_opts;
	memset(opts, 0, sizeof(*opts));
	debugger = NULL;

	testutil_check(testutil_parse_opts(argc, argv, opts));
	argc -= __wt_optind;
	argv += __wt_optind;
	if (opts->nrecords == 0)
		opts->nrecords = 50000;

	while (argc > 0) {
		if (strcmp(argv[0], "subtest") == 0) {
			subtest_main(argc, argv, false);
			return (0);
		} else if (strcmp(argv[0], "subtest_close") == 0) {
			subtest_main(argc, argv, true);
			return (0);
		} else if (strcmp(argv[0], "gdb") == 0)
			debugger = "/usr/bin/gdb";
		else
			testutil_assert(false);
		argc--;
		argv++;
	}
	if (opts->verbose) {
		printf("Number of operations until failure: %" PRIu64
		    "  (change with -o N)\n", opts->nops);
		printf("Number of records: %" PRIu64
		    "  (change with -n N)\n", opts->nrecords);
	}
	if (opts->nops == 0) {
		run_check_subtest_range(opts, debugger, false);
		run_check_subtest_range(opts, debugger, true);
	} else
		run_check_subtest(opts, debugger, opts->nops,
		    opts->nrecords, &nresults);

	testutil_clean_work_dir(opts->home);
	testutil_cleanup(opts);

	return (0);
}
Пример #5
0
int
main(int argc, char *argv[])
{
	TEST_OPTS *opts, _opts;

	opts = &_opts;
	memset(opts, 0, sizeof(*opts));
	testutil_check(testutil_parse_opts(argc, argv, opts));
	testutil_make_work_dir(opts->home);
	testutil_check(
	    wiredtiger_open(opts->home, NULL, "create", &opts->conn));

	/* Run the test. */
	modify_run(opts->verbose);

	testutil_cleanup(opts);
	return (EXIT_SUCCESS);
}
Пример #6
0
int
main(int argc, char *argv[])
{
	TEST_OPTS *opts, _opts;
	WT_CURSOR *balancecur, *flagcur, *joincur, *postcur;
	WT_CURSOR *maincur;
	WT_SESSION *session;
	int balance, count, flag, key, key2, post, ret;
	char balanceuri[256];
	char cfg[128];
	char flaguri[256];
	char joinuri[256];
	char posturi[256];
	const char *tablename;

	opts = &_opts;
	memset(opts, 0, sizeof(*opts));
	testutil_check(testutil_parse_opts(argc, argv, opts));
	testutil_make_work_dir(opts->home);
	testutil_progress(opts, "start");

	testutil_check(wiredtiger_open(opts->home, NULL,
	    "create,cache_size=250M", &opts->conn));
	testutil_progress(opts, "wiredtiger_open");
	testutil_check(
	    opts->conn->open_session(opts->conn, NULL, NULL, &session));
	testutil_progress(opts, "sessions opened");

	/*
	 * Note: repeated primary key 'id' as 'id2'.  This makes
	 * it easier to dump an index and know which record we're
	 * looking at.
	 */
	testutil_check(session->create(session, opts->uri,
	    "key_format=i,value_format=iiii,"
	    "columns=(id,post,balance,flag,id2)"));

	tablename = strchr(opts->uri, ':');
	testutil_assert(tablename != NULL);
	tablename++;
	testutil_check(__wt_snprintf(
	    posturi, sizeof(posturi), "index:%s:post", tablename));
	testutil_check(__wt_snprintf(
	    balanceuri, sizeof(balanceuri), "index:%s:balance", tablename));
	testutil_check(__wt_snprintf(
	    flaguri, sizeof(flaguri), "index:%s:flag", tablename));
	testutil_check(__wt_snprintf(
	    joinuri, sizeof(joinuri), "join:%s", opts->uri));

	testutil_check(session->create(session, posturi, "columns=(post)"));
	testutil_check(session->create(session, balanceuri,
	    "columns=(balance)"));
	testutil_check(session->create(session, flaguri, "columns=(flag)"));
	testutil_progress(opts, "setup complete");

	/*
	 * Insert a single record with all items we are search for,
	 * this makes our logic easier.
	 */
	testutil_check(session->open_cursor(session, opts->uri, NULL, NULL,
	    &maincur));
	maincur->set_key(maincur, N_RECORDS);
	maincur->set_value(maincur, 54321, 0, "", 0, N_RECORDS);
	testutil_check(maincur->insert(maincur));
	testutil_check(maincur->close(maincur));
	testutil_check(session->close(session, NULL));

	testutil_progress(opts, "populate start");
	populate(opts);
	testutil_progress(opts, "populate end");

	testutil_check(opts->conn->open_session(
	    opts->conn, NULL, NULL, &session));

	testutil_check(session->open_cursor(session,
	    posturi, NULL, NULL, &postcur));
	testutil_check(session->open_cursor(session,
	    balanceuri, NULL, NULL, &balancecur));
	testutil_check(session->open_cursor(session,
	    flaguri, NULL, NULL, &flagcur));
	testutil_check(session->open_cursor(session,
	    joinuri, NULL, NULL, &joincur));

	postcur->set_key(postcur, 54321);
	testutil_check(postcur->search(postcur));
	testutil_check(session->join(session, joincur, postcur,
	    "compare=eq"));

	balancecur->set_key(balancecur, 0);
	testutil_check(balancecur->search(balancecur));
	testutil_check(__wt_snprintf(cfg, sizeof(cfg),
	    "compare=lt,strategy=bloom,count=%d", N_RECORDS / 100));
	testutil_check(session->join(session, joincur, balancecur, cfg));

	flagcur->set_key(flagcur, 0);
	testutil_check(flagcur->search(flagcur));
	testutil_check(__wt_snprintf(cfg, sizeof(cfg),
	    "compare=eq,strategy=bloom,count=%d", N_RECORDS / 100));
	testutil_check(session->join(session, joincur, flagcur, cfg));

	/* Expect no values returned */
	count = 0;
	while ((ret = joincur->next(joincur)) == 0) {
		/*
		 * The values may already have been changed, but
		 * print them for informational purposes.
		 */
		testutil_check(joincur->get_key(joincur, &key));
		testutil_check(joincur->get_value(joincur, &post,
		    &balance, &flag, &key2));
		fprintf(stderr, "FAIL: "
		    "key=%d/%d, postal_code=%d, balance=%d, flag=%d\n",
		    key, key2, post, balance, flag);
		count++;
	}
	testutil_assert(ret == WT_NOTFOUND);
	testutil_assert(count == 0);

	testutil_progress(opts, "cleanup starting");
	testutil_cleanup(opts);
	return (EXIT_SUCCESS);
}
Пример #7
0
int main(void)
{
    int p1[2], p2[2];
    remsh_xport *wxp, *rxp;
    remsh_wire *wwire, *rwire;
    int eof;
    int status;
    char my_cwd[PATH_MAX];

    testutil_init();

    test_is_not_null(getcwd(my_cwd, PATH_MAX),
            "get test directory");

    if (pipe(p1) < 0 || pipe(p2) < 0) {
        perror("pipe");
        return 1;
    }

    /* fork the slave */
    switch (fork()) {
        case 0:
            rwire = remsh_wire_new(remsh_fd_xport_new(p2[0]));
            wwire = remsh_wire_new(remsh_fd_xport_new(p1[1]));
            close(p2[1]);
            close(p1[0]);

            remsh_op_init();

            eof = 0;
            while (1) {
                int rv = remsh_op_perform(rwire, wwire, &eof);
                if (rv < 0)
                    return 1;
                if (eof) {
                    return 0;
                }
            }
            return 0;

        case -1:
            perror("fork");
            return 1;

        default:
            ; /* fall through */
    }

    rwire = remsh_wire_new(rxp = remsh_fd_xport_new(p1[0]));
    wwire = remsh_wire_new(wxp = remsh_fd_xport_new(p2[1]));
    close(p1[1]);
    close(p2[0]);

    /* return the current dir */
    {
        int keycount;
        remsh_box box[] = {
            { 0, "meth", 7, "set_cwd", },
            { 0, "version", 1, "1", },
            { 0, "cwd", 0, NULL },
            { 0, NULL, 0, NULL, },
        };
        remsh_box result[] = {
            { 0, "cwd", 0, NULL, },
            { 0, NULL, 0, NULL, },
        };
        char *cwd;
        remsh_box *res;

        test_call_ok(remsh_wire_send_box(wwire, box), NULL,
                "send box");
        test_call_ok(remsh_wire_read_box(rwire, &res), NULL,
                "read response");
        test_is_int(box_len(res), 1,
                "response has one key");
        remsh_wire_box_extract(res, result);
        test_is_str(result[0].val, my_cwd,
                "and it is cwd and has the right value");
    }

    /* enter a nonexistent directory */
    {
        int keycount;
        remsh_box box[] = {
            { 0, "meth", 7, "set_cwd", },
            { 0, "version", 1, "1", },
            { 0, "cwd", 14, "does/not/exist" },
            { 0, NULL, 0, NULL, },
        };
        remsh_box *res;

        test_call_ok(remsh_wire_send_box(wwire, box), NULL,
                "send box");
        test_call_ok(remsh_wire_read_box(rwire, &res), NULL,
                "read response");
        test_is_errbox(res, "notfound",
                "returns 'notfound' for nonexistent directory");
    }

    /* enter an existing directory */
    {
        int keycount;
        remsh_box box[] = {
            { 0, "meth", 7, "set_cwd", },
            { 0, "version", 1, "1", },
            { 0, "cwd", 6, "exists" },
            { 0, NULL, 0, NULL, },
        };
        remsh_box result[] = {
            { 0, "cwd", 0, NULL, },
            { 0, NULL, 0, NULL, },
        };
        char *expected;
        remsh_box *res;

        test_call_ok(mkdir("exists", 0777), strerror(errno),
                "make test directory");
        expected = malloc(strlen(my_cwd) + 7 + 1);
        sprintf(expected, "%s/exists", my_cwd);

        test_call_ok(remsh_wire_send_box(wwire, box), NULL,
                "send box");
        test_call_ok(remsh_wire_read_box(rwire, &res), NULL,
                "read response");
        remsh_wire_box_extract(res, result);
        test_is_str(result[0].val, expected,
                "new directory is correct");
        free(expected);
    }

    /* reset to the base dir */
    {
        int keycount;
        remsh_box box[] = {
            { 0, "meth", 7, "set_cwd", },
            { 0, "version", 1, "1", },
            { 0, NULL, 0, NULL, },
        };
        remsh_box result[] = {
            { 0, "cwd", 0, NULL, },
            { 0, NULL, 0, NULL, },
        };
        char *cwd;
        remsh_box *res;

        test_call_ok(remsh_wire_send_box(wwire, box), NULL,
                "send box");
        test_call_ok(remsh_wire_read_box(rwire, &res), NULL,
                "read response");
        test_is_int(box_len(res), 1,
                "response has one key");
        remsh_wire_box_extract(res, result);
        test_is_str(result[0].val, my_cwd,
                "and it is cwd and has the right value");
    }

    /* send EOF to the child */
    remsh_xport_close(rxp);
    remsh_xport_close(wxp);

    /* this side completed successfully, so wait for the child */
    if (wait(&status) < 0) {
        perror("wait");
        return 1;
    }

    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
        printf("child did not exit cleanly: %d\n", WEXITSTATUS(status));
        return 1;
    }

    testutil_cleanup();
    return 0;
}
Пример #8
0
int
main(int argc, char *argv[])
{
	TEST_OPTS *opts, _opts;
	WT_CURSOR *c;
	WT_SESSION *session;
	clock_t ce, cs;
	pthread_t id[100];
	uint64_t current_value;
	int i;

	opts = &_opts;
	if (testutil_disable_long_tests())
		return (0);
	memset(opts, 0, sizeof(*opts));
	opts->nthreads = 10;
	opts->nrecords = 1000;
	opts->table_type = TABLE_ROW;
	testutil_check(testutil_parse_opts(argc, argv, opts));
	testutil_make_work_dir(opts->home);

	testutil_check(wiredtiger_open(opts->home, NULL,
	    "create,"
	    "cache_size=2G,"
	    "eviction=(threads_max=5),"
	    "statistics=(fast)", &opts->conn));
	testutil_check(
	    opts->conn->open_session(opts->conn, NULL, NULL, &session));
	testutil_check(session->create(session, opts->uri,
	    "key_format=Q,value_format=Q,"
	    "leaf_page_max=32k,"));

	/* Create the single record. */
	testutil_check(
	    session->open_cursor(session, opts->uri, NULL, NULL, &c));
	c->set_key(c, 1);
	c->set_value(c, 0);
	testutil_check(c->insert(c));
	testutil_check(c->close(c));
	cs = clock();
	for (i = 0; i < (int)opts->nthreads; ++i) {
		testutil_check(pthread_create(
		    &id[i], NULL, thread_insert_race, (void *)opts));
	}
	while (--i >= 0)
		testutil_check(pthread_join(id[i], NULL));
	testutil_check(
	    session->open_cursor(session, opts->uri, NULL, NULL, &c));
	c->set_key(c, 1);
	testutil_check(c->search(c));
	testutil_check(c->get_value(c, &current_value));
	if (current_value != opts->nthreads * opts->nrecords) {
		fprintf(stderr,
		    "ERROR: didn't get expected number of changes\n");
		fprintf(stderr, "got: %" PRIu64 ", expected: %" PRIu64 "\n",
		    current_value, opts->nthreads * opts->nrecords);
		return (EXIT_FAILURE);
	}
	testutil_check(session->close(session, NULL));
	ce = clock();
	printf("%" PRIu64 ": %.2lf\n",
	    opts->nrecords, (ce - cs) / (double)CLOCKS_PER_SEC);

	testutil_cleanup(opts);
	return (EXIT_SUCCESS);
}
Пример #9
0
int
main(int argc, char *argv[])
{
	enum { CACHE_SHARED, CACHE_SET, CACHE_NONE } cache;
	TEST_OPTS *opts, _opts;
	WT_RAND_STATE rnd;
	WT_SESSION *session;
	size_t len;
	u_int i, j;
	const char *p;
	char *config;

	opts = &_opts;
	memset(opts, 0, sizeof(*opts));
	opts->table_type = TABLE_ROW;
	testutil_check(testutil_parse_opts(argc, argv, opts));
	testutil_make_work_dir(opts->home);

	testutil_check(
	    wiredtiger_open(opts->home, &event_handler, "create", &opts->conn));

	/* Open an LSM file so the LSM reconfiguration options make sense. */
	testutil_check(
	    opts->conn->open_session(opts->conn, NULL, NULL, &session));
	testutil_check(session->create(
	    session, opts->uri, "type=lsm,key_format=S,value_format=S"));

	/* Initialize the RNG. */
	__wt_random_init_seed(NULL, &rnd);

	/* Allocate memory for the config. */
	len = WT_ELEMENTS(list) * 64;
	config = dmalloc(len);

	/* Set an alarm so we can debug hangs. */
	(void)signal(SIGALRM, on_alarm);

	/* A linear pass through the list. */
	for (i = 0; i < WT_ELEMENTS(list); ++i)
		reconfig(opts, session, list[i]);

	/*
	 * A linear pass through the list, adding random elements.
	 *
	 * WiredTiger configurations are usually "the last one set wins", but
	 * "shared_cache" and "cache_set" options aren't allowed in the same
	 * configuration string.
	 */
	for (i = 0; i < WT_ELEMENTS(list); ++i) {
		p = list[i];
		cache = CACHE_NONE;
		if (WT_PREFIX_MATCH(p, ",shared_cache"))
			cache = CACHE_SHARED;
		else if (WT_PREFIX_MATCH(p, ",cache_size"))
			cache = CACHE_SET;
		strcpy(config, p);

		for (j =
		    (__wt_random(&rnd) % WT_ELEMENTS(list)) + 1; j > 0; --j) {
			p = list[__wt_random(&rnd) % WT_ELEMENTS(list)];
			if (WT_PREFIX_MATCH(p, ",shared_cache")) {
				if (cache == CACHE_SET)
					continue;
				cache = CACHE_SHARED;
			} else if (WT_PREFIX_MATCH(p, ",cache_size")) {
				if (cache == CACHE_SHARED)
					continue;
				cache = CACHE_SET;
			}
			strcat(config, p);
		}
		reconfig(opts, session, config);
	}

	/*
	 * Turn on-close statistics off, if on-close is on and statistics were
	 * randomly turned off during the run, close would fail.
	 */
	testutil_check(opts->conn->reconfigure(
	    opts->conn, "statistics_log=(on_close=0)"));

	free(config);
	testutil_cleanup(opts);
	return (EXIT_SUCCESS);
}
Пример #10
0
int
main(int argc, char *argv[])
{
	TEST_OPTS *opts, _opts;
	WT_CURSOR *cursor, *cursor1;
	WT_ITEM got, k, v;
	WT_SESSION *session;
	int32_t ki, vi;

	opts = &_opts;
	memset(opts, 0, sizeof(*opts));
	testutil_check(testutil_parse_opts(argc, argv, opts));
	testutil_make_work_dir(opts->home);

	testutil_check(wiredtiger_open(opts->home, NULL, "create",
	    &opts->conn));
	testutil_check(
	    opts->conn->open_session(opts->conn, NULL, NULL, &session));

	testutil_check(opts->conn->add_collator(opts->conn, "index_coll",
	    &index_coll, NULL));

	testutil_check(session->create(session,
	    "table:main", "key_format=u,value_format=u,columns=(k,v)"));
	testutil_check(session->create(session,
	    "index:main:index", "columns=(v),collator=index_coll"));

	printf("adding new record\n");
	testutil_check(session->open_cursor(session, "table:main", NULL, NULL,
	    &cursor));

	ki = 13;
	vi = 17;

	k.data = &ki; k.size = sizeof(ki);
	v.data = &vi; v.size = sizeof(vi);

	cursor->set_key(cursor, &k);
	cursor->set_value(cursor, &v);
	testutil_check(cursor->insert(cursor));
	testutil_check(cursor->close(cursor));

	printf("positioning index cursor\n");

	testutil_check(session->open_cursor(session, "index:main:index", NULL,
	    NULL, &cursor));
	cursor->set_key(cursor, &v);
	testutil_check(cursor->search(cursor));

	printf("duplicating cursor\n");
	testutil_check(session->open_cursor(session, NULL, cursor, NULL,
	    &cursor1));
	testutil_check(cursor->get_value(cursor, &got));
	testutil_assert(item_to_int(&got) == 17);
	testutil_check(cursor1->get_value(cursor1, &got));
	testutil_assert(item_to_int(&got) == 17);

	testutil_check(session->close(session, NULL));
	testutil_cleanup(opts);
	return (EXIT_SUCCESS);
}
Пример #11
0
Файл: wire.c Проект: cnh/remsh
int main(void)
{
    int p[2];
    remsh_xport *wxp, *rxp;
    remsh_wire *wwire, *rwire;
    char *str;

    testutil_init();

    if (pipe(p) < 0) {
        perror("pipe");
        return 1;
    }

    rxp = remsh_fd_xport_new(p[0]);
    rwire = remsh_wire_new(rxp);

    wxp = remsh_fd_xport_new(p[1]);
    wwire = remsh_wire_new(wxp);

    /* test writing */
    {
        char buf[256];
        remsh_box box[] = {
            { 4, "name", 4, "lark", },
            { 1, "x", 0, "", },
            { 0, "hloxwfxotvcaq", 1, "z", },
            { 0, NULL, 0, NULL, },
        };
        char expected[] =
            "\x00\x04name"          "\x00\x04lark"
            "\x00\x01x"             "\x00\x00"
            "\x00\x0dhloxwfxotvcaq" "\x00\x01z"
            "\x00\x00";
        remsh_box badbox[] = {
            { 0, "", 4, "nono", },
            { 0, NULL, 0, NULL, },
        };

        test_call_ok(remsh_wire_send_box(wwire, box), NULL,
                "send box 1");
        test_is_int(remsh_xport_read(rxp, buf, sizeof(buf)), sizeof(expected)-1,
                "read correct size");
        test_is_int(memcmp(buf, expected, sizeof(expected)-1), 0,
                "buffer data matches (binary)");
        test_is_int(remsh_wire_send_box(wwire, badbox), -1,
                "send bad box");
    }

    /* test reading */
    {
        char data[] =
            "\x00\x04name"          "\x00\x04lark"
            "\x00\x01x"             "\x00\x00"
            "\x00\x0dhloxwfxotvcaq" "\x00\x01z"
            "\x00\x00"

            "\x00\x01x"             "\x01\x00"
             "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
             "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
             "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
             "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
            "\x00\x01y"             "\x00\x01x"
            "\x00\x00";
        remsh_box get1[] = {
            { 4, "name", 0, NULL, },
            { 0, NULL, 0, NULL, },
        };
        remsh_box get2[] = {
            { 13, "hloxwfxotvcaq", 0, NULL, },
            { 0, "x", 0, NULL, },
            { 0, NULL, 0, NULL, },
        };
        remsh_box get3[] = {
            { 0, "y", 0, NULL, },
            { 0, "x", 0, NULL, },
            { 0, "z", 0, (char *)13, },
            { 0, NULL, 0, NULL, },
        };
        remsh_box *res;

        test_call_ok(remsh_xport_write(wxp, data, sizeof(data)-1), wxp->errmsg,
                "write data");
        test_call_ok(remsh_wire_read_box(rwire, &res), NULL,
                "read first box");
        test_is_int(box_len(res), 3,
                "first box length is correct");

        test_is_str((str = remsh_wire_box_repr(res)),
                "{ \"name\" : \"lark\", \"x\" : \"\", \"hloxwfxotvcaq\" : \"z\", }",
                "box repr is correct");
        free(str);

        remsh_wire_box_extract(res, get1);
        test_is_str(get1[0].val, "lark",
                "extracted correct value");

        remsh_wire_box_extract(res, get2);
        test_is_str(get2[0].val, "z",
                "extracted correct value");
        test_is_int(get2[1].val_len, 0,
                "x is empty");
        test_is_not_null(get2[1].val,
                "x is not NULL");

        test_call_ok(remsh_wire_read_box(rwire, &res), NULL,
                "read second box");
        test_is_int(box_len(res), 2,
                "second box has two elements");

        remsh_wire_box_extract(res, get3);
        test_is_str(get3[0].val, "x",
                "short value is correct");
        test_is_int(get3[1].val_len, 0x100,
                "long value len is correct");
        test_is_null(get3[2].val,
                "nonexistent key returned NULL");
    }

    /* test writing */
    {
        remsh_box box1[] = {
            { 0, "meth", 4, "edit", },
            { 0, "version", 1, "2", },
            { 6, "object", 5, "fe\091", },
            { 0, NULL, 0, NULL, },
        };
        remsh_box box2[] = {
            { 0, "meth", 4, "save", },
            { 0, "version", 1, "3", },
            { 4, "data", 0, "" },
            { 6, "object", 5, "fe\091", },
            { 0, NULL, 0, NULL, },
        };

        char data[] =
            "\x00\x04""meth"          "\x00\x04""edit"
            "\x00\x07""version"       "\x00\x01""2"
            "\x00\x06""object"        "\x00\x05""fe\091"
            "\x00\x00" /* 41 bytes */

            "\x00\x04""meth"          "\x00\x04""save"
            "\x00\x07""version"       "\x00\x01""3"
            "\x00\x04""data"          "\x00\x00"
            "\x00\x06""object"        "\x00\x05""fe\091"
            "\x00\x00"; /* 49 bytes */
        char buf[1024];

        test_call_ok(remsh_wire_send_box(wwire, box1), NULL,
                "send first box");
        test_call_ok(remsh_wire_send_box(wwire, box2), NULL,
                "send second box");
        test_is_int(remsh_xport_read(rxp, buf, sizeof(buf)), 90,
                "two boxes take up 90 bytes");
        test_is_int(memcmp(buf, data, 90), 0,
                "binary data matches");
    }

    testutil_cleanup();
    return 0;
}
Пример #12
0
int
main(int argc, char *argv[])
{
	POP_RECORD *p;
	TEST_OPTS *opts, _opts;
	WT_CURSOR *country_cursor, *country_cursor2, *cursor, *join_cursor,
	    *subjoin_cursor, *year_cursor;
	WT_SESSION *session;
	const char *country, *tablename;
	char countryuri[256], joinuri[256], yearuri[256];
	uint64_t recno, population;
	uint16_t year;
	int count, ret;

	opts = &_opts;
	memset(opts, 0, sizeof(*opts));
	testutil_check(testutil_parse_opts(argc, argv, opts));
	testutil_make_work_dir(opts->home);

	tablename = strchr(opts->uri, ':');
	testutil_assert(tablename != NULL);
	tablename++;
	snprintf(countryuri, sizeof(countryuri), "index:%s:country", tablename);
	snprintf(yearuri, sizeof(yearuri), "index:%s:year", tablename);
	snprintf(joinuri, sizeof(joinuri), "join:%s", opts->uri);

	testutil_check(wiredtiger_open(opts->home, NULL,
	    "create,cache_size=200M", &opts->conn));
	testutil_check(
	    opts->conn->open_session(opts->conn, NULL, NULL, &session));
	testutil_check(session->create(session, opts->uri,
	    "key_format=r,"
	    "value_format=5sHQ,"
	    "columns=(id,country,year,population)"));

	/* Create an index with a simple key. */
	testutil_check(session->create(session,
	    countryuri, "columns=(country)"));

	/* Create an immutable index. */
	testutil_check(session->create(session,
	    yearuri, "columns=(year),immutable"));

	/* Insert the records into the table. */
	testutil_check(session->open_cursor(
	    session, opts->uri, NULL, "append", &cursor));
	count = 1;
	for (p = pop_data; p->year != 0; p++) {
		cursor->set_key(cursor, count);
		cursor->set_value(cursor, p->country, p->year, p->population);
		testutil_check(cursor->insert(cursor));
		count++;
	}
	testutil_check(cursor->close(cursor));

	/* Open cursors needed by the join. */
	testutil_check(session->open_cursor(session,
	    joinuri, NULL, NULL, &join_cursor));
	testutil_check(session->open_cursor(session,
	    countryuri, NULL, NULL, &country_cursor));
	testutil_check(session->open_cursor(session,
	    yearuri, NULL, NULL, &year_cursor));

	/* select values WHERE country == "AU" AND year > 1900 */
	country_cursor->set_key(country_cursor, "AU\0\0\0");
	testutil_check(country_cursor->search(country_cursor));
	testutil_check(session->join(session, join_cursor, country_cursor,
	    "compare=eq,count=10"));
	year_cursor->set_key(year_cursor, (uint16_t)1900);
	testutil_check(year_cursor->search(year_cursor));
	testutil_check(session->join(session, join_cursor, year_cursor,
	    "compare=gt,count=10,strategy=bloom"));

	count = 0;
	/* List the values that are joined */
	while ((ret = join_cursor->next(join_cursor)) == 0) {
		testutil_check(join_cursor->get_key(join_cursor, &recno));
		testutil_check(join_cursor->get_value(join_cursor, &country,
		    &year, &population));
		printf("ID %" PRIu64, recno);
		printf(
		    ": country %s, year %" PRIu16 ", population %" PRIu64 "\n",
		    country, year, population);
		count++;
	}
	testutil_assert(ret == WT_NOTFOUND);
	testutil_assert(count == 2);

	testutil_check(join_cursor->close(join_cursor));
	testutil_check(year_cursor->close(year_cursor));
	testutil_check(country_cursor->close(country_cursor));

	/* Open cursors needed by the join. */
	testutil_check(session->open_cursor(session,
	    joinuri, NULL, NULL, &join_cursor));
	testutil_check(session->open_cursor(session,
	    joinuri, NULL, NULL, &subjoin_cursor));
	testutil_check(session->open_cursor(session,
	    countryuri, NULL, NULL, &country_cursor));
	testutil_check(session->open_cursor(session,
	    countryuri, NULL, NULL, &country_cursor2));
	testutil_check(session->open_cursor(session,
	    yearuri, NULL, NULL, &year_cursor));

	/*
	 * select values WHERE (country == "AU" OR country == "UK")
	 *                     AND year > 1900
	 *
	 * First, set up the join representing the country clause.
	 */
	country_cursor->set_key(country_cursor, "AU\0\0\0");
	testutil_check(country_cursor->search(country_cursor));
	testutil_check(session->join(session, subjoin_cursor, country_cursor,
	    "operation=or,compare=eq,count=10"));
	country_cursor2->set_key(country_cursor2, "UK\0\0\0");
	testutil_check(country_cursor2->search(country_cursor2));
	testutil_check(session->join(session, subjoin_cursor, country_cursor2,
	    "operation=or,compare=eq,count=10"));

	/* Join that to the top join, and add the year clause */
	testutil_check(session->join(session, join_cursor, subjoin_cursor,
	    NULL));
	year_cursor->set_key(year_cursor, (uint16_t)1900);
	testutil_check(year_cursor->search(year_cursor));
	testutil_check(session->join(session, join_cursor, year_cursor,
	    "compare=gt,count=10,strategy=bloom"));

	count = 0;
	/* List the values that are joined */
	while ((ret = join_cursor->next(join_cursor)) == 0) {
		testutil_check(join_cursor->get_key(join_cursor, &recno));
		testutil_check(join_cursor->get_value(join_cursor, &country,
		    &year, &population));
		printf("ID %" PRIu64, recno);
		printf(
		    ": country %s, year %" PRIu16 ", population %" PRIu64 "\n",
		    country, year, population);
		count++;
	}
	testutil_assert(ret == WT_NOTFOUND);
	testutil_assert(count == 4);

	testutil_check(join_cursor->close(join_cursor));
	testutil_check(subjoin_cursor->close(subjoin_cursor));
	testutil_check(country_cursor->close(country_cursor));
	testutil_check(country_cursor2->close(country_cursor2));
	testutil_check(year_cursor->close(year_cursor));
	testutil_check(session->close(session, NULL));

	testutil_cleanup(opts);
	return (EXIT_SUCCESS);
}
Пример #13
0
int
main(int argc, char *argv[])
{
	/*
	 * Add a bunch of tables so that some of the metadata ends up on
	 * other pages and a good number of tables are available after
	 * salvage completes.
	 */
	TABLE_INFO table_data[] = {
		{ "file:aaa-file.SS", "key_format=S,value_format=S", false },
		{ "file:bbb-file.rS", "key_format=r,value_format=S", false },
		{ "lsm:ccc-lsm.SS", "key_format=S,value_format=S", false },
		{ "table:ddd-table.SS", "key_format=S,value_format=S", false },
		{ "table:eee-table.rS", "key_format=r,value_format=S", false },
		{ "file:fff-file.SS", "key_format=S,value_format=S", false },
		{ "file:ggg-file.rS", "key_format=r,value_format=S", false },
		{ "lsm:hhh-lsm.SS", "key_format=S,value_format=S", false },
		{ "table:iii-table.SS", "key_format=S,value_format=S", false },
		{ "table:jjj-table.rS", "key_format=r,value_format=S", false },
		{ CORRUPT, "key_format=S,value_format=S", false },
		{ NULL, NULL, false }
	};
	TABLE_INFO *t;
	TEST_OPTS *opts, _opts;
	int ret;
	char buf[1024];

	opts = &_opts;
	memset(opts, 0, sizeof(*opts));
	testutil_check(testutil_parse_opts(argc, argv, opts));
	/*
	 * Set a global. We use this everywhere.
	 */
	home = opts->home;
	testutil_make_work_dir(home);

	testutil_check(
	    wiredtiger_open(home, &event_handler, "create", &opts->conn));

	testutil_check(opts->conn->open_session(
	    opts->conn, NULL, NULL, &wt_session));
	/*
	 * Create a bunch of different tables.
	 */
	for (t = table_data; t->name != NULL; t++)
		create_data(t);

	/*
	 * Take some checkpoints and add more data for out of sync testing.
	 */
	make_database_copies(table_data);
	testutil_check(opts->conn->close(opts->conn, NULL));
	opts->conn = NULL;

	/*
	 * Make copy of original directory.
	 */
	copy_database(SAVE);
	/*
	 * Damage/corrupt WiredTiger.wt.
	 */
	printf("corrupt metadata\n");
	corrupt_metadata();
	testutil_check(__wt_snprintf(buf, sizeof(buf),
	    "cp -p %s/WiredTiger.wt ./%s.SAVE/WiredTiger.wt.CORRUPT",
	    home, home));
	printf("copy: %s\n", buf);
	if ((ret = system(buf)) < 0)
		testutil_die(ret, "system: %s", buf);
	run_all_verification(NULL, &table_data[0]);

	out_of_sync(&table_data[0]);

	/*
	 * We need to set up the string before we clean up
	 * the structure. Then after the clean up we will
	 * run this command.
	 */
	testutil_check(__wt_snprintf(buf, sizeof(buf),
	    "rm -rf core* %s*", home));
	testutil_cleanup(opts);

	/*
	 * We've created a lot of extra directories and possibly some core
	 * files from child process aborts. Manually clean them up.
	 */
	printf("cleanup and remove: %s\n", buf);
	if ((ret = system(buf)) < 0)
		testutil_die(ret, "system: %s", buf);

	return (EXIT_SUCCESS);
}
Пример #14
0
int
main(int argc, char *argv[])
{
	TEST_OPTS *opts, _opts;
	WT_CURSOR *rcursor, *wcursor;
	WT_ITEM key, value;
	WT_SESSION *session, *session2;
	pthread_t thread;
	uint64_t i;

	char str[] = "0000000000000000";

	/*
	 * Create a clean test directory for this run of the test program if the
	 * environment variable isn't already set (as is done by make check).
	 */
	opts = &_opts;
	memset(opts, 0, sizeof(*opts));
	testutil_check(testutil_parse_opts(argc, argv, opts));
	testutil_make_work_dir(opts->home);
	testutil_check(wiredtiger_open(opts->home,
	    NULL, "create,cache_size=200M", &opts->conn));

	testutil_check(
	    opts->conn->open_session(opts->conn, NULL, NULL, &session));
	testutil_check(
	    opts->conn->open_session(opts->conn, NULL, NULL, &session2));

	testutil_check(session->create(session, name,
	    "key_format=Q,value_format=S"));

	/* Populate the table with some data. */
	testutil_check(session->open_cursor(
	    session, name, NULL, "overwrite", &wcursor));
	for (i = 0; i < NUM_DOCS; i++) {
		wcursor->set_key(wcursor, i);
		rand_str(i, str);
		wcursor->set_value(wcursor, str);
		testutil_check(wcursor->insert(wcursor));
	}
	testutil_check(wcursor->close(wcursor));
	printf("%d documents inserted\n", NUM_DOCS);

	/* Perform some random reads */
	testutil_check(session->open_cursor(
	    session, name, NULL, "next_random=true", &rcursor));
	query_docs(rcursor, false);
	testutil_check(rcursor->close(rcursor));

	/* Setup Transaction to pin the current values */
	testutil_check(
	    session2->begin_transaction(session2, "isolation=snapshot"));
	testutil_check(session2->open_cursor(
	    session2, name, NULL, "next_random=true", &rcursor));

	/* Perform updates in a txn to confirm that we see only the original. */
	testutil_check(session->open_cursor(
	    session, name, NULL, "overwrite", &wcursor));
	for (i = 0; i < NUM_DOCS; i++) {
		rand_str(i, str);
		str[0] = 'A';
		wcursor->set_key(wcursor, i);
		wcursor->set_value(wcursor, str);
		testutil_check(wcursor->update(wcursor));
	}
	testutil_check(wcursor->close(wcursor));
	printf("%d documents set to update\n", NUM_DOCS);

	/* Random reads, which should see the original values */
	query_docs(rcursor, false);
	testutil_check(rcursor->close(rcursor));

	/* Finish the txn */
	testutil_check(session2->rollback_transaction(session2, NULL));

	/* Random reads, which should see the updated values */
	testutil_check(session2->open_cursor(
	    session2, name, NULL, "next_random=true", &rcursor));
	query_docs(rcursor, true);
	testutil_check(rcursor->close(rcursor));

	/* Setup a pre-delete txn */
	testutil_check(
	    session2->begin_transaction(session2, "isolation=snapshot"));
	testutil_check(session2->open_cursor(
	    session2, name, NULL, "next_random=true", &rcursor));

	/* Delete all but one document */
	testutil_check(session->open_cursor(
	    session, name, NULL, "overwrite", &wcursor));
	for (i = 0; i < NUM_DOCS - 1; i++) {
		wcursor->set_key(wcursor, i);
		testutil_check(wcursor->remove(wcursor));
	}
	testutil_check(wcursor->close(wcursor));
	printf("%d documents deleted\n", NUM_DOCS - 1);

	/* Random reads, which should not see the deletes */
	query_docs(rcursor, true);
	testutil_check(rcursor->close(rcursor));

	/* Rollback the txn so we can see the deletes */
	testutil_check(session2->rollback_transaction(session2, NULL));

	/* Find the one remaining document 3 times */
	testutil_check(session2->open_cursor(
	    session2, name, NULL, "next_random=true", &rcursor));
	for (i = 0; i < 3; i++) {
		testutil_check(rcursor->next(rcursor));
		testutil_check(rcursor->get_key(rcursor, &key));
		testutil_check(rcursor->get_value(rcursor, &value));
		/* There should only be one value available to us */
		testutil_assertfmt((uint64_t)key.data == NUM_DOCS - 1,
		    "expected %d and got %" PRIu64,
		    NUM_DOCS - 1, (uint64_t)key.data);
		check_str((uint64_t)key.data, (char *)value.data, true);
	}
	printf("Found the deleted doc 3 times\n");
	testutil_check(rcursor->close(rcursor));

	/* Repopulate the table for compact. */
	testutil_check(session->open_cursor(
	    session, name, NULL, "overwrite", &wcursor));
	for (i = 0; i < NUM_DOCS - 1; i++) {
		wcursor->set_key(wcursor, i);
		rand_str(i, str);
		str[0] = 'A';
		wcursor->set_value(wcursor, str);
		testutil_check(wcursor->insert(wcursor));
	}
	testutil_check(wcursor->close(wcursor));

	/* Run random cursor queries while compact is running */
	testutil_check(session2->open_cursor(
	    session2, name, NULL, "next_random=true", &rcursor));
	testutil_check(pthread_create(&thread, NULL, compact_thread, session));
	query_docs(rcursor, true);
	testutil_check(rcursor->close(rcursor));
	testutil_check(pthread_join(thread, NULL));

	/* Delete everything. Check for infinite loops */
	testutil_check(session->open_cursor(
	    session, name, NULL, "overwrite", &wcursor));
	for (i = 0; i < NUM_DOCS; i++) {
		wcursor->set_key(wcursor, i);
		testutil_check(wcursor->remove(wcursor));
	}
	testutil_check(wcursor->close(wcursor));

	testutil_check(session2->open_cursor(
	    session2, name, NULL, "next_random=true", &rcursor));
	for (i = 0; i < 3; i++)
		testutil_assert(rcursor->next(rcursor) == WT_NOTFOUND);
	printf("Successfully got WT_NOTFOUND\n");

	testutil_cleanup(opts);
	return (EXIT_SUCCESS);
}
Пример #15
0
int
main(int argc, char *argv[])
{
	TEST_OPTS *opts, _opts;
	WT_CURSOR *cursor;
	WT_SESSION *session;
	pthread_t thr[NR_THREADS];
	size_t t;
	uint64_t f[NR_FIELDS], r, ts;
	int i, ret;
	char table_format[256];

	opts = &_opts;
	memset(opts, 0, sizeof(*opts));
	testutil_check(testutil_parse_opts(argc, argv, opts));
	testutil_make_work_dir(opts->home);

	testutil_check(wiredtiger_open(opts->home, NULL,
	    "create,cache_size=1G,checkpoint=(wait=30),"
	    "eviction_trigger=80,eviction_target=64,eviction_dirty_target=65,"
	    "log=(enabled,file_max=10M),"
	    "transaction_sync=(enabled=true,method=none)", &opts->conn));
	testutil_check(opts->conn->open_session(
	    opts->conn, NULL, NULL, &session));

	sprintf(table_format, "key_format=r,value_format=");
	for (i = 0; i < NR_FIELDS; i++)
		strcat(table_format, "Q");

	/* recno -> timestamp + NR_FIELDS * Q */
	testutil_check(session->create(
	    session, opts->uri, table_format));
	/* timestamp -> recno */
	testutil_check(session->create(session,
	    "table:index", "key_format=Q,value_format=Q"));

	testutil_check(session->close(session, NULL));

	for (t = 0; t < NR_THREADS; ++t)
		testutil_check(pthread_create(
		    &thr[t], NULL, thread_func, (void *)opts));

	for (t = 0; t < NR_THREADS; ++t)
		(void)pthread_join(thr[t], NULL);

	testutil_check(opts->conn->open_session(
	    opts->conn, NULL, NULL, &session));

	/* recno -> timestamp + NR_FIELDS * Q */
	testutil_check(session->create(session, opts->uri, table_format));

	testutil_check(session->open_cursor(
	    session, opts->uri, NULL, NULL, &cursor));

	while ((ret = cursor->next(cursor)) == 0) {
		testutil_check(cursor->get_key(cursor, &r));
		testutil_check(cursor->get_value(cursor, &ts,
		    &f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7]));

		if (!opts->verbose)
			continue;

		printf("(%" PRIu64 ",%llu)\t\t%" PRIu64,
		    (r >> 40), r & ((1ULL << 40) - 1), ts);

		for (i = 0; i < NR_FIELDS; i++)
			printf("\t%" PRIu64, f[i]);
		printf("\n");
	}
	testutil_assert(ret == WT_NOTFOUND);

	testutil_cleanup(opts);
	return (EXIT_SUCCESS);
}
Пример #16
0
int
main(int argc, char *argv[])
{
	SHARED_OPTS *sharedopts, _sharedopts;
	TEST_OPTS *opts, _opts;
	THREAD_ARGS get_args[N_GET_THREAD], insert_args[N_INSERT_THREAD];
	WT_CURSOR *maincur;
	WT_SESSION *session;
	pthread_t get_tid[N_GET_THREAD], insert_tid[N_INSERT_THREAD];
	int i, nfail;
	const char *tablename;

	opts = &_opts;
	sharedopts = &_sharedopts;

	if (testutil_disable_long_tests())
		return (0);
	memset(opts, 0, sizeof(*opts));
	memset(sharedopts, 0, sizeof(*sharedopts));
	memset(insert_args, 0, sizeof(insert_args));
	memset(get_args, 0, sizeof(get_args));
	nfail = 0;

	sharedopts->bloom = BLOOM;
	testutil_check(testutil_parse_opts(argc, argv, opts));
	testutil_make_work_dir(opts->home);

	testutil_check(wiredtiger_open(opts->home, NULL,
	    "create,cache_size=1G", &opts->conn));

	testutil_check(
	    opts->conn->open_session(opts->conn, NULL, NULL, &session));

	/*
	 * Note: id is repeated as id2.  This makes it easier to
	 * identify the primary key in dumps of the index files.
	 */
	testutil_check(session->create(session, opts->uri,
	    "key_format=i,value_format=iiSii,"
	    "columns=(id,post,bal,extra,flag,id2)"));

	tablename = strchr(opts->uri, ':');
	testutil_assert(tablename != NULL);
	tablename++;
	snprintf(sharedopts->posturi, sizeof(sharedopts->posturi),
	    "index:%s:post", tablename);
	snprintf(sharedopts->baluri, sizeof(sharedopts->baluri),
	    "index:%s:bal", tablename);
	snprintf(sharedopts->flaguri, sizeof(sharedopts->flaguri),
	    "index:%s:flag", tablename);

	testutil_check(session->create(session, sharedopts->posturi,
	    "columns=(post)"));
	testutil_check(session->create(session, sharedopts->baluri,
	    "columns=(bal)"));
	testutil_check(session->create(session, sharedopts->flaguri,
	    "columns=(flag)"));

	/*
	 * Insert a single record with all items we need to
	 * call search() on, this makes our join logic easier.
	 */
	testutil_check(session->open_cursor(session, opts->uri, NULL, NULL,
	    &maincur));
	maincur->set_key(maincur, N_RECORDS);
	maincur->set_value(maincur, 54321, 0, "", 0, N_RECORDS);
	testutil_check(maincur->insert(maincur));
	testutil_check(maincur->close(maincur));
	testutil_check(session->close(session, NULL));

	for (i = 0; i < N_INSERT_THREAD; ++i) {
		insert_args[i].threadnum = i;
		insert_args[i].nthread = N_INSERT_THREAD;
		insert_args[i].testopts = opts;
		insert_args[i].sharedopts = sharedopts;
		testutil_check(pthread_create(&insert_tid[i], NULL,
		    thread_insert, (void *)&insert_args[i]));
	}

	for (i = 0; i < N_GET_THREAD; ++i) {
		get_args[i].threadnum = i;
		get_args[i].nthread = N_GET_THREAD;
		get_args[i].testopts = opts;
		get_args[i].sharedopts = sharedopts;
		testutil_check(pthread_create(&get_tid[i], NULL,
		    thread_get, (void *)&get_args[i]));
	}

	/*
	 * Wait for insert threads to finish.  When they
	 * are done, signal get threads to complete.
	 */
	for (i = 0; i < N_INSERT_THREAD; ++i)
		testutil_check(pthread_join(insert_tid[i], NULL));

	for (i = 0; i < N_GET_THREAD; ++i)
		get_args[i].done = 1;

	for (i = 0; i < N_GET_THREAD; ++i)
		testutil_check(pthread_join(get_tid[i], NULL));

	fprintf(stderr, "\n");
	for (i = 0; i < N_GET_THREAD; ++i) {
		fprintf(stderr, "  thread %d did %d joins (%d fails)\n", i,
		    get_args[i].njoins, get_args[i].nfail);
		nfail += get_args[i].nfail;
	}

	testutil_assert(nfail == 0);
	testutil_cleanup(opts);

	return (0);
}