Beispiel #1
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);
}
Beispiel #2
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);
}
Beispiel #3
0
int
main(int argc, char *argv[])
{
	TEST_OPTS *opts, _opts;
	WT_CURSOR *maincur;
	WT_CURSOR *postcur, *balancecur, *flagcur, *joincur;
	WT_SESSION *session;
	int balance, count, flag, key, key2, post, ret;
	char cfg[128];
	const char *tablename;
	char posturi[256];
	char balanceuri[256];
	char flaguri[256];
	char joinuri[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=250M", &opts->conn));
	testutil_check(
	    opts->conn->open_session(opts->conn, NULL, NULL, &session));
	/*
	 * 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++;
	snprintf(posturi, sizeof(posturi), "index:%s:post", tablename);
	snprintf(balanceuri, sizeof(balanceuri), "index:%s:balance", tablename);
	snprintf(flaguri, sizeof(flaguri), "index:%s:flag", tablename);
	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)"));

	/*
	 * 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);
	maincur->insert(maincur);
	maincur->close(maincur);
	testutil_check(session->close(session, NULL));

	populate(opts);

	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));
	sprintf(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));
	sprintf(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(count == 0);

	testutil_cleanup(opts);
	/* NOTREACHED */

	return (0);
}
Beispiel #4
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;
	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);
}
Beispiel #5
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);
}
Beispiel #6
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);
}
Beispiel #7
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);
}