Пример #1
0
/*
 * start_workers --
 *     Setup the configuration for the tables being populated, then start
 *     the worker thread(s) and wait for them to finish.
 */
int
start_workers(table_type type)
{
	WT_SESSION *session;
	struct timeval start, stop;
	double seconds;
	pthread_t *tids;
	int i, ret;
	void *thread_ret;

	ret = 0;

	/* Create statistics and thread structures. */
	if ((tids = calloc((size_t)(g.nworkers), sizeof(*tids))) == NULL)
		return (log_print_err("calloc", errno, 1));

	if ((ret = g.conn->open_session(g.conn, NULL, NULL, &session)) != 0) {
		(void)log_print_err("conn.open_session", ret, 1);
		goto err;
	}
	/* Setup the cookies */
	for (i = 0; i < g.ntables; ++i) {
		g.cookies[i].id = i;
		if (type == MIX)
			g.cookies[i].type =
			    (table_type)((i % MAX_TABLE_TYPE) + 1);
		else
			g.cookies[i].type = type;
		(void)snprintf(g.cookies[i].uri, 128,
		    "%s%04d", URI_BASE, g.cookies[i].id);

		/* Should probably be atomic to avoid races. */
		if ((ret = create_table(session, &g.cookies[i])) != 0)
			goto err;
	}

	(void)gettimeofday(&start, NULL);

	/* Create threads. */
	for (i = 0; i < g.nworkers; ++i) {
		if ((ret = pthread_create(
		    &tids[i], NULL, worker, &g.cookies[i])) != 0) {
			(void)log_print_err("pthread_create", ret, 1);
			goto err;
		}
	}

	/* Wait for the threads. */
	for (i = 0; i < g.nworkers; ++i)
		(void)pthread_join(tids[i], &thread_ret);

	(void)gettimeofday(&stop, NULL);
	seconds = (stop.tv_sec - start.tv_sec) +
	    (stop.tv_usec - start.tv_usec) * 1e-6;
	printf("Ran workers for: %f seconds\n", seconds);

err:	free(tids);

	return (ret);
}
Пример #2
0
/*
 * wt_connect --
 *	Configure the WiredTiger connection.
 */
static int
wt_connect(const char *config_open)
{
	static WT_EVENT_HANDLER event_handler = {
		handle_error,
		handle_message,
		NULL,
		NULL	/* Close handler. */
	};
	int ret;
	char config[128];

	testutil_make_work_dir(g.home);

	snprintf(config, sizeof(config),
	    "create,statistics=(fast),error_prefix=\"%s\",cache_size=1GB%s%s",
	    g.progname,
	    config_open == NULL ? "" : ",",
	    config_open == NULL ? "" : config_open);

	if ((ret = wiredtiger_open(
	    g.home, &event_handler, config, &g.conn)) != 0)
		return (log_print_err("wiredtiger_open", ret, 1));
	return (0);
}
Пример #3
0
/*
 * real_checkpointer --
 *     Do the work of creating checkpoints and then verifying them. Also
 *     responsible for finishing in a timely fashion.
 */
static int
real_checkpointer(void)
{
	WT_SESSION *session;
	char *checkpoint_config, _buf[128];
	int ret;

	if (g.running == 0)
		return (log_print_err(
		    "Checkpoint thread started stopped\n", EINVAL, 1));

	while (g.ntables > g.ntables_created)
		sched_yield();

	if ((ret = g.conn->open_session(g.conn, NULL, NULL, &session)) != 0)
		return (log_print_err("conn.open_session", ret, 1));

	if (strncmp(g.checkpoint_name,
	    "WiredTigerCheckpoint", strlen("WiredTigerCheckpoint")) == 0)
		checkpoint_config = NULL;
	else {
		checkpoint_config = _buf;
		snprintf(checkpoint_config, 128, "name=%s", g.checkpoint_name);
	}
	while (g.running) {
		/* Execute a checkpoint */
		if ((ret = session->checkpoint(
		    session, checkpoint_config)) != 0)
			return (log_print_err("session.checkpoint", ret, 1));
		printf("Finished a checkpoint\n");

		if (!g.running)
			goto done;

		/* Verify the content of the checkpoint. */
		if ((ret = verify_checkpoint(session)) != 0)
			return (log_print_err("verify_checkpoint", ret, 1));
	}

done:	if ((ret = session->close(session, NULL)) != 0)
		return (log_print_err("session.close", ret, 1));

	return (0);
}
Пример #4
0
/*
 * start_checkpoints --
 *     Responsible for creating the checkpoint thread.
 */
int
start_checkpoints(void)
{
	int ret;

	if ((ret = pthread_create(
	    &g.checkpoint_thread, NULL, checkpointer, NULL)) != 0)
		return (log_print_err("pthread_create", ret, 1));
	return (0);
}
Пример #5
0
/*
 * compare_cursors --
 *     Compare the key/value pairs from two cursors.
 */
static int
compare_cursors(
    WT_CURSOR *cursor1, const char *type1,
    WT_CURSOR *cursor2, const char *type2)
{
	uint64_t key1, key2;
	char *val1, *val2;
	char buf[128];

	memset(buf, 0, 128);

	if (cursor1->get_key(cursor1, &key1) != 0 ||
	    cursor2->get_key(cursor2, &key2) != 0)
		return (log_print_err("Error getting keys", EINVAL, 1));

	if (key1 != key2) {
		printf("Key mismatch %" PRIu64 " from a %s table "
		    "is not %" PRIu64 " from a %s table\n",
		    key1, type1, key2, type2);

		return (ERR_KEY_MISMATCH);
	}

	/* Now check the values. */
	if (cursor1->get_value(cursor1, &val1) != 0 ||
	    cursor2->get_value(cursor2, &val2) != 0)
		return (log_print_err("Error getting values", EINVAL, 1));

	if (g.logfp != NULL)
		fprintf(g.logfp, "k1: %" PRIu64 " k2: %" PRIu64
		    " val1: %s val2: %s \n",
		    key1, key2, val1, val2);
	if (strlen(val1) != strlen(val2) ||
	    strcmp(val1, val2) != 0) {
		printf("Value mismatch for key %" PRIu64
		    ", %s from a %s table is not %s from a %s table\n",
		    key1, val1, type1, val2, type2);
		return (ERR_DATA_MISMATCH);
	}

	return (0);
}
Пример #6
0
/*
 * compare_cursors --
 *     Compare the key/value pairs from two cursors.
 */
static int
compare_cursors(
    WT_CURSOR *cursor1, const char *type1,
    WT_CURSOR *cursor2, const char *type2)
{
	uint64_t key1, key2;
	char *val1, *val2, buf[128];
	int ret;

	ret = 0;
	memset(buf, 0, 128);

	if (cursor1->get_key(cursor1, &key1) != 0 ||
	    cursor2->get_key(cursor2, &key2) != 0)
		return (log_print_err("Error getting keys", EINVAL, 1));

	if (cursor1->get_value(cursor1, &val1) != 0 ||
	    cursor2->get_value(cursor2, &val2) != 0)
		return (log_print_err("Error getting values", EINVAL, 1));

	if (g.logfp != NULL)
		fprintf(g.logfp, "k1: %" PRIu64 " k2: %" PRIu64
		    " val1: %s val2: %s \n", key1, key2, val1, val2);

	if (key1 != key2)
		ret = ERR_KEY_MISMATCH;
	else if (strlen(val1) != strlen(val2) || strcmp(val1, val2) != 0)
		ret = ERR_DATA_MISMATCH;
	else
		return (0);

	printf("Key/value mismatch: %" PRIu64 "/%s from a %s table is not %"
	    PRIu64 "/%s from a %s table\n",
	    key1, val1, type1, key2, val2, type2);

	return (ret);
}
Пример #7
0
/*
 * wt_shutdown --
 *	Shut down the WiredTiger connection.
 */
static int
wt_shutdown(void)
{
	int ret;

	if (g.conn == NULL)
		return (0);

	printf("Closing connection\n");
	ret = g.conn->close(g.conn, NULL);
	g.conn = NULL;
	if (ret != 0)
		return (log_print_err("conn.close", ret, 1));
	return (0);
}
Пример #8
0
/*
 * create_table --
 *     Create a WiredTiger table of the configured type for this cookie.
 */
static int
create_table(WT_SESSION *session, COOKIE *cookie)
{
	int ret;
	char config[128];

	testutil_check(__wt_snprintf(config, sizeof(config),
	    "key_format=%s,value_format=S,%s",
	    cookie->type == COL ? "r" : "q",
	    cookie->type == LSM ? ",type=lsm" : ""));

	if ((ret = session->create(session, cookie->uri, config)) != 0)
		if (ret != EEXIST)
			return (log_print_err("session.create", ret, 1));
	++g.ntables_created;
	return (0);
}
Пример #9
0
/*
 * worker_op --
 *	Write operation.
 */
static inline int
worker_op(WT_CURSOR *cursor, uint64_t keyno, u_int new_val)
{
	int ret;
	char valuebuf[64];

	cursor->set_key(cursor, keyno);
	testutil_check(__wt_snprintf(
	    valuebuf, sizeof(valuebuf), "%037u", new_val));
	cursor->set_value(cursor, valuebuf);
	if ((ret = cursor->insert(cursor)) != 0) {
		if (ret == WT_ROLLBACK)
			return (WT_ROLLBACK);
		return (log_print_err("cursor.insert", ret, 1));
	}
	return (0);
}
Пример #10
0
/*
 * create_table --
 *     Create a WiredTiger table of the configured type for this cookie.
 */
static int
create_table(WT_SESSION *session, COOKIE *cookie)
{
	int ret;
	char *p, *end, config[128];

	p = config;
	end = config + sizeof(config);
	p += snprintf(p, (size_t)(end - p),
	    "key_format=%s,value_format=S",
	    cookie->type == COL ? "r" : "q");
	if (cookie->type == LSM)
		(void)snprintf(p, (size_t)(end - p), ",type=lsm");

	if ((ret = session->create(session, cookie->uri, config)) != 0)
		if (ret != EEXIST)
			return (log_print_err("session.create", ret, 1));
	++g.ntables_created;
	return (0);
}
Пример #11
0
/*
 * diagnose_key_error --
 *     Dig a bit deeper on failure. Continue after some failures here to
 *     extract as much information as we can.
 */
static int
diagnose_key_error(
    WT_CURSOR *cursor1, int index1,
    WT_CURSOR *cursor2, int index2)
{
	WT_CURSOR *c;
	WT_SESSION *session;
	uint64_t key1, key1_orig, key2, key2_orig;
	char next_uri[128], ckpt[128];
	int ret;

	/* Hack to avoid passing session as parameter. */
	session = cursor1->session;
	key1_orig = key2_orig = 0;

	snprintf(ckpt, 128, "checkpoint=%s", g.checkpoint_name);

	/* Save the failed keys. */
	if (cursor1->get_key(cursor1, &key1_orig) != 0 ||
	    cursor2->get_key(cursor2, &key2_orig) != 0) {
		(void)log_print_err("Error retrieving key.", EINVAL, 0);
		goto live_check;
	}

	if (key1_orig == key2_orig)
		goto live_check;

	/* See if previous values are still valid. */
	if (cursor1->prev(cursor1) != 0 || cursor2->prev(cursor2) != 0)
		return (1);
	if (cursor1->get_key(cursor1, &key1) != 0 ||
	    cursor2->get_key(cursor2, &key2) != 0)
		(void)log_print_err("Error decoding key", EINVAL, 1);
	else if (key1 != key2)
		(void)log_print_err("Now previous keys don't match", EINVAL, 0);

	if (cursor1->next(cursor1) != 0 || cursor2->next(cursor2) != 0)
		return (1);
	if (cursor1->get_key(cursor1, &key1) != 0 ||
	    cursor2->get_key(cursor2, &key2) != 0)
		(void)log_print_err("Error decoding key", EINVAL, 1);
	else if (key1 == key2)
		(void)log_print_err("After prev/next keys match", EINVAL, 0);

	if (cursor1->next(cursor1) != 0 || cursor2->next(cursor2) != 0)
		return (1);
	if (cursor1->get_key(cursor1, &key1) != 0 ||
	    cursor2->get_key(cursor2, &key2) != 0)
		(void)log_print_err("Error decoding key", EINVAL, 1);
	else if (key1 == key2)
		(void)log_print_err(
		    "After prev/next/next keys match", EINVAL, 0);

	/*
	 * Now try opening new cursors on the checkpoints and see if we
	 * get the same missing key via searching.
	 */
	snprintf(next_uri, 128, "table:__wt%04d", index1);
	if (session->open_cursor(session, next_uri, NULL, ckpt, &c) != 0)
		return (1);
	c->set_key(c, key1_orig);
	if ((ret = c->search(c)) != 0)
		(void)log_print_err("1st cursor didn't find 1st key\n", ret, 0);
	c->set_key(c, key2_orig);
	if ((ret = c->search(c)) != 0)
		(void)log_print_err("1st cursor didn't find 2nd key\n", ret, 0);
	if (c->close(c) != 0)
		return (1);

	snprintf(next_uri, 128, "table:__wt%04d", index2);
	if (session->open_cursor(session, next_uri, NULL, ckpt, &c) != 0)
		return (1);
	c->set_key(c, key1_orig);
	if ((ret = c->search(c)) != 0)
		(void)log_print_err("2nd cursor didn't find 1st key\n", ret, 0);
	c->set_key(c, key2_orig);
	if ((ret = c->search(c)) != 0)
		(void)log_print_err("2nd cursor didn't find 2nd key\n", ret, 0);
	if (c->close(c) != 0)
		return (1);

live_check:
	/*
	 * Now try opening cursors on the live checkpoint to see if we get the
	 * same missing key via searching.
	 */
	snprintf(next_uri, 128, "table:__wt%04d", index1);
	if (session->open_cursor(session, next_uri, NULL, NULL, &c) != 0)
		return (1);
	c->set_key(c, key1_orig);
	if ((ret = c->search(c)) != 0)
		(void)log_print_err("1st cursor didn't find 1st key\n", ret, 0);
	if (c->close(c) != 0)
		return (1);

	snprintf(next_uri, 128, "table:__wt%04d", index2);
	if (session->open_cursor(session, next_uri, NULL, NULL, &c) != 0)
		return (1);
	c->set_key(c, key2_orig);
	if ((ret = c->search(c)) != 0)
		(void)log_print_err("2nd cursor didn't find 2nd key\n", ret, 0);
	if (c->close(c) != 0)
		return (1);

	return (0);
}
Пример #12
0
/*
 * verify_checkpoint --
 *     Open a cursor on each table at the last checkpoint and walk through
 *     the tables in parallel. The key/values should match across all
 *     tables.
 */
static int
verify_checkpoint(WT_SESSION *session)
{
	WT_CURSOR **cursors;
	const char *type0, *typei;
	char next_uri[128], ckpt[128];
	int i, ret, t_ret;
	uint64_t key_count;

	ret = t_ret = 0;
	key_count = 0;
	snprintf(ckpt, 128, "checkpoint=%s", g.checkpoint_name);
	cursors = calloc((size_t)g.ntables, sizeof(*cursors));
	if (cursors == NULL)
		return (log_print_err("verify_checkpoint", ENOMEM, 1));

	for (i = 0; i < g.ntables; i++) {
		/*
		 * TODO: LSM doesn't currently support reading from
		 * checkpoints.
		 */
		if (g.cookies[i].type == LSM)
			continue;
		snprintf(next_uri, 128, "table:__wt%04d", i);
		if ((ret = session->open_cursor(
		    session, next_uri, NULL, ckpt, &cursors[i])) != 0) {
			(void)log_print_err(
			    "verify_checkpoint:session.open_cursor", ret, 1);
			goto err;
		}
	}

	while (ret == 0) {
		ret = cursors[0]->next(cursors[0]);
		if (ret == 0)
			++key_count;
		else if (ret != WT_NOTFOUND) {
			(void)log_print_err("cursor->next", ret, 1);
			goto err;
		}
		/*
		 * Check to see that all remaining cursors have the
		 * same key/value pair.
		 */
		for (i = 1; i < g.ntables; i++) {
			/*
			 * TODO: LSM doesn't currently support reading from
			 * checkpoints.
			 */
			if (g.cookies[i].type == LSM)
				continue;
			t_ret = cursors[i]->next(cursors[i]);
			if (t_ret != 0 && t_ret != WT_NOTFOUND) {
				(void)log_print_err("cursor->next", ret, 1);
				goto err;
			}

			if (ret == WT_NOTFOUND && t_ret == WT_NOTFOUND)
				continue;
			else if (ret == WT_NOTFOUND || t_ret == WT_NOTFOUND) {
				(void)log_print_err(
				    "verify_checkpoint tables with different"
				    " amount of data", EFAULT, 1);
				goto err;
			}

			type0 = type_to_string(g.cookies[0].type);
			typei = type_to_string(g.cookies[i].type);
			if ((ret = compare_cursors(
			    cursors[0], type0, cursors[i], typei)) != 0) {
				(void)diagnose_key_error(
				    cursors[0], 0, cursors[i], i);
				(void)log_print_err(
				    "verify_checkpoint - mismatching data",
				    EFAULT, 1);
				goto err;
			}
		}
	}
	printf("Finished verifying a checkpoint with %d tables and %" PRIu64
	    " keys\n", g.ntables, key_count);

err:	for (i = 0; i < g.ntables; i++) {
		if (cursors[i] != NULL &&
		    (ret = cursors[i]->close(cursors[i])) != 0)
			(void)log_print_err(
			    "verify_checkpoint:cursor close", ret, 1);
	}
	free(cursors);
	return (0);
}
Пример #13
0
int
main(int argc, char *argv[])
{
	table_type ttype;
	int ch, cnt, ret, runs;
	char *working_dir;
	const char *config_open;

	if ((g.progname = strrchr(argv[0], DIR_DELIM)) == NULL)
		g.progname = argv[0];
	else
		++g.progname;

	config_open = NULL;
	ret = 0;
	working_dir = NULL;
	ttype = MIX;
	g.checkpoint_name = "WiredTigerCheckpoint";
	if ((g.home = malloc(512)) == NULL)
		testutil_die(ENOMEM, "Unable to allocate memory");
	g.nkeys = 10000;
	g.nops = 100000;
	g.ntables = 3;
	g.nworkers = 1;
	runs = 1;

	while ((ch = __wt_getopt(
	    g.progname, argc, argv, "c:C:h:k:l:n:r:t:T:W:")) != EOF)
		switch (ch) {
		case 'c':
			g.checkpoint_name = __wt_optarg;
			break;
		case 'C':			/* wiredtiger_open config */
			config_open = __wt_optarg;
			break;
		case 'h':			/* wiredtiger_open config */
			working_dir = __wt_optarg;
			break;
		case 'k':			/* rows */
			g.nkeys = (u_int)atoi(__wt_optarg);
			break;
		case 'l':			/* log */
			if ((g.logfp = fopen(__wt_optarg, "w")) == NULL) {
				fprintf(stderr,
				    "%s: %s\n", __wt_optarg, strerror(errno));
				return (EXIT_FAILURE);
			}
			break;
		case 'n':			/* operations */
			g.nops = (u_int)atoi(__wt_optarg);
			break;
		case 'r':			/* runs */
			runs = atoi(__wt_optarg);
			break;
		case 't':
			switch (__wt_optarg[0]) {
			case 'c':
				ttype = COL;
				break;
			case 'l':
				ttype = LSM;
				break;
			case 'm':
				ttype = MIX;
				break;
			case 'r':
				ttype = ROW;
				break;
			default:
				return (usage());
			}
			break;
		case 'T':
			g.ntables = atoi(__wt_optarg);
			break;
		case 'W':
			g.nworkers = atoi(__wt_optarg);
			break;
		default:
			return (usage());
		}

	argc -= __wt_optind;
	if (argc != 0)
		return (usage());

	/* Clean up on signal. */
	(void)signal(SIGINT, onint);

	testutil_work_dir_from_path(g.home, 512, working_dir);

	printf("%s: process %" PRIu64 "\n", g.progname, (uint64_t)getpid());
	for (cnt = 1; (runs == 0 || cnt <= runs) && g.status == 0; ++cnt) {
		printf("    %d: %u workers, %u tables\n",
		    cnt, g.nworkers, g.ntables);

		(void)cleanup();		/* Clean up previous runs */

		/* Setup a fresh set of cookies in the global array. */
		if ((g.cookies = calloc(
		    (size_t)(g.ntables), sizeof(COOKIE))) == NULL) {
			(void)log_print_err("No memory", ENOMEM, 1);
			break;
		}

		g.running = 1;

		if ((ret = wt_connect(config_open)) != 0) {
			(void)log_print_err("Connection failed", ret, 1);
			break;
		}

		if ((ret = start_checkpoints()) != 0) {
			(void)log_print_err("Start checkpoints failed", ret, 1);
			break;
		}
		if ((ret = start_workers(ttype)) != 0) {
			(void)log_print_err("Start workers failed", ret, 1);
			break;
		}

		g.running = 0;
		if ((ret = end_checkpoints()) != 0) {
			(void)log_print_err("Start workers failed", ret, 1);
			break;
		}

		free(g.cookies);
		g.cookies = NULL;
		if ((ret = wt_shutdown()) != 0) {
			(void)log_print_err("Start workers failed", ret, 1);
			break;
		}
	}
	if (g.logfp != NULL)
		(void)fclose(g.logfp);

	/* Ensure that cleanup is done on error. */
	(void)wt_shutdown();
	free(g.cookies);
	return (g.status);
}
Пример #14
0
/*
 * real_worker --
 *     A single worker thread that transactionally updates all tables with
 *     consistent values.
 */
static int
real_worker(void)
{
	WT_CURSOR **cursors;
	WT_RAND_STATE rnd;
	WT_SESSION *session;
	u_int i, keyno;
	int j, ret, t_ret;

	ret = t_ret = 0;

	__wt_random_init(&rnd);

	if ((cursors = calloc(
	    (size_t)(g.ntables), sizeof(WT_CURSOR *))) == NULL)
		return (log_print_err("malloc", ENOMEM, 1));

	if ((ret = g.conn->open_session(
	    g.conn, NULL, "isolation=snapshot", &session)) != 0) {
		(void)log_print_err("conn.open_session", ret, 1);
		goto err;
	}

	for (j = 0; j < g.ntables; j++)
		if ((ret = session->open_cursor(session,
		    g.cookies[j].uri, NULL, NULL, &cursors[j])) != 0) {
			(void)log_print_err("session.open_cursor", ret, 1);
			goto err;
		}

	for (i = 0; i < g.nops && g.running; ++i, __wt_yield()) {
		if ((ret = session->begin_transaction(session, NULL)) != 0) {
			(void)log_print_err(
			    "real_worker:begin_transaction", ret, 1);
			goto err;
		}
		keyno = __wt_random(&rnd) % g.nkeys + 1;
		for (j = 0; j < g.ntables; j++) {
			if ((ret = worker_op(cursors[j], keyno, i)) != 0)
				break;
		}
		if (ret == 0) {
			if ((ret = session->commit_transaction(
			    session, NULL)) != 0) {
				(void)log_print_err(
				    "real_worker:commit_transaction", ret, 1);
				goto err;
			}
		} else if (ret == WT_ROLLBACK) {
			if ((ret = session->rollback_transaction(
			    session, NULL)) != 0) {
				(void)log_print_err(
				    "real_worker:rollback_transaction", ret, 1);
				goto err;
			    }
		} else {
			(void)log_print_err("worker op failed", ret, 1);
			goto err;
		}
	}

err:	if ((t_ret = session->close(session, NULL)) != 0 && ret == 0) {
		ret = t_ret;
		(void)log_print_err("session.close", ret, 1);
	}
	free(cursors);

	return (ret);
}