summaryrefslogtreecommitdiff
path: root/src/third_party/wiredtiger/test/format
diff options
context:
space:
mode:
Diffstat (limited to 'src/third_party/wiredtiger/test/format')
-rw-r--r--src/third_party/wiredtiger/test/format/config.c15
-rw-r--r--src/third_party/wiredtiger/test/format/format.h4
-rw-r--r--src/third_party/wiredtiger/test/format/ops.c130
-rw-r--r--src/third_party/wiredtiger/test/format/t.c2
4 files changed, 110 insertions, 41 deletions
diff --git a/src/third_party/wiredtiger/test/format/config.c b/src/third_party/wiredtiger/test/format/config.c
index d46b0868887..0677b3b753c 100644
--- a/src/third_party/wiredtiger/test/format/config.c
+++ b/src/third_party/wiredtiger/test/format/config.c
@@ -159,9 +159,8 @@ config_setup(void)
/*
* Periodically, run single-threaded so we can compare the results to
* a Berkeley DB copy, as long as the thread-count isn't nailed down.
- * Don't do it on the first run, all our smoke tests would hit it.
*/
- if (!g.replay && g.run_cnt % 20 == 19 && !config_is_perm("threads"))
+ if (!config_is_perm("threads") && mmrand(NULL, 1, 20) == 1)
g.c_threads = 1;
config_checkpoint();
@@ -191,12 +190,8 @@ config_setup(void)
/*
* Turn off truncate for LSM runs (some configurations with truncate
* always results in a timeout).
- *
- * WiredTiger doesn't currently support truncate and prepare at the
- * same time, see WT-3922. For now, pick one on each run.
*/
- if (!config_is_perm("truncate"))
- if (DATASOURCE("lsm") || mmrand(NULL, 0, 1) == 1)
+ if (!config_is_perm("truncate") && DATASOURCE("lsm"))
config_single("truncate=off", 0);
/* Give Helium configuration a final review. */
@@ -629,10 +624,10 @@ config_pct(void)
/*
* If the delete percentage isn't nailed down, periodically set it to
- * 0 so salvage gets run. Don't do it on the first run, all our smoke
- * tests would hit it.
+ * 0 so salvage gets run and so we can perform stricter sanity checks
+ * on key ordering.
*/
- if (!config_is_perm("delete_pct") && !g.replay && g.run_cnt % 10 == 9) {
+ if (!config_is_perm("delete_pct") && mmrand(NULL, 1, 10) == 1) {
list[CONFIG_DELETE_ENTRY].order = 0;
*list[CONFIG_DELETE_ENTRY].vp = 0;
}
diff --git a/src/third_party/wiredtiger/test/format/format.h b/src/third_party/wiredtiger/test/format/format.h
index d277fb1a915..4eac7a5eb8e 100644
--- a/src/third_party/wiredtiger/test/format/format.h
+++ b/src/third_party/wiredtiger/test/format/format.h
@@ -122,6 +122,8 @@ typedef struct {
WT_RAND_STATE rnd; /* Global RNG state */
+ pthread_rwlock_t prepare_lock; /* Prepare running */
+
uint64_t timestamp; /* Counter for timestamps */
uint64_t truncate_cnt; /* Counter for truncation */
@@ -290,6 +292,8 @@ typedef struct {
uint64_t last; /* truncate range */
WT_ITEM *lastkey, _lastkey;
+ WT_ITEM *tbuf, _tbuf; /* temporary buffer */
+
#define TINFO_RUNNING 1 /* Running */
#define TINFO_COMPLETE 2 /* Finished */
#define TINFO_JOINED 3 /* Resolved */
diff --git a/src/third_party/wiredtiger/test/format/ops.c b/src/third_party/wiredtiger/test/format/ops.c
index 596d952dcc6..54aa6d2b766 100644
--- a/src/third_party/wiredtiger/test/format/ops.c
+++ b/src/third_party/wiredtiger/test/format/ops.c
@@ -512,6 +512,12 @@ begin_transaction(TINFO *tinfo, WT_SESSION *session, u_int *iso_configp)
config = "isolation=snapshot";
if (g.c_txn_timestamps) {
/*
+ * Avoid starting a new reader when a prepare is in
+ * progress.
+ */
+ (void)pthread_rwlock_rdlock(&g.prepare_lock);
+
+ /*
* Set the thread's read timestamp to the current value
* before allocating a new read timestamp. This
* guarantees the oldest timestamp won't move past the
@@ -531,6 +537,9 @@ begin_transaction(TINFO *tinfo, WT_SESSION *session, u_int *iso_configp)
testutil_check(session->begin_transaction(session, config));
+ if (v == ISOLATION_SNAPSHOT && g.c_txn_timestamps)
+ (void)pthread_rwlock_unlock(&g.prepare_lock);
+
/*
* It's OK for the oldest timestamp to move past a running query, clear
* the thread's read timestamp, it no longer needs to be pinned.
@@ -617,6 +626,7 @@ rollback_transaction(TINFO *tinfo, WT_SESSION *session)
static int
prepare_transaction(TINFO *tinfo, WT_SESSION *session)
{
+ WT_DECL_RET;
uint64_t ts;
char config_buf[64];
@@ -635,10 +645,23 @@ prepare_transaction(TINFO *tinfo, WT_SESSION *session)
*/
++tinfo->prepare;
+ /*
+ * Synchronize prepare call with begin transaction to prevent a new
+ * reader creeping in.
+ *
+ * Prepare will return error if prepare timestamp is less than any
+ * active read timestamp.
+ */
+ (void)pthread_rwlock_wrlock(&g.prepare_lock);
+
ts = set_commit_timestamp(tinfo);
testutil_check(__wt_snprintf(
config_buf, sizeof(config_buf), "prepare_timestamp=%" PRIx64, ts));
- return (session->prepare_transaction(session, config_buf));
+ ret = session->prepare_transaction(session, config_buf);
+
+ (void)pthread_rwlock_unlock(&g.prepare_lock);
+
+ return (ret);
}
/*
@@ -690,6 +713,7 @@ ops(void *arg)
val_gen_init(tinfo->value);
tinfo->lastkey = &tinfo->_lastkey;
key_gen_init(tinfo->lastkey);
+ tinfo->tbuf = &tinfo->_tbuf;
/* Set the first operation where we'll create sessions and cursors. */
cursor = NULL;
@@ -1072,9 +1096,8 @@ update_instead_of_chosen_op:
/*
* Prepare the transaction 10% of the time.
- * Currently doesn't work with truncation, see WT-3922.
*/
- if (g.c_truncate == 0 && mmrand(&tinfo->rnd, 1, 10) == 1) {
+ if (mmrand(&tinfo->rnd, 1, 10) == 1) {
ret = prepare_transaction(tinfo, session);
testutil_assert(ret == 0 || ret == WT_PREPARE_CONFLICT);
if (ret == WT_PREPARE_CONFLICT)
@@ -1113,6 +1136,7 @@ deadlock: ++tinfo->deadlock;
key_gen_teardown(tinfo->key);
val_gen_teardown(tinfo->value);
key_gen_teardown(tinfo->lastkey);
+ free(tinfo->tbuf->mem);
tinfo->state = TINFO_COMPLETE;
return (WT_THREAD_RET_VALUE);
@@ -1291,11 +1315,11 @@ nextprev(TINFO *tinfo, WT_CURSOR *cursor, bool next)
{
WT_DECL_RET;
WT_ITEM key, value;
- uint64_t keyno;
+ uint64_t keyno, keyno_prev;
uint8_t bitfield;
int cmp;
const char *which;
- bool incrementing;
+ bool incrementing, record_gaps;
keyno = 0;
which = next ? "WT_CURSOR.next" : "WT_CURSOR.prev";
@@ -1332,41 +1356,85 @@ nextprev(TINFO *tinfo, WT_CURSOR *cursor, bool next)
if (DATASOURCE("lsm"))
break;
+ /*
+ * Compare the returned key with the previously returned key,
+ * and assert the order is correct. If not deleting keys, and
+ * the rows aren't in the column-store insert name space, also
+ * assert we don't skip groups of records (that's a page-split
+ * bug symptom).
+ */
+ record_gaps = g.c_delete_pct != 0;
switch (g.type) {
case FIX:
case VAR:
- testutil_assertfmt(
- !next || tinfo->keyno < keyno,
- "%s returned %" PRIu64 " then %" PRIu64,
- which, tinfo->keyno, keyno);
- testutil_assertfmt(
- next || tinfo->keyno > keyno,
- "%s returned %" PRIu64 " then %" PRIu64,
- which, tinfo->keyno, keyno);
+ if (tinfo->keyno > g.c_rows || keyno > g.c_rows)
+ record_gaps = true;
+ if (!next) {
+ if (tinfo->keyno < keyno ||
+ (!record_gaps && keyno != tinfo->keyno - 1))
+ goto order_error_col;
+ } else
+ if (tinfo->keyno > keyno ||
+ (!record_gaps && keyno != tinfo->keyno + 1))
+ goto order_error_col;
+ if (0) {
+order_error_col:
+ testutil_die(0,
+ "%s returned %" PRIu64 " then %" PRIu64,
+ which, tinfo->keyno, keyno);
+ }
tinfo->keyno = keyno;
break;
case ROW:
- cmp = memcmp(tinfo->key->data, key.data,
- WT_MIN(tinfo->key->size, key.size));
incrementing =
(next && !g.c_reverse) || (!next && g.c_reverse);
- testutil_assertfmt(
- !incrementing ||
- cmp < 0 ||
- (cmp == 0 && tinfo->key->size < key.size),
- "%s returned {%.*s} then {%.*s}",
- which,
- (int)tinfo->key->size, tinfo->key->data,
- (int)key.size, key.data);
- testutil_assertfmt(
- incrementing ||
- cmp > 0 ||
- (cmp == 0 && tinfo->key->size > key.size),
- "%s returned {%.*s} then {%.*s}",
- which,
- (int)tinfo->key->size, tinfo->key->data,
- (int)key.size, key.data);
+ cmp = memcmp(tinfo->key->data, key.data,
+ WT_MIN(tinfo->key->size, key.size));
+ if (incrementing) {
+ if (cmp > 0 ||
+ (cmp == 0 && tinfo->key->size < key.size))
+ goto order_error_row;
+ } else
+ if (cmp < 0 ||
+ (cmp == 0 && tinfo->key->size > key.size))
+ goto order_error_row;
+ if (!record_gaps) {
+ /*
+ * Convert the keys to record numbers and then
+ * compare less-than-or-equal. (Not less-than,
+ * row-store inserts new rows in-between rows
+ * by append a new suffix to the row's key.)
+ */
+ testutil_check(__wt_buf_fmt(
+ (WT_SESSION_IMPL *)cursor->session,
+ tinfo->tbuf, "%.*s",
+ (int)tinfo->key->size,
+ (char *)tinfo->key->data));
+ keyno_prev =
+ strtoul(tinfo->tbuf->data, NULL, 10);
+ testutil_check(__wt_buf_fmt(
+ (WT_SESSION_IMPL *)cursor->session,
+ tinfo->tbuf, "%.*s",
+ (int)key.size, (char *)key.data));
+ keyno = strtoul(tinfo->tbuf->data, NULL, 10);
+ if (incrementing) {
+ if (keyno_prev != keyno &&
+ keyno_prev + 1 != keyno)
+ goto order_error_row;
+ } else
+ if (keyno_prev != keyno &&
+ keyno_prev - 1 != keyno)
+ goto order_error_row;
+ }
+ if (0) {
+order_error_row:
+ testutil_die(0,
+ "%s returned {%.*s} then {%.*s}",
+ which,
+ (int)tinfo->key->size, tinfo->key->data,
+ (int)key.size, key.data);
+ }
testutil_check(__wt_buf_set((WT_SESSION_IMPL *)
cursor->session, tinfo->key, key.data, key.size));
diff --git a/src/third_party/wiredtiger/test/format/t.c b/src/third_party/wiredtiger/test/format/t.c
index 6077a67a541..d7b9add1f14 100644
--- a/src/third_party/wiredtiger/test/format/t.c
+++ b/src/third_party/wiredtiger/test/format/t.c
@@ -170,6 +170,7 @@ main(int argc, char *argv[])
testutil_check(pthread_rwlock_init(&g.append_lock, NULL));
testutil_check(pthread_rwlock_init(&g.backup_lock, NULL));
testutil_check(pthread_rwlock_init(&g.death_lock, NULL));
+ testutil_check(pthread_rwlock_init(&g.prepare_lock, NULL));
printf("%s: process %" PRIdMAX "\n", progname, (intmax_t)getpid());
while (++g.run_cnt <= g.c_runs || g.c_runs == 0 ) {
@@ -267,6 +268,7 @@ main(int argc, char *argv[])
testutil_check(pthread_rwlock_destroy(&g.append_lock));
testutil_check(pthread_rwlock_destroy(&g.backup_lock));
testutil_check(pthread_rwlock_destroy(&g.death_lock));
+ testutil_check(pthread_rwlock_destroy(&g.prepare_lock));
config_clear();