Beispiel #1
0
/*
 * __debug_config --
 *	Configure debugging output.
 */
static int
__debug_config(WT_SESSION_IMPL *session, WT_DBG *ds, const char *ofile)
{
	memset(ds, 0, sizeof(WT_DBG));

	ds->session = session;

	WT_RET(__wt_scr_alloc(session, 512, &ds->tmp));

	/*
	 * If we weren't given a file, we use the default event handler, and
	 * we'll have to buffer messages.
	 */
	if (ofile == NULL) {
		WT_RET(__wt_scr_alloc(session, 512, &ds->msg));
		ds->f = __dmsg_event;
	} else {
		if ((ds->fp = fopen(ofile, "w")) == NULL)
			return (EIO);
		__wt_stream_set_line_buffer(ds->fp);
		ds->f = __dmsg_file;
	}

	return (0);
}
Beispiel #2
0
/* Setup the logging output mechanism. */
int
setup_log_file(WTPERF *wtperf)
{
	CONFIG_OPTS *opts;
	size_t len;
	int ret;
	char *fname;

	opts = wtperf->opts;
	ret = 0;

	if (opts->verbose < 1)
		return (0);

	len = strlen(wtperf->monitor_dir) +
	    strlen(opts->table_name) + strlen(".stat") + 2;
	fname = dmalloc(len);
	testutil_check(__wt_snprintf(fname, len,
	    "%s/%s.stat", wtperf->monitor_dir, opts->table_name));
	if ((wtperf->logf = fopen(fname, "w")) == NULL) {
		ret = errno;
		fprintf(stderr, "%s: %s\n", fname, strerror(ret));
	}
	free(fname);
	if (wtperf->logf == NULL)
		return (ret);

	/* Use line buffering for the log file. */
	__wt_stream_set_line_buffer(wtperf->logf);
	return (0);
}
Beispiel #3
0
/*
 * thread_run --
 *	Runner function for the worker threads.
 */
static WT_THREAD_RET
thread_run(void *arg)
{
	FILE *fp;
	WT_CURSOR *cur_coll, *cur_local, *cur_oplog, *cur_stable;
	WT_ITEM data;
	WT_RAND_STATE rnd;
	WT_SESSION *session;
	WT_THREAD_DATA *td;
	uint64_t i, stable_ts;
	int ret;
	char cbuf[MAX_VAL], lbuf[MAX_VAL], obuf[MAX_VAL];
	char kname[64], tscfg[64];

	__wt_random_init(&rnd);
	memset(cbuf, 0, sizeof(cbuf));
	memset(lbuf, 0, sizeof(lbuf));
	memset(obuf, 0, sizeof(obuf));
	memset(kname, 0, sizeof(kname));

	td = (WT_THREAD_DATA *)arg;
	/*
	 * Set up the separate file for checking.
	 */
	testutil_check(__wt_snprintf(cbuf, sizeof(cbuf), RECORDS_FILE, td->id));
	(void)unlink(cbuf);
	testutil_checksys((fp = fopen(cbuf, "w")) == NULL);
	/*
	 * Set to line buffering.  But that is advisory only.  We've seen
	 * cases where the result files end up with partial lines.
	 */
	__wt_stream_set_line_buffer(fp);
	if ((ret = td->conn->open_session(td->conn, NULL, NULL, &session)) != 0)
		testutil_die(ret, "WT_CONNECTION:open_session");
	/*
	 * Open a cursor to each table.
	 */
	if ((ret = session->open_cursor(session,
	    uri_collection, NULL, NULL, &cur_coll)) != 0)
		testutil_die(ret, "WT_SESSION.open_cursor: %s", uri_collection);
	if ((ret = session->open_cursor(session,
	    uri_local, NULL, NULL, &cur_local)) != 0)
		testutil_die(ret, "WT_SESSION.open_cursor: %s", uri_local);
	if ((ret = session->open_cursor(session,
	    uri_oplog, NULL, NULL, &cur_oplog)) != 0)
		testutil_die(ret, "WT_SESSION.open_cursor: %s", uri_oplog);

	if ((ret = session->open_cursor(
	    session, stable_store, NULL, NULL, &cur_stable)) != 0)
		testutil_die(ret, "WT_SESSION.open_cursor: %s", stable_store);

	/*
	 * Write our portion of the key space until we're killed.
	 */
	printf("Thread %" PRIu32 " starts at %" PRIu64 "\n", td->id, td->start);
	for (i = td->start; ; ++i) {
		if (use_ts)
			stable_ts = global_ts++;
		else
			stable_ts = 0;
		testutil_check(__wt_snprintf(
		    kname, sizeof(kname), "%" PRIu64, i));

		testutil_check(session->begin_transaction(session, NULL));
		cur_coll->set_key(cur_coll, kname);
		cur_local->set_key(cur_local, kname);
		cur_oplog->set_key(cur_oplog, kname);
		/*
		 * Put an informative string into the value so that it
		 * can be viewed well in a binary dump.
		 */
		testutil_check(__wt_snprintf(cbuf, sizeof(cbuf),
		    "COLL: thread:%" PRIu64 " ts:%" PRIu64 " key: %" PRIu64,
		    td->id, stable_ts, i));
		testutil_check(__wt_snprintf(lbuf, sizeof(lbuf),
		    "LOCAL: thread:%" PRIu64 " ts:%" PRIu64 " key: %" PRIu64,
		    td->id, stable_ts, i));
		testutil_check(__wt_snprintf(obuf, sizeof(obuf),
		    "OPLOG: thread:%" PRIu64 " ts:%" PRIu64 " key: %" PRIu64,
		    td->id, stable_ts, i));
		data.size = __wt_random(&rnd) % MAX_VAL;
		data.data = cbuf;
		cur_coll->set_value(cur_coll, &data);
		if ((ret = cur_coll->insert(cur_coll)) != 0)
			testutil_die(ret, "WT_CURSOR.insert");
		data.size = __wt_random(&rnd) % MAX_VAL;
		data.data = obuf;
		cur_oplog->set_value(cur_oplog, &data);
		if ((ret = cur_oplog->insert(cur_oplog)) != 0)
			testutil_die(ret, "WT_CURSOR.insert");
		if (use_ts) {
			testutil_check(__wt_snprintf(tscfg, sizeof(tscfg),
			    "commit_timestamp=%" PRIx64, stable_ts));
			testutil_check(
			    session->commit_transaction(session, tscfg));
		} else
			testutil_check(
			    session->commit_transaction(session, NULL));
		/*
		 * Insert into the local table outside the timestamp txn.
		 */
		data.size = __wt_random(&rnd) % MAX_VAL;
		data.data = lbuf;
		cur_local->set_value(cur_local, &data);
		if ((ret = cur_local->insert(cur_local)) != 0)
			testutil_die(ret, "WT_CURSOR.insert");

		/*
		 * Every N records we will record our stable timestamp into the
		 * stable table.  That will define our threshold where we
		 * expect to find records after recovery.
		 */
		if (i % STABLE_PERIOD == 0) {
			if (use_ts) {
				/*
				 * Set both the oldest and stable timestamp
				 * so that we don't need to maintain read
				 * availability at older timestamps.
				 */
				testutil_check(__wt_snprintf(
				    tscfg, sizeof(tscfg),
				    "oldest_timestamp=%" PRIx64
				    ",stable_timestamp=%" PRIx64,
				    stable_ts, stable_ts));
				testutil_check(
				    td->conn->set_timestamp(td->conn, tscfg));
			}
			cur_stable->set_key(cur_stable, td->id);
			cur_stable->set_value(cur_stable, stable_ts);
			testutil_check(cur_stable->insert(cur_stable));
		}
		/*
		 * Save the timestamp and key separately for checking later.
		 */
		if (fprintf(fp,
		    "%" PRIu64 " %" PRIu64 "\n", stable_ts, i) < 0)
			testutil_die(EIO, "fprintf");
	}
	/* NOTREACHED */
}
Beispiel #4
0
/*
 * thread_run --
 *	Runner function for the worker threads.
 */
static WT_THREAD_RET
thread_run(void *arg)
{
	FILE *fp;
	WT_CURSOR *cur_coll, *cur_local, *cur_oplog;
	WT_ITEM data;
	WT_RAND_STATE rnd;
	WT_SESSION *prepared_session, *session;
	THREAD_DATA *td;
	uint64_t i, active_ts;
	char cbuf[MAX_VAL], lbuf[MAX_VAL], obuf[MAX_VAL];
	char kname[64], tscfg[64], uri[128];
	bool use_prep;

	__wt_random_init(&rnd);
	memset(cbuf, 0, sizeof(cbuf));
	memset(lbuf, 0, sizeof(lbuf));
	memset(obuf, 0, sizeof(obuf));
	memset(kname, 0, sizeof(kname));

	prepared_session = NULL;
	td = (THREAD_DATA *)arg;
	/*
	 * Set up the separate file for checking.
	 */
	testutil_check(__wt_snprintf(
	    cbuf, sizeof(cbuf), RECORDS_FILE, td->info));
	(void)unlink(cbuf);
	testutil_checksys((fp = fopen(cbuf, "w")) == NULL);
	/*
	 * Set to line buffering.  But that is advisory only.  We've seen
	 * cases where the result files end up with partial lines.
	 */
	__wt_stream_set_line_buffer(fp);

	/*
	 * Have 10% of the threads use prepared transactions if timestamps
	 * are in use. Thread numbers start at 0 so we're always guaranteed
	 * that at least one thread is using prepared transactions.
	 */
	use_prep = (use_ts && td->info % PREPARE_PCT == 0) ? true : false;

	/*
	 * For the prepared case we have two sessions so that the oplog session
	 * can have its own transaction in parallel with the collection session
	 * We need this because prepared transactions cannot have any operations
	 * that modify a table that is logged. But we also want to test mixed
	 * logged and not-logged transactions.
	 */
	testutil_check(td->conn->open_session(td->conn, NULL, NULL, &session));
	if (use_prep)
		testutil_check(td->conn->open_session(
		    td->conn, NULL, NULL, &prepared_session));
	/*
	 * Open a cursor to each table.
	 */
	testutil_check(__wt_snprintf(
	    uri, sizeof(uri), "%s:%s", table_pfx, uri_collection));
	if (use_prep)
		testutil_check(prepared_session->open_cursor(prepared_session,
		    uri, NULL, NULL, &cur_coll));
	else
		testutil_check(session->open_cursor(session,
		    uri, NULL, NULL, &cur_coll));
	testutil_check(__wt_snprintf(
	    uri, sizeof(uri), "%s:%s", table_pfx, uri_local));
	if (use_prep)
		testutil_check(prepared_session->open_cursor(prepared_session,
		    uri, NULL, NULL, &cur_local));
	else
		testutil_check(session->open_cursor(session,
		    uri, NULL, NULL, &cur_local));
	testutil_check(__wt_snprintf(
	    uri, sizeof(uri), "%s:%s", table_pfx, uri_oplog));
	testutil_check(session->open_cursor(session,
	    uri, NULL, NULL, &cur_oplog));

	/*
	 * Write our portion of the key space until we're killed.
	 */
	printf("Thread %" PRIu32 " starts at %" PRIu64 "\n",
	    td->info, td->start);
	active_ts = 0;
	for (i = td->start;; ++i) {
		testutil_check(__wt_snprintf(
		    kname, sizeof(kname), "%" PRIu64, i));

		testutil_check(session->begin_transaction(session, NULL));
		if (use_prep)
			testutil_check(prepared_session->begin_transaction(
			    prepared_session, NULL));

		if (use_ts) {
			testutil_check(pthread_rwlock_rdlock(&ts_lock));
			active_ts = __wt_atomic_addv64(&global_ts, 1);
			testutil_check(__wt_snprintf(tscfg,
			    sizeof(tscfg), "commit_timestamp=%" PRIx64,
			    active_ts));
			/*
			 * Set the transaction's timestamp now before performing
			 * the operation. If we are using prepared transactions,
			 * set the timestamp for the session used for oplog. The
			 * collection session in that case would continue to use
			 * this timestamp.
			 */
			testutil_check(session->timestamp_transaction(
			    session, tscfg));
			testutil_check(pthread_rwlock_unlock(&ts_lock));
		}

		cur_coll->set_key(cur_coll, kname);
		cur_local->set_key(cur_local, kname);
		cur_oplog->set_key(cur_oplog, kname);
		/*
		 * Put an informative string into the value so that it
		 * can be viewed well in a binary dump.
		 */
		testutil_check(__wt_snprintf(cbuf, sizeof(cbuf),
		    "COLL: thread:%" PRIu64 " ts:%" PRIu64 " key: %" PRIu64,
		    td->info, active_ts, i));
		testutil_check(__wt_snprintf(lbuf, sizeof(lbuf),
		    "LOCAL: thread:%" PRIu64 " ts:%" PRIu64 " key: %" PRIu64,
		    td->info, active_ts, i));
		testutil_check(__wt_snprintf(obuf, sizeof(obuf),
		    "OPLOG: thread:%" PRIu64 " ts:%" PRIu64 " key: %" PRIu64,
		    td->info, active_ts, i));
		data.size = __wt_random(&rnd) % MAX_VAL;
		data.data = cbuf;
		cur_coll->set_value(cur_coll, &data);
		testutil_check(cur_coll->insert(cur_coll));
		data.size = __wt_random(&rnd) % MAX_VAL;
		data.data = obuf;
		cur_oplog->set_value(cur_oplog, &data);
		testutil_check(cur_oplog->insert(cur_oplog));
		if (use_prep) {
			/*
			 * Run with prepare every once in a while. And also
			 * yield after prepare sometimes too. This is only done
			 * on the collection session.
			 */
			if (i % PREPARE_FREQ == 0) {
				testutil_check(__wt_snprintf(tscfg,
				    sizeof(tscfg), "prepare_timestamp=%"
				    PRIx64, active_ts));
				testutil_check(
				    prepared_session->prepare_transaction(
				    prepared_session, tscfg));
				if (i % PREPARE_YIELD == 0)
					__wt_yield();
				testutil_check(
				    __wt_snprintf(tscfg, sizeof(tscfg),
				    "commit_timestamp=%" PRIx64
				    ",durable_timestamp=%" PRIx64,
				    active_ts, active_ts));
			} else
				testutil_check(
				    __wt_snprintf(tscfg, sizeof(tscfg),
				    "commit_timestamp=%" PRIx64, active_ts));

			testutil_check(
			    prepared_session->commit_transaction(
			    prepared_session, tscfg));
		}
		testutil_check(
		    session->commit_transaction(session, NULL));
		/*
		 * Insert into the local table outside the timestamp txn.
		 */
		data.size = __wt_random(&rnd) % MAX_VAL;
		data.data = lbuf;
		cur_local->set_value(cur_local, &data);
		testutil_check(cur_local->insert(cur_local));

		/*
		 * Save the timestamp and key separately for checking later.
		 */
		if (fprintf(fp,
		    "%" PRIu64 " %" PRIu64 "\n", active_ts, i) < 0)
			testutil_die(EIO, "fprintf");
	}
	/* NOTREACHED */
}