/* * __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); }
/* 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); }
/* * 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 */ }
/* * 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 */ }