diff options
Diffstat (limited to 'src/third_party/wiredtiger/test/format')
-rw-r--r-- | src/third_party/wiredtiger/test/format/config.c | 15 | ||||
-rw-r--r-- | src/third_party/wiredtiger/test/format/format.h | 4 | ||||
-rw-r--r-- | src/third_party/wiredtiger/test/format/ops.c | 130 | ||||
-rw-r--r-- | src/third_party/wiredtiger/test/format/t.c | 2 |
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(); |