summaryrefslogtreecommitdiff
path: root/src/third_party/wiredtiger
diff options
context:
space:
mode:
authorEtienne Petrel <etienne.petrel@mongodb.com>2022-04-08 01:32:31 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-04-08 02:01:05 +0000
commit4508cd461c9ac97860d0a75ec3c1d1e929636e07 (patch)
tree8dba87511236295612adc3024233a2a010dc99e1 /src/third_party/wiredtiger
parente6cce2875f3efa0c9b1443cf66efab95d5325a8f (diff)
downloadmongo-4508cd461c9ac97860d0a75ec3c1d1e929636e07.tar.gz
Import wiredtiger: 2aa2673d45c3ef1666107a5e381202f92502201e from branch mongodb-master
ref: 03dfd53f7a..2aa2673d45 for: 6.0.0-rc0 WT-8990 Validate commit and durability timestamps at transaction commit
Diffstat (limited to 'src/third_party/wiredtiger')
-rw-r--r--src/third_party/wiredtiger/import.data2
-rw-r--r--src/third_party/wiredtiger/src/docs/timestamp-misc.dox9
-rw-r--r--src/third_party/wiredtiger/src/docs/transactions_api.dox12
-rw-r--r--src/third_party/wiredtiger/src/include/extern.h6
-rw-r--r--src/third_party/wiredtiger/src/session/session_api.c4
-rw-r--r--src/third_party/wiredtiger/src/txn/txn.c4
-rw-r--r--src/third_party/wiredtiger/src/txn/txn_timestamp.c132
-rw-r--r--src/third_party/wiredtiger/test/format/format.h1
-rw-r--r--src/third_party/wiredtiger/test/format/ops.c32
-rw-r--r--src/third_party/wiredtiger/test/format/snap.c5
-rw-r--r--src/third_party/wiredtiger/test/format/util.c21
-rw-r--r--src/third_party/wiredtiger/test/format/wts.c2
-rw-r--r--src/third_party/wiredtiger/test/suite/test_checkpoint_snapshot02.py4
-rw-r--r--src/third_party/wiredtiger/test/suite/test_timestamp28.py59
14 files changed, 199 insertions, 94 deletions
diff --git a/src/third_party/wiredtiger/import.data b/src/third_party/wiredtiger/import.data
index 9de55d40aac..8fad1e19220 100644
--- a/src/third_party/wiredtiger/import.data
+++ b/src/third_party/wiredtiger/import.data
@@ -2,5 +2,5 @@
"vendor": "wiredtiger",
"github": "wiredtiger/wiredtiger.git",
"branch": "mongodb-master",
- "commit": "03dfd53f7ac5eef24fe50241610e701bd8f67cda"
+ "commit": "2aa2673d45c3ef1666107a5e381202f92502201e"
}
diff --git a/src/third_party/wiredtiger/src/docs/timestamp-misc.dox b/src/third_party/wiredtiger/src/docs/timestamp-misc.dox
index 5724a9fe814..537251a7773 100644
--- a/src/third_party/wiredtiger/src/docs/timestamp-misc.dox
+++ b/src/third_party/wiredtiger/src/docs/timestamp-misc.dox
@@ -61,15 +61,6 @@ will fail and drop core at the failing check.
These are best-effort checks by WiredTiger, and there are cases where
application misbehavior will not be detected.
-@section timestamp_misc_reset_snapshot Resetting the snapshot
-
-Transactions that have not set \c read_timestamp can use
-WT_SESSION::reset_snapshot with timestamped tables as with
-non-timestamped tables, to get a new snapshot of the database to read
-from. See @ref snapshot_reset.
-Transactions that have set \c read_timestamp can also call
-WT_SESSION::reset_snapshot, but it will have no effect.
-
@section timestamps_misc_in_memory In-memory configurations and timestamps
Timestamps are supported for in-memory databases, but must be configured as in
diff --git a/src/third_party/wiredtiger/src/docs/transactions_api.dox b/src/third_party/wiredtiger/src/docs/transactions_api.dox
index e3083aaac59..de4054018da 100644
--- a/src/third_party/wiredtiger/src/docs/transactions_api.dox
+++ b/src/third_party/wiredtiger/src/docs/transactions_api.dox
@@ -136,14 +136,16 @@ well as any key and value that may have been set.
@section snapshot_reset Resetting the session snapshot
-Snapshot-isolation transactions can pin a large amount of data into the database
+Snapshot-isolation transactions can pin large amounts of data into the database
cache in order to be able to satisfy potential reads at the snapshot.
WT_SESSION::reset_snapshot releases the current snapshot and gets a new (more
recent) snapshot to avoid pinning content in the cache that is no longer needed.
-Applications may see different search results compared to earlier after updating
-the snapshot. It is an error to call WT_SESSION::reset_snapshot at any isolation
-level other than snapshot, or if the current transaction has performed any write
-operations.
+It is an error to call WT_SESSION::reset_snapshot at any isolation level other
+than snapshot, or if the current transaction has performed any write operations.
+
+\warning
+Applications not using read timestamps for search may see different results
+after the snapshot is updated.
@snippet ex_all.c reset snapshot
diff --git a/src/third_party/wiredtiger/src/include/extern.h b/src/third_party/wiredtiger/src/include/extern.h
index 5b6c36bdb6e..7ebf7ba83e1 100644
--- a/src/third_party/wiredtiger/src/include/extern.h
+++ b/src/third_party/wiredtiger/src/include/extern.h
@@ -1588,7 +1588,7 @@ extern int __wt_txn_set_prepare_timestamp(WT_SESSION_IMPL *session, wt_timestamp
WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_txn_set_read_timestamp(WT_SESSION_IMPL *session, wt_timestamp_t read_ts)
WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
-extern int __wt_txn_set_timestamp(WT_SESSION_IMPL *session, const char *cfg[])
+extern int __wt_txn_set_timestamp(WT_SESSION_IMPL *session, const char *cfg[], bool commit)
WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_txn_set_timestamp_uint(WT_SESSION_IMPL *session, WT_TS_TXN_TYPE which,
wt_timestamp_t ts) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
@@ -1600,6 +1600,10 @@ extern int __wt_txn_update_oldest(WT_SESSION_IMPL *session, uint32_t flags)
WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_txn_update_pinned_timestamp(WT_SESSION_IMPL *session, bool force)
WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
+extern int __wt_txn_validate_commit_timestamp(WT_SESSION_IMPL *session, wt_timestamp_t *commit_tsp)
+ WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
+extern int __wt_txn_validate_durable_timestamp(WT_SESSION_IMPL *session, wt_timestamp_t durable_ts)
+ WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_unexpected_object_type(
WT_SESSION_IMPL *session, const char *uri, const char *expect) WT_GCC_FUNC_DECL_ATTRIBUTE((cold))
WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
diff --git a/src/third_party/wiredtiger/src/session/session_api.c b/src/third_party/wiredtiger/src/session/session_api.c
index c66963875ae..8adaee16387 100644
--- a/src/third_party/wiredtiger/src/session/session_api.c
+++ b/src/third_party/wiredtiger/src/session/session_api.c
@@ -1797,7 +1797,7 @@ __session_timestamp_transaction(WT_SESSION *wt_session, const char *config)
cfg[1] = config;
#endif
- ret = __wt_txn_set_timestamp(session, cfg);
+ ret = __wt_txn_set_timestamp(session, cfg, false);
err:
API_END_RET(session, ret);
}
@@ -1851,7 +1851,7 @@ __session_reset_snapshot(WT_SESSION *wt_session)
session = (WT_SESSION_IMPL *)wt_session;
txn = session->txn;
- /* Return error if the isolation mode is read committed. */
+ /* Return error if the isolation mode is not snapshot. */
if (txn->isolation != WT_ISO_SNAPSHOT)
WT_RET_MSG(
session, ENOTSUP, "not supported in read-committed or read-uncommitted transactions");
diff --git a/src/third_party/wiredtiger/src/txn/txn.c b/src/third_party/wiredtiger/src/txn/txn.c
index 730b08225e1..641d3ed0e5b 100644
--- a/src/third_party/wiredtiger/src/txn/txn.c
+++ b/src/third_party/wiredtiger/src/txn/txn.c
@@ -1491,7 +1491,7 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
F_CLR(txn, WT_TXN_TS_ROUND_PREPARED);
/* Set the commit and the durable timestamps. */
- WT_ERR(__wt_txn_set_timestamp(session, cfg));
+ WT_ERR(__wt_txn_set_timestamp(session, cfg, true));
if (prepare) {
if (!F_ISSET(txn, WT_TXN_HAS_TS_COMMIT))
@@ -1786,7 +1786,7 @@ __wt_txn_prepare(WT_SESSION_IMPL *session, const char *cfg[])
WT_RET_MSG(session, EINVAL, "a prepared transaction cannot include a logged table");
/* Set the prepare timestamp. */
- WT_RET(__wt_txn_set_timestamp(session, cfg));
+ WT_RET(__wt_txn_set_timestamp(session, cfg, false));
if (!F_ISSET(txn, WT_TXN_HAS_TS_PREPARE))
WT_RET_MSG(session, EINVAL, "prepare timestamp is not set");
diff --git a/src/third_party/wiredtiger/src/txn/txn_timestamp.c b/src/third_party/wiredtiger/src/txn/txn_timestamp.c
index 5fe02c397cf..160f638a72c 100644
--- a/src/third_party/wiredtiger/src/txn/txn_timestamp.c
+++ b/src/third_party/wiredtiger/src/txn/txn_timestamp.c
@@ -520,28 +520,25 @@ __txn_assert_after_reads(WT_SESSION_IMPL *session, const char *op, wt_timestamp_
}
/*
- * __wt_txn_set_commit_timestamp --
+ * __wt_txn_validate_commit_timestamp --
* Validate the commit timestamp of a transaction.
*/
int
-__wt_txn_set_commit_timestamp(WT_SESSION_IMPL *session, wt_timestamp_t commit_ts)
+__wt_txn_validate_commit_timestamp(WT_SESSION_IMPL *session, wt_timestamp_t *commit_tsp)
{
WT_TXN *txn;
WT_TXN_GLOBAL *txn_global;
- wt_timestamp_t oldest_ts, stable_ts;
+ wt_timestamp_t commit_ts, oldest_ts, stable_ts;
char ts_string[2][WT_TS_INT_STRING_SIZE];
bool has_oldest_ts, has_stable_ts;
txn = session->txn;
txn_global = &S2C(session)->txn_global;
+ commit_ts = *commit_tsp;
/* Added this redundant initialization to circumvent build failure. */
oldest_ts = stable_ts = WT_TS_NONE;
- if (txn->isolation != WT_ISO_SNAPSHOT)
- WT_RET_MSG(session, EINVAL,
- "setting a commit_timestamp requires a transaction running at snapshot isolation");
-
/*
* Compare against the oldest and the stable timestamp. Return an error if the given timestamp
* is less than oldest and/or stable timestamp.
@@ -595,16 +592,40 @@ __wt_txn_set_commit_timestamp(WT_SESSION_IMPL *session, wt_timestamp_t commit_ts
"commit timestamp %s is less than the prepare timestamp %s for this transaction",
__wt_timestamp_to_string(commit_ts, ts_string[0]),
__wt_timestamp_to_string(txn->prepare_timestamp, ts_string[1]));
- commit_ts = txn->prepare_timestamp;
+
+ /* Update the caller's value. */
+ *commit_tsp = txn->prepare_timestamp;
}
if (!F_ISSET(txn, WT_TXN_PREPARE))
WT_RET_MSG(
session, EINVAL, "commit timestamp must not be set before transaction is prepared");
}
- WT_ASSERT(session,
- !F_ISSET(txn, WT_TXN_HAS_TS_DURABLE) || txn->durable_timestamp == txn->commit_timestamp);
+ return (0);
+}
+
+/*
+ * __wt_txn_set_commit_timestamp --
+ * Set the commit timestamp of a transaction.
+ */
+int
+__wt_txn_set_commit_timestamp(WT_SESSION_IMPL *session, wt_timestamp_t commit_ts)
+{
+ WT_TXN *txn;
+
+ txn = session->txn;
+
+ if (txn->isolation != WT_ISO_SNAPSHOT)
+ WT_RET_MSG(session, EINVAL,
+ "setting a commit_timestamp requires a transaction running at snapshot isolation");
+
+ /*
+ * In scenarios where the prepare timestamp is greater than the provided commit timestamp, the
+ * validate function returns the new commit timestamp based on the configuration.
+ */
+ WT_RET(__wt_txn_validate_commit_timestamp(session, &commit_ts));
txn->commit_timestamp = commit_ts;
+
/*
* First time copy the commit timestamp to the first commit timestamp.
*/
@@ -624,11 +645,11 @@ __wt_txn_set_commit_timestamp(WT_SESSION_IMPL *session, wt_timestamp_t commit_ts
}
/*
- * __wt_txn_set_durable_timestamp --
+ * __wt_txn_validate_durable_timestamp --
* Validate the durable timestamp of a transaction.
*/
int
-__wt_txn_set_durable_timestamp(WT_SESSION_IMPL *session, wt_timestamp_t durable_ts)
+__wt_txn_validate_durable_timestamp(WT_SESSION_IMPL *session, wt_timestamp_t durable_ts)
{
WT_TXN *txn;
WT_TXN_GLOBAL *txn_global;
@@ -642,13 +663,6 @@ __wt_txn_set_durable_timestamp(WT_SESSION_IMPL *session, wt_timestamp_t durable_
/* Added this redundant initialization to circumvent build failure. */
oldest_ts = stable_ts = 0;
- if (!F_ISSET(txn, WT_TXN_PREPARE))
- WT_RET_MSG(session, EINVAL,
- "durable timestamp should not be specified for non-prepared transaction");
-
- if (!F_ISSET(txn, WT_TXN_HAS_TS_COMMIT))
- WT_RET_MSG(session, EINVAL, "commit timestamp is needed before the durable timestamp");
-
/*
* Compare against the oldest and the stable timestamp. Return an error if the given timestamp
* is less than oldest and/or stable timestamp.
@@ -677,6 +691,29 @@ __wt_txn_set_durable_timestamp(WT_SESSION_IMPL *session, wt_timestamp_t durable_
__wt_timestamp_to_string(durable_ts, ts_string[0]),
__wt_timestamp_to_string(txn->commit_timestamp, ts_string[1]));
+ return (0);
+}
+
+/*
+ * __wt_txn_set_durable_timestamp --
+ * Set the durable timestamp of a transaction.
+ */
+int
+__wt_txn_set_durable_timestamp(WT_SESSION_IMPL *session, wt_timestamp_t durable_ts)
+{
+ WT_TXN *txn;
+
+ txn = session->txn;
+
+ if (!F_ISSET(txn, WT_TXN_PREPARE))
+ WT_RET_MSG(session, EINVAL,
+ "durable timestamp should not be specified for non-prepared transaction");
+
+ if (!F_ISSET(txn, WT_TXN_HAS_TS_COMMIT))
+ WT_RET_MSG(
+ session, EINVAL, "a commit timestamp is required before setting a durable timestamp");
+
+ WT_RET(__wt_txn_validate_durable_timestamp(session, durable_ts));
txn->durable_timestamp = durable_ts;
F_SET(txn, WT_TXN_HAS_TS_DURABLE);
@@ -869,51 +906,58 @@ __wt_txn_set_read_timestamp(WT_SESSION_IMPL *session, wt_timestamp_t read_ts)
* Parse a request to set a timestamp in a transaction.
*/
int
-__wt_txn_set_timestamp(WT_SESSION_IMPL *session, const char *cfg[])
+__wt_txn_set_timestamp(WT_SESSION_IMPL *session, const char *cfg[], bool commit)
{
WT_CONFIG cparser;
WT_CONFIG_ITEM ckey, cval;
WT_CONNECTION_IMPL *conn;
WT_DECL_RET;
+ WT_TXN *txn;
wt_timestamp_t commit_ts, durable_ts, prepare_ts, read_ts;
bool set_ts;
conn = S2C(session);
- commit_ts = durable_ts = prepare_ts = read_ts = WT_TS_NONE;
+ txn = session->txn;
set_ts = false;
WT_RET(__wt_txn_context_check(session, true));
/*
- * If the API received no configuration string, or we just have the base configuration, there's
- * nothing to do.
+ * If no commit or durable timestamp is set here, set to any previously set values and validate
+ * them, the stable timestamp might have moved forward since they were successfully set.
*/
- if (cfg == NULL || cfg[0] == NULL || cfg[1] == NULL)
- return (0);
+ commit_ts = durable_ts = prepare_ts = read_ts = WT_TS_NONE;
+ if (commit && F_ISSET(txn, WT_TXN_HAS_TS_COMMIT))
+ commit_ts = txn->commit_timestamp;
+ if (commit && F_ISSET(txn, WT_TXN_HAS_TS_DURABLE))
+ durable_ts = txn->durable_timestamp;
/*
- * We take a shortcut in parsing that works because we're only given a base configuration and a
- * user configuration.
+ * If the API received no configuration string, or we just have the base configuration, there
+ * are no strings to parse. Additionally, take a shortcut in parsing that works because we're
+ * only given a base configuration and a user configuration.
*/
- WT_ASSERT(session, cfg[0] != NULL && cfg[1] != NULL && cfg[2] == NULL);
- __wt_config_init(session, &cparser, cfg[1]);
- while ((ret = __wt_config_next(&cparser, &ckey, &cval)) == 0) {
- WT_ASSERT(session, ckey.str != NULL);
- if (WT_STRING_MATCH("commit_timestamp", ckey.str, ckey.len)) {
- WT_RET(__wt_txn_parse_timestamp(session, "commit", &commit_ts, &cval));
- set_ts = true;
- } else if (WT_STRING_MATCH("durable_timestamp", ckey.str, ckey.len)) {
- WT_RET(__wt_txn_parse_timestamp(session, "durable", &durable_ts, &cval));
- set_ts = true;
- } else if (WT_STRING_MATCH("prepare_timestamp", ckey.str, ckey.len)) {
- WT_RET(__wt_txn_parse_timestamp(session, "prepare", &prepare_ts, &cval));
- set_ts = true;
- } else if (WT_STRING_MATCH("read_timestamp", ckey.str, ckey.len)) {
- WT_RET(__wt_txn_parse_timestamp(session, "read", &read_ts, &cval));
- set_ts = true;
+ if (cfg != NULL && cfg[0] != NULL && cfg[1] != NULL) {
+ WT_ASSERT(session, cfg[2] == NULL);
+ __wt_config_init(session, &cparser, cfg[1]);
+ while ((ret = __wt_config_next(&cparser, &ckey, &cval)) == 0) {
+ WT_ASSERT(session, ckey.str != NULL);
+ if (WT_STRING_MATCH("commit_timestamp", ckey.str, ckey.len)) {
+ WT_RET(__wt_txn_parse_timestamp(session, "commit", &commit_ts, &cval));
+ set_ts = true;
+ } else if (WT_STRING_MATCH("durable_timestamp", ckey.str, ckey.len)) {
+ WT_RET(__wt_txn_parse_timestamp(session, "durable", &durable_ts, &cval));
+ set_ts = true;
+ } else if (WT_STRING_MATCH("prepare_timestamp", ckey.str, ckey.len)) {
+ WT_RET(__wt_txn_parse_timestamp(session, "prepare", &prepare_ts, &cval));
+ set_ts = true;
+ } else if (WT_STRING_MATCH("read_timestamp", ckey.str, ckey.len)) {
+ WT_RET(__wt_txn_parse_timestamp(session, "read", &read_ts, &cval));
+ set_ts = true;
+ }
}
+ WT_RET_NOTFOUND_OK(ret);
}
- WT_RET_NOTFOUND_OK(ret);
/* Look for a commit timestamp. */
if (commit_ts != WT_TS_NONE)
diff --git a/src/third_party/wiredtiger/test/format/format.h b/src/third_party/wiredtiger/test/format/format.h
index f53f519fd70..dd3f5d58018 100644
--- a/src/third_party/wiredtiger/test/format/format.h
+++ b/src/third_party/wiredtiger/test/format/format.h
@@ -374,6 +374,7 @@ void key_gen_teardown(WT_ITEM *);
void key_init(TABLE *, void *);
void lock_destroy(WT_SESSION *, RWLOCK *);
void lock_init(WT_SESSION *, RWLOCK *);
+uint64_t maximum_read_ts(void);
void operations(u_int, bool);
void path_setup(const char *);
void set_alarm(u_int);
diff --git a/src/third_party/wiredtiger/test/format/ops.c b/src/third_party/wiredtiger/test/format/ops.c
index 62e29d2919b..df58005f131 100644
--- a/src/third_party/wiredtiger/test/format/ops.c
+++ b/src/third_party/wiredtiger/test/format/ops.c
@@ -401,7 +401,6 @@ operations(u_int ops_seconds, bool lastrun)
static void
begin_transaction_ts(TINFO *tinfo)
{
- TINFO **tlp;
WT_DECL_RET;
WT_SESSION *session;
uint64_t ts;
@@ -410,16 +409,13 @@ begin_transaction_ts(TINFO *tinfo)
session = tinfo->session;
/*
- * Transaction reads are normally repeatable, but WiredTiger timestamps allow rewriting commits,
- * that is, applications can specify at commit time the timestamp at which the commit happens.
- * If that happens, our read might no longer be repeatable. Test in both modes: pick a read
- * timestamp we know is repeatable (because it's at least as old as the oldest resolved commit
- * timestamp in any thread), and pick a current timestamp, 50% of the time.
+ * Transaction timestamp reads are repeatable, but read timestamps must be before any possible
+ * commit timestamp. Without a read timestamp, reads are based on the transaction snapshot,
+ * which will include the latest values as of when the snapshot is taken. Test in both modes:
+ * 75% of the time, pick a read timestamp before any commit timestamp in any thread, 25% of
+ * the time don't set a timestamp at all.
*/
- ts = 0;
- if (mmrand(&tinfo->rnd, 1, 2) == 1)
- for (ts = UINT64_MAX, tlp = tinfo_list; *tlp != NULL; ++tlp)
- ts = WT_MIN(ts, (*tlp)->commit_ts);
+ ts = mmrand(&tinfo->rnd, 1, 4) == 1 ? 0 : maximum_read_ts();
if (ts != 0) {
wiredtiger_begin_transaction(session, NULL);
@@ -442,22 +438,6 @@ begin_transaction_ts(TINFO *tinfo)
wiredtiger_begin_transaction(session, NULL);
- /*
- * Otherwise, pick a current timestamp.
- *
- * Prepare returns an error if the prepare timestamp is less than any active read timestamp,
- * single-thread transaction prepare and begin.
- *
- * Lock out the oldest timestamp update.
- */
- lock_writelock(session, &g.ts_lock);
-
- ts = __wt_atomic_addv64(&g.timestamp, 1);
- testutil_check(__wt_snprintf(buf, sizeof(buf), "read_timestamp=%" PRIx64, ts));
- testutil_check(session->timestamp_transaction(session, buf));
-
- lock_writeunlock(session, &g.ts_lock);
-
snap_op_init(tinfo, ts, false);
trace_op(tinfo, "begin snapshot read-ts=%" PRIu64 " (not repeatable)", ts);
}
diff --git a/src/third_party/wiredtiger/test/format/snap.c b/src/third_party/wiredtiger/test/format/snap.c
index 2982f5bf4a1..94a7643c234 100644
--- a/src/third_party/wiredtiger/test/format/snap.c
+++ b/src/third_party/wiredtiger/test/format/snap.c
@@ -603,9 +603,12 @@ void
snap_repeat_single(TINFO *tinfo)
{
SNAP_OPS *snap;
+ uint64_t ts;
u_int v;
int count;
+ ts = maximum_read_ts();
+
/*
* Start at a random spot in the list of operations and look for a read to retry. Stop when
* we've walked the entire list or found one.
@@ -616,7 +619,7 @@ snap_repeat_single(TINFO *tinfo)
if (snap >= tinfo->snap_end)
snap = tinfo->snap_list;
- if (snap->repeatable)
+ if (snap->repeatable && snap->ts <= ts)
break;
}
diff --git a/src/third_party/wiredtiger/test/format/util.c b/src/third_party/wiredtiger/test/format/util.c
index 30f446da4e7..d0566e456a4 100644
--- a/src/third_party/wiredtiger/test/format/util.c
+++ b/src/third_party/wiredtiger/test/format/util.c
@@ -401,6 +401,27 @@ set_oldest_timestamp(void)
}
/*
+ * maximum_read_ts --
+ * Return the largest safe read timestamp.
+ */
+uint64_t
+maximum_read_ts(void)
+{
+ TINFO **tlp;
+ uint64_t ts;
+
+ /*
+ * We can't use a read timestamp that's ahead of a commit timestamp. Find the maximum safe read
+ * timestamp.
+ */
+ for (ts = g.timestamp, tlp = tinfo_list; *tlp != NULL; ++tlp)
+ ts = WT_MIN(ts, (*tlp)->commit_ts);
+ if (ts != 0)
+ --ts;
+ return (ts);
+}
+
+/*
* lock_init --
* Initialize abstract lock that can use either pthread of wt reader-writer locks.
*/
diff --git a/src/third_party/wiredtiger/test/format/wts.c b/src/third_party/wiredtiger/test/format/wts.c
index 92f8f6bbf5a..dc91c759bf1 100644
--- a/src/third_party/wiredtiger/test/format/wts.c
+++ b/src/third_party/wiredtiger/test/format/wts.c
@@ -380,7 +380,7 @@ create_object(TABLE *table, void *arg)
/* Assertions: assertions slow down the code for additional diagnostic checking. */
if (GV(ASSERT_READ_TIMESTAMP))
CONFIG_APPEND(
- p, ",assert=(read_timestamp=%s)", g.transaction_timestamps_config ? "always" : "never");
+ p, ",assert=(read_timestamp=%s)", g.transaction_timestamps_config ? "none" : "never");
if (GV(ASSERT_WRITE_TIMESTAMP))
CONFIG_APPEND(p, ",assert=(write_timestamp=on),write_timestamp_usage=%s",
g.transaction_timestamps_config ? "always" : "never");
diff --git a/src/third_party/wiredtiger/test/suite/test_checkpoint_snapshot02.py b/src/third_party/wiredtiger/test/suite/test_checkpoint_snapshot02.py
index c1f3f070944..89a7faddfc0 100644
--- a/src/third_party/wiredtiger/test/suite/test_checkpoint_snapshot02.py
+++ b/src/third_party/wiredtiger/test/suite/test_checkpoint_snapshot02.py
@@ -207,8 +207,8 @@ class test_checkpoint_snapshot02(wttest.WiredTigerTestCase):
self.assertEqual(cursor1.insert(), 0)
session1.timestamp_transaction('commit_timestamp=' + self.timestamp_str(30))
- # Set stable timestamp to 40
- self.conn.set_timestamp('stable_timestamp=' + self.timestamp_str(40))
+ # Set stable timestamp to 25
+ self.conn.set_timestamp('stable_timestamp=' + self.timestamp_str(25))
# Create a checkpoint thread
done = threading.Event()
diff --git a/src/third_party/wiredtiger/test/suite/test_timestamp28.py b/src/third_party/wiredtiger/test/suite/test_timestamp28.py
new file mode 100644
index 00000000000..259499d7182
--- /dev/null
+++ b/src/third_party/wiredtiger/test/suite/test_timestamp28.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+#
+# Public Domain 2014-present MongoDB, Inc.
+# Public Domain 2008-2014 WiredTiger, Inc.
+#
+# This is free and unencumbered software released into the public domain.
+#
+# Anyone is free to copy, modify, publish, use, compile, sell, or
+# distribute this software, either in source code form or as a compiled
+# binary, for any purpose, commercial or non-commercial, and by any
+# means.
+#
+# In jurisdictions that recognize copyright laws, the author or authors
+# of this software dedicate any and all copyright interest in the
+# software to the public domain. We make this dedication for the benefit
+# of the public at large and to the detriment of our heirs and
+# successors. We intend this dedication to be an overt act of
+# relinquishment in perpetuity of all present and future rights to this
+# software under copyright law.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# test_timestamp28.py
+# Timestamps: smoke test that commit is tested at both commit and set time.
+
+import wiredtiger, wttest
+from wtdataset import SimpleDataSet
+
+# Timestamps: smoke test that commit is tested at both commit and set time.
+class test_timestamp28(wttest.WiredTigerTestCase):
+ def test_timestamp28(self):
+ uri = 'table:timestamp28'
+ ds = SimpleDataSet(self, uri, 50, key_format='i', value_format='S')
+ ds.populate()
+ c = self.session.open_cursor(uri)
+
+ self.conn.set_timestamp('stable_timestamp=' + self.timestamp_str(30))
+ self.session.begin_transaction()
+ c[5] = 'xxx'
+ self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
+ lambda: self.session.commit_transaction(
+ 'commit_timestamp=' + self.timestamp_str(20)), '/must be after/')
+
+ self.conn.set_timestamp('stable_timestamp=' + self.timestamp_str(40))
+ self.session.begin_transaction()
+ c[5] = 'xxx'
+ self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(50))
+ self.conn.set_timestamp('stable_timestamp=' + self.timestamp_str(60))
+ self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
+ lambda: self.session.commit_transaction(), '/must be after/')
+
+if __name__ == '__main__':
+ wttest.run()