summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Chen <luke.chen@mongodb.com>2020-06-10 16:12:22 +1000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-06-10 06:31:42 +0000
commitbea79f76addfe4b754c8696db029c5b3c762041c (patch)
tree187e6f29515fcdf6b14526a76071b98d27244ae0
parent2a20c87a57afdd20349ed35258b92f998a19603f (diff)
downloadmongo-bea79f76addfe4b754c8696db029c5b3c762041c.tar.gz
Import wiredtiger: 154719f3ff736872f67f2b3e9f4d8b396d2d8adf from branch mongodb-4.4r4.4.0-rc9
ref: bf1d78126c..154719f3ff for: 4.4.0-rc9 WT-6185 Insert full updates into the history store in some corner cases and add a history store c test WT-6257 Fix rows out-of-order in history store file WT-6339 Stop creating snapshots for history store cursors WT-6396 Fix wrong assert when inserting updates to the history store
-rw-r--r--src/third_party/wiredtiger/dist/s_string.ok3
-rw-r--r--src/third_party/wiredtiger/import.data2
-rw-r--r--src/third_party/wiredtiger/src/btree/bt_curnext.c3
-rw-r--r--src/third_party/wiredtiger/src/btree/bt_debug.c4
-rw-r--r--src/third_party/wiredtiger/src/btree/row_srch.c23
-rw-r--r--src/third_party/wiredtiger/src/cursor/cur_file.c2
-rw-r--r--src/third_party/wiredtiger/src/history/hs.c235
-rw-r--r--src/third_party/wiredtiger/src/include/cursor.h9
-rw-r--r--src/third_party/wiredtiger/src/include/cursor.i43
-rw-r--r--src/third_party/wiredtiger/src/include/extern.h1
-rw-r--r--src/third_party/wiredtiger/src/include/wiredtiger.in33
-rw-r--r--src/third_party/wiredtiger/src/support/modify.c12
-rw-r--r--src/third_party/wiredtiger/src/txn/txn.c6
-rw-r--r--src/third_party/wiredtiger/test/csuite/Makefile.am4
-rw-r--r--src/third_party/wiredtiger/test/csuite/wt6185_modify_ts/main.c383
-rwxr-xr-xsrc/third_party/wiredtiger/test/evergreen.yml15
-rw-r--r--src/third_party/wiredtiger/test/format/Makefile.am4
-rw-r--r--src/third_party/wiredtiger/test/format/alter.c76
-rw-r--r--src/third_party/wiredtiger/test/format/bulk.c14
-rw-r--r--src/third_party/wiredtiger/test/format/format.h2
-rw-r--r--src/third_party/wiredtiger/test/format/format.i18
-rw-r--r--src/third_party/wiredtiger/test/format/ops.c80
-rw-r--r--src/third_party/wiredtiger/test/format/snap.c29
-rw-r--r--src/third_party/wiredtiger/test/format/t.c2
-rw-r--r--src/third_party/wiredtiger/test/format/util.c47
-rw-r--r--src/third_party/wiredtiger/test/format/wts.c4
-rw-r--r--src/third_party/wiredtiger/test/suite/test_hs08.py2
27 files changed, 745 insertions, 311 deletions
diff --git a/src/third_party/wiredtiger/dist/s_string.ok b/src/third_party/wiredtiger/dist/s_string.ok
index 294166060f6..23ba8dc737e 100644
--- a/src/third_party/wiredtiger/dist/s_string.ok
+++ b/src/third_party/wiredtiger/dist/s_string.ok
@@ -563,6 +563,8 @@ cb
ccc
ccr
cd
+ce
+ceh
centric
cfg
cfko
@@ -1212,6 +1214,7 @@ rwlock
sH
sHQ
sT
+sanitizer
sanitizers
scalability
sched
diff --git a/src/third_party/wiredtiger/import.data b/src/third_party/wiredtiger/import.data
index 942a0437e0e..7381ba0bcfe 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-4.4",
- "commit": "bf1d78126c2ff448b868f199aef22b6c528dd45d"
+ "commit": "154719f3ff736872f67f2b3e9f4d8b396d2d8adf"
}
diff --git a/src/third_party/wiredtiger/src/btree/bt_curnext.c b/src/third_party/wiredtiger/src/btree/bt_curnext.c
index 4b20a8fa3a2..e6047060faf 100644
--- a/src/third_party/wiredtiger/src/btree/bt_curnext.c
+++ b/src/third_party/wiredtiger/src/btree/bt_curnext.c
@@ -548,7 +548,8 @@ __wt_cursor_key_order_reset(WT_CURSOR_BTREE *cbt)
/*
* Clear the last-key returned, it doesn't apply.
*/
- cbt->lastkey->size = 0;
+ if (cbt->lastkey != NULL)
+ cbt->lastkey->size = 0;
cbt->lastrecno = WT_RECNO_OOB;
}
#endif
diff --git a/src/third_party/wiredtiger/src/btree/bt_debug.c b/src/third_party/wiredtiger/src/btree/bt_debug.c
index dff7010448a..f5a8cf0019e 100644
--- a/src/third_party/wiredtiger/src/btree/bt_debug.c
+++ b/src/third_party/wiredtiger/src/btree/bt_debug.c
@@ -337,8 +337,6 @@ __wt_debug_addr(WT_SESSION_IMPL *session, const uint8_t *addr, size_t addr_size,
WT_DECL_ITEM(buf);
WT_DECL_RET;
- WT_ASSERT(session, S2BT_SAFE(session) != NULL);
-
bm = S2BT(session)->bm;
WT_RET(__wt_scr_alloc(session, 1024, &buf));
@@ -1022,10 +1020,10 @@ __debug_page(WT_DBG *ds, WT_REF *ref, uint32_t flags)
WT_SESSION_IMPL *session;
session = ds->session;
+ WT_RET(__wt_scr_alloc(session, 100, &ds->key));
/* Set up history store support. */
if (!WT_IS_HS(S2BT(session))) {
- WT_RET(__wt_scr_alloc(session, 100, &ds->key));
WT_RET(__wt_scr_alloc(session, 0, &ds->hs_key));
WT_RET(__wt_scr_alloc(session, 0, &ds->hs_value));
if (session->hs_cursor == NULL) {
diff --git a/src/third_party/wiredtiger/src/btree/row_srch.c b/src/third_party/wiredtiger/src/btree/row_srch.c
index 05516281d59..75bf4b9aa44 100644
--- a/src/third_party/wiredtiger/src/btree/row_srch.c
+++ b/src/third_party/wiredtiger/src/btree/row_srch.c
@@ -242,9 +242,9 @@ __wt_row_search(WT_CURSOR_BTREE *cbt, WT_ITEM *srch_key, bool insert, WT_REF *le
* In some cases we expect we're comparing more than a few keys with matching prefixes, so it's
* faster to avoid the memory fetches by skipping over those prefixes. That's done by tracking
* the length of the prefix match for the lowest and highest keys we compare as we descend the
- * tree.
+ * tree. The high boundary is reset on each new page, the lower boundary is maintained.
*/
- skiphigh = skiplow = 0;
+ skiplow = 0;
/*
* If a cursor repeatedly appends to the tree, compare the search key against the last key on
@@ -281,7 +281,7 @@ restart:
* Discard the currently held page and restart the search from the root.
*/
WT_RET(__wt_page_release(session, current, 0));
- skiphigh = skiplow = 0;
+ skiplow = 0;
}
/* Search the internal pages of the tree. */
@@ -352,8 +352,7 @@ restart:
* parent, the child page's key space will have been truncated, and the values from the
* parent's search may be wrong for the child. We only need to reset the high count
* because the split-page algorithm truncates the end of the internal page's key space,
- * the low count is still correct. We also don't need to clear either count when
- * transitioning to a leaf page, a leaf page's key space can't change in flight.
+ * the low count is still correct.
*/
skiphigh = 0;
@@ -501,7 +500,17 @@ leaf_only:
} else if (cmp == 0)
goto leaf_match;
}
- else if (collator == NULL)
+ else if (collator == NULL) {
+ /*
+ * Reset the skipped prefix counts; we'd normally expect the parent's skipped prefix values
+ * to be larger than the child's values and so we'd only increase them as we walk down the
+ * tree (in other words, if we can skip N bytes on the parent, we can skip at least N bytes
+ * on the child). However, leaf pages at the end of the tree can be extended, causing the
+ * parent's search to be wrong for the child. We only need to reset the high count, the page
+ * can only be extended so the low count is still correct.
+ */
+ skiphigh = 0;
+
for (; limit != 0; limit >>= 1) {
indx = base + (limit >> 1);
rip = page->pg_row + indx;
@@ -518,7 +527,7 @@ leaf_only:
else
goto leaf_match;
}
- else
+ } else
for (; limit != 0; limit >>= 1) {
indx = base + (limit >> 1);
rip = page->pg_row + indx;
diff --git a/src/third_party/wiredtiger/src/cursor/cur_file.c b/src/third_party/wiredtiger/src/cursor/cur_file.c
index e19ee8b32b0..19e69d6dc3e 100644
--- a/src/third_party/wiredtiger/src/cursor/cur_file.c
+++ b/src/third_party/wiredtiger/src/cursor/cur_file.c
@@ -667,7 +667,7 @@ __curfile_create(WT_SESSION_IMPL *session, WT_CURSOR *owner, const char *cfg[],
__wt_cursor_dhandle_incr_use(session);
if (session->dhandle->checkpoint != NULL)
- F_SET(cbt, WT_CBT_NO_TXN);
+ F_SET(cbt, WT_CBT_NO_TXN | WT_CBT_NO_TRACKING);
if (bulk) {
F_SET(cursor, WT_CURSTD_BULK);
diff --git a/src/third_party/wiredtiger/src/history/hs.c b/src/third_party/wiredtiger/src/history/hs.c
index b55e1a77171..06ac36fc2ac 100644
--- a/src/third_party/wiredtiger/src/history/hs.c
+++ b/src/third_party/wiredtiger/src/history/hs.c
@@ -202,6 +202,10 @@ __wt_hs_cursor_open(WT_SESSION_IMPL *session)
session, ret = __wt_open_cursor(session, WT_HS_URI, NULL, open_cursor_cfg, &cursor));
WT_RET(ret);
+ /*
+ * Set the flag to stop creating snapshots for history store cursors
+ */
+ F_SET((WT_CURSOR_BTREE *)cursor, WT_CBT_NO_TXN);
/* History store cursors should always ignore tombstones. */
F_SET(cursor, WT_CURSTD_IGNORE_TOMBSTONE);
@@ -289,6 +293,9 @@ __hs_row_search(WT_CURSOR_BTREE *hs_cbt, WT_ITEM *srch_key, bool insert)
WT_WITH_BTREE(CUR2S(hs_cbt), CUR2BT(hs_cbt),
ret = __wt_row_search(hs_cbt, srch_key, insert, NULL, false, NULL));
+#ifdef HAVE_DIAGNOSTIC
+ WT_TRET(__wt_cursor_key_order_init(hs_cbt));
+#endif
return (ret);
}
@@ -416,10 +423,7 @@ __hs_insert_record_with_btree_int(WT_SESSION_IMPL *session, WT_CURSOR *cursor, W
else
hs_upd = upd_local;
- /*
- * Search the page and insert the updates. We expect there will be no existing data: assert that
- * we don't find a matching key.
- */
+ /* Search the page and insert the updates. */
WT_WITH_PAGE_INDEX(session, ret = __hs_row_search(cbt, &cursor->key, true));
WT_ERR(ret);
WT_ERR(__wt_hs_modify(cbt, hs_upd));
@@ -503,23 +507,15 @@ __hs_insert_record_with_btree(WT_SESSION_IMPL *session, WT_CURSOR *cursor, WT_BT
if (upd->start_ts != WT_TS_NONE)
goto done;
-/*
- * If we inserted an update with no timestamp, we need to delete all history records for that key
- * that are further in the history table than us (the key is lexicographically greater). For
- * timestamped tables that are occasionally getting a non-timestamped update, that means that all
- * timestamped updates should get removed. In the case of non-timestamped tables, that means that
- * all updates with higher transaction ids will get removed (which could happen at some more relaxed
- * isolation levels).
- */
-#ifdef HAVE_DIAGNOSTIC
/*
- * We need to initialize the last searched key so that we can do key comparisons when we
- * begin iterating over the history store. This needs to be done otherwise the subsequent
- * "next" calls will blow up.
+ * If we inserted an update with no timestamp, we need to delete all history records for that
+ * key that are further in the history table than us (the key is lexicographically greater). For
+ * timestamped tables that are occasionally getting a non-timestamped update, that means that
+ * all timestamped updates should get removed. In the case of non-timestamped tables, that means
+ * that all updates with higher transaction ids will get removed (which could happen at some
+ * more relaxed isolation levels). We're pointing at the newly inserted update, iterate once
+ * more to avoid deleting it.
*/
- WT_ERR(__wt_cursor_key_order_init((WT_CURSOR_BTREE *)cursor));
-#endif
- /* We're pointing at the newly inserted update. Iterate once more to avoid deleting it. */
WT_ERR_NOTFOUND_OK(cursor->next(cursor), true);
/* No records to delete. */
@@ -560,15 +556,36 @@ __hs_insert_record(WT_SESSION_IMPL *session, WT_CURSOR *cursor, WT_BTREE *btree,
}
/*
- * __hs_calculate_full_value --
- * Calculate the full value of an update.
+ * __hs_next_upd_full_value --
+ * Get the next update and its full value.
*/
static inline int
-__hs_calculate_full_value(WT_SESSION_IMPL *session, WT_ITEM *full_value, WT_UPDATE *upd,
- const void *base_full_value, size_t size)
+__hs_next_upd_full_value(WT_SESSION_IMPL *session, WT_MODIFY_VECTOR *modifies,
+ WT_ITEM *older_full_value, uint32_t btree_id, const WT_ITEM *key, WT_ITEM *full_value,
+ WT_UPDATE **updp)
{
- if (upd->type == WT_UPDATE_MODIFY) {
- WT_RET(__wt_buf_set(session, full_value, base_full_value, size));
+ WT_UPDATE *upd;
+ *updp = NULL;
+ __wt_modify_vector_pop(modifies, &upd);
+ if (upd->type == WT_UPDATE_TOMBSTONE) {
+ if (upd->start_ts == WT_TS_NONE) {
+ /* We can only delete history store entries that have timestamps. */
+ WT_RET(__wt_hs_delete_key_from_ts(session, btree_id, key, 1));
+ WT_STAT_CONN_INCR(session, cache_hs_key_truncate_mix_ts);
+ }
+
+ if (modifies->size == 0) {
+ WT_ASSERT(session, older_full_value == NULL);
+ *updp = upd;
+ return (0);
+ }
+
+ __wt_modify_vector_pop(modifies, &upd);
+ WT_ASSERT(session, upd->type == WT_UPDATE_STANDARD);
+ full_value->data = upd->data;
+ full_value->size = upd->size;
+ } else if (upd->type == WT_UPDATE_MODIFY) {
+ WT_RET(__wt_buf_set(session, full_value, older_full_value->data, older_full_value->size));
WT_RET(__wt_modify_apply_item(session, S2BT(session)->value_format, full_value, upd->data));
} else {
WT_ASSERT(session, upd->type == WT_UPDATE_STANDARD);
@@ -576,6 +593,7 @@ __hs_calculate_full_value(WT_SESSION_IMPL *session, WT_ITEM *full_value, WT_UPDA
full_value->size = upd->size;
}
+ *updp = upd;
return (0);
}
@@ -599,15 +617,14 @@ __wt_hs_insert_updates(WT_SESSION_IMPL *session, WT_PAGE *page, WT_MULTI *multi)
WT_MODIFY entries[MAX_REVERSE_MODIFY_NUM];
WT_MODIFY_VECTOR modifies;
WT_SAVE_UPD *list;
- WT_UPDATE *prev_upd, *second_older_than_prepare, *upd;
+ WT_UPDATE *prev_upd, *upd;
WT_HS_TIME_POINT stop_time_point;
wt_off_t hs_size;
uint64_t insert_cnt, max_hs_size;
uint32_t i;
uint8_t *p;
int nentries;
- bool squashed, track_prepare;
- uint8_t upd_count;
+ bool enable_reverse_modify, squashed;
btree = S2BT(session);
cursor = session->hs_cursor;
@@ -660,9 +677,7 @@ __wt_hs_insert_updates(WT_SESSION_IMPL *session, WT_PAGE *page, WT_MULTI *multi)
session, btree, upd = __wt_update_obsolete_check(session, page, list->onpage_upd, true));
__wt_free_update_list(session, &upd);
upd = list->onpage_upd;
- second_older_than_prepare = NULL;
- track_prepare = false;
- upd_count = 0;
+ enable_reverse_modify = true;
/*
* The algorithm assumes the oldest update on the update chain in memory is either a full
@@ -691,67 +706,49 @@ __wt_hs_insert_updates(WT_SESSION_IMPL *session, WT_PAGE *page, WT_MULTI *multi)
* tombstone.
* 4) We have a single tombstone on the chain, it is simply ignored.
*/
- for (; upd != NULL; upd = upd->next) {
+ for (prev_upd = NULL; upd != NULL; prev_upd = upd, upd = upd->next) {
if (upd->txnid == WT_TXN_ABORTED)
continue;
+
WT_ERR(__wt_modify_vector_push(&modifies, upd));
/*
- * If the update is the second update older than the prepared update and we haven't seen
- * a tombstone. Mark the update.
+ * Always insert full update to the history store if we write a prepared update to the
+ * data store.
*/
- if (upd->prepare_state == WT_PREPARE_INPROGRESS) {
- /*
- * No normal update between prepared updates and the first prepared update cannot be
- * a tombstone.
- */
- WT_ASSERT(session, (track_prepare && upd_count == 0) ||
- (!track_prepare && upd->type != WT_UPDATE_TOMBSTONE));
- track_prepare = true;
- } else if (track_prepare) {
- if (upd->type == WT_UPDATE_TOMBSTONE) {
- upd_count = 0;
- track_prepare = false;
- } else if (upd_count == 0)
- ++upd_count;
- else {
- second_older_than_prepare = upd;
- upd_count = 0;
- track_prepare = false;
- }
- }
+ if (upd->prepare_state == WT_PREPARE_INPROGRESS)
+ enable_reverse_modify = false;
+
+ /* Always insert full update to the history store if we need to squash the updates. */
+ if (prev_upd != NULL && prev_upd->txnid == upd->txnid &&
+ prev_upd->start_ts == upd->start_ts)
+ enable_reverse_modify = false;
+
+ /* Always insert full update to the history store if the timestamps are not in order. */
+ if (prev_upd != NULL && prev_upd->start_ts < upd->start_ts)
+ enable_reverse_modify = false;
/*
- * If we've reached a full update and its in the history store we don't need to continue
- * as anything beyond this point won't help with calculating deltas.
+ * If we've reached a full update and it's in the history store we don't need to
+ * continue as anything beyond this point won't help with calculating deltas.
*/
if (upd->type == WT_UPDATE_STANDARD && F_ISSET(upd, WT_UPDATE_HS))
break;
}
- upd = NULL;
+ prev_upd = upd = NULL;
/* Construct the oldest full update. */
WT_ASSERT(session, modifies.size > 0);
- __wt_modify_vector_pop(&modifies, &upd);
+
+#ifdef HAVE_DIAGNOSTIC
+ __wt_modify_vector_peek(&modifies, &upd);
WT_ASSERT(session, upd->type == WT_UPDATE_STANDARD || upd->type == WT_UPDATE_TOMBSTONE);
- /* Skip TOMBSTONE at the end of the update chain. */
- if (upd->type == WT_UPDATE_TOMBSTONE) {
- if (modifies.size > 0) {
- if (upd->start_ts == WT_TS_NONE) {
- /* We can only delete history store entries that have timestamps. */
- WT_ERR(__wt_hs_delete_key_from_ts(session, btree->id, key, 1));
- WT_STAT_CONN_INCR(session, cache_hs_key_truncate_mix_ts);
- }
- __wt_modify_vector_pop(&modifies, &upd);
- } else
- continue;
- }
+#endif
- WT_ASSERT(session, upd->type == WT_UPDATE_STANDARD);
- full_value->data = upd->data;
- full_value->size = upd->size;
+ WT_ERR(
+ __hs_next_upd_full_value(session, &modifies, NULL, btree->id, key, full_value, &upd));
squashed = false;
@@ -766,7 +763,7 @@ __wt_hs_insert_updates(WT_SESSION_IMPL *session, WT_PAGE *page, WT_MULTI *multi)
upd = prev_upd) {
WT_ASSERT(session, upd->type == WT_UPDATE_STANDARD || upd->type == WT_UPDATE_MODIFY);
- __wt_modify_vector_pop(&modifies, &prev_upd);
+ __wt_modify_vector_peek(&modifies, &prev_upd);
/*
* For any uncommitted prepared updates written to disk, the stop timestamp of the last
@@ -774,8 +771,8 @@ __wt_hs_insert_updates(WT_SESSION_IMPL *session, WT_PAGE *page, WT_MULTI *multi)
* removal by checkpoint garbage collection until the data store update is committed.
*/
if (prev_upd->prepare_state == WT_PREPARE_INPROGRESS) {
- WT_ASSERT(session,
- list->onpage_upd == prev_upd || list->onpage_upd->txnid == prev_upd->txnid);
+ WT_ASSERT(session, list->onpage_upd->txnid == prev_upd->txnid &&
+ list->onpage_upd->start_ts == prev_upd->start_ts);
stop_time_point.durable_ts = stop_time_point.ts = WT_TS_MAX;
stop_time_point.txnid = WT_TXN_MAX;
} else {
@@ -790,64 +787,38 @@ __wt_hs_insert_updates(WT_SESSION_IMPL *session, WT_PAGE *page, WT_MULTI *multi)
stop_time_point.txnid = prev_upd->txnid;
}
- if (prev_upd->type == WT_UPDATE_TOMBSTONE) {
- WT_ASSERT(session, modifies.size > 0);
- if (prev_upd->start_ts == WT_TS_NONE) {
- /* We can only delete history store entries that have timestamps. */
- WT_ERR(__wt_hs_delete_key_from_ts(session, btree->id, key, 1));
- WT_STAT_CONN_INCR(session, cache_hs_key_truncate_mix_ts);
- }
- __wt_modify_vector_pop(&modifies, &prev_upd);
- WT_ASSERT(session, prev_upd->type == WT_UPDATE_STANDARD);
- prev_full_value->data = prev_upd->data;
- prev_full_value->size = prev_upd->size;
- } else
- WT_ERR(__hs_calculate_full_value(
- session, prev_full_value, prev_upd, full_value->data, full_value->size));
+ WT_ERR(__hs_next_upd_full_value(
+ session, &modifies, full_value, btree->id, key, prev_full_value, &prev_upd));
- /*
- * Skip the updates have the same start timestamp and transaction id
- *
- * Modifies that have the same start time point as the onpage_upd can be squashed away.
- */
- if (upd->start_ts != prev_upd->start_ts || upd->txnid != prev_upd->txnid) {
- /*
- * Calculate reverse delta. Insert full update for the newest historical record even
- * it's a MODIFY.
- *
- * It is not correct to check prev_upd == list->onpage_upd as we may have aborted
- * updates in the middle.
- *
- * We must insert the first and second updates after a prepared update as full
- * values because if the prepared update is aborted, we will remove the first update
- * after it from the history store to the update chain. Readers reading the older
- * values need a full update as the base value for constructing reverse modifies.
- */
- nentries = MAX_REVERSE_MODIFY_NUM;
- if (!F_ISSET(upd, WT_UPDATE_HS)) {
- if (upd->type == WT_UPDATE_MODIFY &&
- prev_upd->prepare_state != WT_PREPARE_INPROGRESS &&
- (second_older_than_prepare == NULL || upd != second_older_than_prepare) &&
- __wt_calc_modify(session, prev_full_value, full_value,
- prev_full_value->size / 10, entries, &nentries) == 0) {
- WT_ERR(__wt_modify_pack(cursor, entries, nentries, &modify_value));
- WT_ERR(__hs_insert_record(session, cursor, btree, key, upd,
- WT_UPDATE_MODIFY, modify_value, &stop_time_point));
- __wt_scr_free(session, &modify_value);
- } else
- WT_ERR(__hs_insert_record(session, cursor, btree, key, upd,
- WT_UPDATE_STANDARD, full_value, &stop_time_point));
-
- /* Flag the update as now in the history store. */
- F_SET(upd, WT_UPDATE_HS);
- ++insert_cnt;
- if (squashed) {
- WT_STAT_CONN_INCR(session, cache_hs_write_squash);
- squashed = false;
- }
- }
- } else
+ /* Squash the updates from the same transaction. */
+ if (upd->start_ts == prev_upd->start_ts && upd->txnid == prev_upd->txnid) {
squashed = true;
+ continue;
+ }
+
+ if (F_ISSET(upd, WT_UPDATE_HS))
+ continue;
+
+ /* Calculate reverse modify. */
+ nentries = MAX_REVERSE_MODIFY_NUM;
+ if (upd->type == WT_UPDATE_MODIFY && enable_reverse_modify &&
+ __wt_calc_modify(session, prev_full_value, full_value, prev_full_value->size / 10,
+ entries, &nentries) == 0) {
+ WT_ERR(__wt_modify_pack(cursor, entries, nentries, &modify_value));
+ WT_ERR(__hs_insert_record(session, cursor, btree, key, upd, WT_UPDATE_MODIFY,
+ modify_value, &stop_time_point));
+ __wt_scr_free(session, &modify_value);
+ } else
+ WT_ERR(__hs_insert_record(session, cursor, btree, key, upd, WT_UPDATE_STANDARD,
+ full_value, &stop_time_point));
+
+ /* Flag the update as now in the history store. */
+ F_SET(upd, WT_UPDATE_HS);
+ ++insert_cnt;
+ if (squashed) {
+ WT_STAT_CONN_INCR(session, cache_hs_write_squash);
+ squashed = false;
+ }
}
if (modifies.size > 0)
diff --git a/src/third_party/wiredtiger/src/include/cursor.h b/src/third_party/wiredtiger/src/include/cursor.h
index e35791e5cb9..95e5c8de1fb 100644
--- a/src/third_party/wiredtiger/src/include/cursor.h
+++ b/src/third_party/wiredtiger/src/include/cursor.h
@@ -214,10 +214,11 @@ struct __wt_cursor_btree {
#define WT_CBT_ITERATE_PREV 0x008u /* Prev iteration configuration */
#define WT_CBT_ITERATE_RETRY_NEXT 0x010u /* Prepare conflict by next. */
#define WT_CBT_ITERATE_RETRY_PREV 0x020u /* Prepare conflict by prev. */
-#define WT_CBT_NO_TXN 0x040u /* Non-txn cursor (e.g. a checkpoint) */
-#define WT_CBT_READ_ONCE 0x080u /* Page in with WT_READ_WONT_NEED */
-#define WT_CBT_SEARCH_SMALLEST 0x100u /* Row-store: small-key insert list */
-#define WT_CBT_VAR_ONPAGE_MATCH 0x200u /* Var-store: on-page recno match */
+#define WT_CBT_NO_TRACKING 0x040u /* Non tracking cursor. */
+#define WT_CBT_NO_TXN 0x080u /* Non-txn cursor (e.g. a checkpoint) */
+#define WT_CBT_READ_ONCE 0x100u /* Page in with WT_READ_WONT_NEED */
+#define WT_CBT_SEARCH_SMALLEST 0x200u /* Row-store: small-key insert list */
+#define WT_CBT_VAR_ONPAGE_MATCH 0x400u /* Var-store: on-page recno match */
/* AUTOMATIC FLAG VALUE GENERATION STOP */
#define WT_CBT_POSITION_MASK /* Flags associated with position */ \
diff --git a/src/third_party/wiredtiger/src/include/cursor.i b/src/third_party/wiredtiger/src/include/cursor.i
index 362efea63a9..99354198433 100644
--- a/src/third_party/wiredtiger/src/include/cursor.i
+++ b/src/third_party/wiredtiger/src/include/cursor.i
@@ -173,13 +173,9 @@ __cursor_enter(WT_SESSION_IMPL *session)
static inline void
__cursor_leave(WT_SESSION_IMPL *session)
{
- /*
- * Decrement the count of active cursors in the session. When that goes to zero, there are no
- * active cursors, and we can release any snapshot we're holding for read committed isolation.
- */
+ /* Decrement the count of active cursors in the session. */
WT_ASSERT(session, session->ncursors > 0);
- if (--session->ncursors == 0)
- __wt_txn_read_last(session);
+ --session->ncursors;
}
/*
@@ -189,20 +185,32 @@ __cursor_leave(WT_SESSION_IMPL *session)
static inline int
__cursor_reset(WT_CURSOR_BTREE *cbt)
{
+ WT_CURSOR *cursor;
WT_DECL_RET;
WT_SESSION_IMPL *session;
+ cursor = &cbt->iface;
session = CUR2S(cbt);
+#ifdef HAVE_DIAGNOSTIC
+ __wt_cursor_key_order_reset(cbt); /* Clear key-order checks. */
+#endif
__cursor_pos_clear(cbt);
/* If the cursor was active, deactivate it. */
if (F_ISSET(cbt, WT_CBT_ACTIVE)) {
- if (!F_ISSET(cbt, WT_CBT_NO_TXN))
+ if (!F_ISSET(cbt, WT_CBT_NO_TRACKING))
__cursor_leave(session);
F_CLR(cbt, WT_CBT_ACTIVE);
}
+ /*
+ * When the count of active cursors in the session goes to zero, there are no active cursors,
+ * and we can release any snapshot we're holding for read committed isolation.
+ */
+ if (session->ncursors == 0 && !F_ISSET(cbt, WT_CBT_NO_TXN))
+ __wt_txn_read_last(session);
+
/* If we're not holding a cursor reference, we're done. */
if (cbt->ref == NULL)
return (0);
@@ -223,12 +231,15 @@ __cursor_reset(WT_CURSOR_BTREE *cbt)
cbt->page_deleted_count = 0;
/*
- * Release any page references we're holding. This can trigger eviction (e.g., forced eviction
- * of big pages), so it's important to do after releasing our snapshot above.
- *
- * Clear the reference regardless, so we don't try the release twice.
+ * Release any page references we're holding. This can trigger eviction (for example, forced
+ * eviction of big pages), so it must happen after releasing our snapshot above. Additionally,
+ * there's a debug mode where an application can force the eviction in order to test or stress
+ * the system. Clear the reference so we never try the release twice.
*/
- ret = __wt_page_release(session, cbt->ref, 0);
+ if (F_ISSET(cursor, WT_CURSTD_DEBUG_RESET_EVICT))
+ WT_TRET_BUSY_OK(__wt_page_release_evict(session, cbt->ref, 0));
+ else
+ ret = __wt_page_release(session, cbt->ref, 0);
cbt->ref = NULL;
return (ret);
@@ -377,12 +388,8 @@ __cursor_func_init(WT_CURSOR_BTREE *cbt, bool reenter)
session = CUR2S(cbt);
- if (reenter) {
-#ifdef HAVE_DIAGNOSTIC
- __wt_cursor_key_order_reset(cbt);
-#endif
+ if (reenter)
WT_RET(__cursor_reset(cbt));
- }
/*
* Any old insert position is now invalid. We rely on this being cleared to detect if a new
@@ -395,7 +402,7 @@ __cursor_func_init(WT_CURSOR_BTREE *cbt, bool reenter)
/* Activate the file cursor. */
if (!F_ISSET(cbt, WT_CBT_ACTIVE)) {
- if (!F_ISSET(cbt, WT_CBT_NO_TXN))
+ if (!F_ISSET(cbt, WT_CBT_NO_TRACKING))
WT_RET(__cursor_enter(session));
F_SET(cbt, WT_CBT_ACTIVE);
}
diff --git a/src/third_party/wiredtiger/src/include/extern.h b/src/third_party/wiredtiger/src/include/extern.h
index 4bc55287eef..a8b80658f05 100644
--- a/src/third_party/wiredtiger/src/include/extern.h
+++ b/src/third_party/wiredtiger/src/include/extern.h
@@ -1700,6 +1700,7 @@ extern void __wt_metadata_free_ckptlist(WT_SESSION *session, WT_CKPT *ckptbase)
WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default")));
extern void __wt_modify_vector_free(WT_MODIFY_VECTOR *modifies);
extern void __wt_modify_vector_init(WT_SESSION_IMPL *session, WT_MODIFY_VECTOR *modifies);
+extern void __wt_modify_vector_peek(WT_MODIFY_VECTOR *modifies, WT_UPDATE **updp);
extern void __wt_modify_vector_pop(WT_MODIFY_VECTOR *modifies, WT_UPDATE **updp);
extern void __wt_optrack_flush_buffer(WT_SESSION_IMPL *s);
extern void __wt_optrack_record_funcid(
diff --git a/src/third_party/wiredtiger/src/include/wiredtiger.in b/src/third_party/wiredtiger/src/include/wiredtiger.in
index ec40bc20e70..a3abb6c26af 100644
--- a/src/third_party/wiredtiger/src/include/wiredtiger.in
+++ b/src/third_party/wiredtiger/src/include/wiredtiger.in
@@ -709,22 +709,23 @@ struct __wt_cursor {
#define WT_CURSTD_DEAD 0x000010u
#define WT_CURSTD_DEBUG_COPY_KEY 0x000020u
#define WT_CURSTD_DEBUG_COPY_VALUE 0x000040u
-#define WT_CURSTD_DUMP_HEX 0x000080u
-#define WT_CURSTD_DUMP_JSON 0x000100u
-#define WT_CURSTD_DUMP_PRETTY 0x000200u
-#define WT_CURSTD_DUMP_PRINT 0x000400u
-#define WT_CURSTD_IGNORE_TOMBSTONE 0x000800u
-#define WT_CURSTD_JOINED 0x001000u
-#define WT_CURSTD_KEY_EXT 0x002000u /* Key points out of tree. */
-#define WT_CURSTD_KEY_INT 0x004000u /* Key points into tree. */
-#define WT_CURSTD_META_INUSE 0x008000u
-#define WT_CURSTD_OPEN 0x010000u
-#define WT_CURSTD_OVERWRITE 0x020000u
-#define WT_CURSTD_RAW 0x040000u
-#define WT_CURSTD_RAW_SEARCH 0x080000u
-#define WT_CURSTD_UPDATE_LOCAL 0x100000u
-#define WT_CURSTD_VALUE_EXT 0x200000u /* Value points out of tree. */
-#define WT_CURSTD_VALUE_INT 0x400000u /* Value points into tree. */
+#define WT_CURSTD_DEBUG_RESET_EVICT 0x000080u
+#define WT_CURSTD_DUMP_HEX 0x000100u
+#define WT_CURSTD_DUMP_JSON 0x000200u
+#define WT_CURSTD_DUMP_PRETTY 0x000400u
+#define WT_CURSTD_DUMP_PRINT 0x000800u
+#define WT_CURSTD_IGNORE_TOMBSTONE 0x001000u
+#define WT_CURSTD_JOINED 0x002000u
+#define WT_CURSTD_KEY_EXT 0x004000u /* Key points out of tree. */
+#define WT_CURSTD_KEY_INT 0x008000u /* Key points into tree. */
+#define WT_CURSTD_META_INUSE 0x010000u
+#define WT_CURSTD_OPEN 0x020000u
+#define WT_CURSTD_OVERWRITE 0x040000u
+#define WT_CURSTD_RAW 0x080000u
+#define WT_CURSTD_RAW_SEARCH 0x100000u
+#define WT_CURSTD_UPDATE_LOCAL 0x200000u
+#define WT_CURSTD_VALUE_EXT 0x400000u /* Value points out of tree. */
+#define WT_CURSTD_VALUE_INT 0x800000u /* Value points into tree. */
/* AUTOMATIC FLAG VALUE GENERATION STOP */
#define WT_CURSTD_KEY_SET (WT_CURSTD_KEY_EXT | WT_CURSTD_KEY_INT)
#define WT_CURSTD_VALUE_SET (WT_CURSTD_VALUE_EXT | WT_CURSTD_VALUE_INT)
diff --git a/src/third_party/wiredtiger/src/support/modify.c b/src/third_party/wiredtiger/src/support/modify.c
index e428961dfc3..7c9f2a373c3 100644
--- a/src/third_party/wiredtiger/src/support/modify.c
+++ b/src/third_party/wiredtiger/src/support/modify.c
@@ -505,6 +505,18 @@ __wt_modify_vector_pop(WT_MODIFY_VECTOR *modifies, WT_UPDATE **updp)
}
/*
+ * __wt_modify_vector_peek --
+ * Peek an update pointer off a modify vector.
+ */
+void
+__wt_modify_vector_peek(WT_MODIFY_VECTOR *modifies, WT_UPDATE **updp)
+{
+ WT_ASSERT(modifies->session, modifies->size > 0);
+
+ *updp = modifies->listp[modifies->size - 1];
+}
+
+/*
* __wt_modify_vector_free --
* Free any resources associated with a modify vector. If we exceeded the allowed stack space on
* the vector and had to fallback to dynamic allocations, we'll be doing a free here.
diff --git a/src/third_party/wiredtiger/src/txn/txn.c b/src/third_party/wiredtiger/src/txn/txn.c
index 86aeabb9c29..fe92141aa98 100644
--- a/src/third_party/wiredtiger/src/txn/txn.c
+++ b/src/third_party/wiredtiger/src/txn/txn.c
@@ -765,8 +765,8 @@ __txn_fixup_prepared_update(
* If the history update already has a stop time point and we are committing the prepared update
* there is no work to do.
*/
+ WT_ERR(__wt_upd_alloc_tombstone(session, &hs_upd, NULL));
if (commit) {
- WT_ERR(__wt_upd_alloc_tombstone(session, &hs_upd, NULL));
hs_upd->start_ts = txn->commit_timestamp;
hs_upd->durable_ts = txn->durable_timestamp;
hs_upd->txnid = txn->id;
@@ -784,9 +784,7 @@ __txn_fixup_prepared_update(
hs_upd->next->durable_ts = fix_upd->durable_ts;
hs_upd->next->start_ts = fix_upd->start_ts;
hs_upd->next->txnid = fix_upd->txnid;
- } else
- /* Remove the restored update from history store. */
- WT_ERR(__wt_upd_alloc_tombstone(session, &hs_upd, NULL));
+ }
WT_ERR(__wt_hs_modify(hs_cbt, hs_upd));
diff --git a/src/third_party/wiredtiger/test/csuite/Makefile.am b/src/third_party/wiredtiger/test/csuite/Makefile.am
index 1aa06aa2094..cf58cecc8a6 100644
--- a/src/third_party/wiredtiger/test/csuite/Makefile.am
+++ b/src/third_party/wiredtiger/test/csuite/Makefile.am
@@ -148,6 +148,10 @@ test_wt4891_meta_ckptlist_get_alloc_SOURCES=wt4891_meta_ckptlist_get_alloc/main.
noinst_PROGRAMS += test_wt4891_meta_ckptlist_get_alloc
all_TESTS += test_wt4891_meta_ckptlist_get_alloc
+test_wt6185_modify_ts_SOURCES = wt6185_modify_ts/main.c
+noinst_PROGRAMS += test_wt6185_modify_ts
+all_TESTS += test_wt6185_modify_ts
+
# Run this during a "make check" smoke test.
TESTS = $(all_TESTS)
LOG_COMPILER = env top_builddir=$(top_builddir) top_srcdir=$(top_srcdir) $(TEST_WRAPPER)
diff --git a/src/third_party/wiredtiger/test/csuite/wt6185_modify_ts/main.c b/src/third_party/wiredtiger/test/csuite/wt6185_modify_ts/main.c
new file mode 100644
index 00000000000..fbcf87712e4
--- /dev/null
+++ b/src/third_party/wiredtiger/test/csuite/wt6185_modify_ts/main.c
@@ -0,0 +1,383 @@
+/*-
+ * Public Domain 2014-2020 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.
+ */
+
+#include "test_util.h"
+
+extern int __wt_optind;
+extern char *__wt_optarg;
+
+#define KEYNO 50
+#define MAX_MODIFY_ENTRIES 5
+#define MAX_OPS 25
+#define RUNS 250
+#define VALUE_SIZE 80
+
+static WT_RAND_STATE rnd;
+
+static struct { /* List of repeatable operations. */
+ uint64_t ts;
+ char *v;
+} list[MAX_OPS];
+static u_int lnext;
+
+static char *tlist[MAX_OPS * 100]; /* List of traced operations. */
+static u_int tnext;
+
+static uint64_t ts; /* Current timestamp. */
+
+static char key[100], modify_repl[256], tmp[4 * 1024];
+
+/*
+ * trace --
+ * Trace an operation.
+ */
+#define trace(fmt, ...) \
+ do { \
+ testutil_assert(tnext < WT_ELEMENTS(tlist)); \
+ testutil_check(__wt_snprintf(tmp, sizeof(tmp), fmt, __VA_ARGS__)); \
+ free(tlist[tnext]); \
+ tlist[tnext] = dstrdup(tmp); \
+ ++tnext; \
+ } while (0)
+
+/*
+ * usage --
+ * Print usage message and exit.
+ */
+static void usage(void) WT_GCC_FUNC_DECL_ATTRIBUTE((noreturn));
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-ce] [-h home] [-S seed]\n", progname);
+ exit(EXIT_FAILURE);
+}
+
+/*
+ * cleanup --
+ * Discard allocated memory in case it's a sanitizer run.
+ */
+static void
+cleanup(void)
+{
+ u_int i;
+
+ for (i = 0; i < WT_ELEMENTS(list); ++i)
+ free(list[i].v);
+ for (i = 0; i < WT_ELEMENTS(tlist); ++i)
+ free(tlist[i]);
+}
+
+/*
+ * mmrand --
+ * Return a random value between a min/max pair, inclusive.
+ */
+static inline uint32_t
+mmrand(u_int min, u_int max)
+{
+ uint32_t v;
+ u_int range;
+
+ /*
+ * Test runs with small row counts can easily pass a max of 0 (for example, "g.rows / 20").
+ * Avoid the problem.
+ */
+ if (max <= min)
+ return (min);
+
+ v = __wt_random(&rnd);
+ range = (max - min) + 1;
+ v %= range;
+ v += min;
+ return (v);
+}
+
+/*
+ * modify_repl_init --
+ * Initialize the replacement information.
+ */
+static void
+modify_repl_init(void)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof(modify_repl); ++i)
+ modify_repl[i] = "zyxwvutsrqponmlkjihgfedcba"[i % 26];
+}
+
+/*
+ * modify_build --
+ * Generate a set of modify vectors.
+ */
+static void
+modify_build(WT_MODIFY *entries, int *nentriesp, int tag)
+{
+ int i, nentries;
+
+ /* Randomly select a number of byte changes, offsets and lengths. */
+ nentries = (int)mmrand(1, MAX_MODIFY_ENTRIES);
+ for (i = 0; i < nentries; ++i) {
+ /*
+ * Take between 0 and 10 bytes from a random spot in the modify data. Replace between 0 and
+ * 10 bytes in a random spot in the value, but start at least 11 bytes into the buffer so we
+ * skip leading key information.
+ */
+ entries[i].data.data = modify_repl + mmrand(1, sizeof(modify_repl) - 10);
+ entries[i].data.size = (size_t)mmrand(0, 10);
+ entries[i].offset = (size_t)mmrand(15, VALUE_SIZE);
+ entries[i].size = (size_t)mmrand(0, 10);
+ trace("modify %d: off=%" WT_SIZET_FMT ", size=%" WT_SIZET_FMT ", data=\"%.*s\"", tag,
+ entries[i].offset, entries[i].size, (int)entries[i].data.size,
+ (char *)entries[i].data.data);
+ }
+
+ *nentriesp = (int)nentries;
+}
+
+/*
+ * modify --
+ * Make two modifications to a record inside a single transaction.
+ */
+static void
+modify(WT_SESSION *session, WT_CURSOR *c)
+{
+ WT_MODIFY entries[MAX_MODIFY_ENTRIES];
+ int cnt, loop, nentries;
+ const char *v;
+
+ testutil_check(session->begin_transaction(session, "isolation=snapshot"));
+
+ /* Set a read timestamp 90% of the time. */
+ if (mmrand(1, 10) != 1) {
+ testutil_check(__wt_snprintf(tmp, sizeof(tmp), "read_timestamp=%" PRIx64, ts));
+ testutil_check(session->timestamp_transaction(session, tmp));
+ }
+
+ /* Up to 4 modify operations, 80% chance for each. */
+ for (cnt = loop = 1; loop < 5; ++cnt, ++loop)
+ if (mmrand(1, 10) <= 8) {
+ modify_build(entries, &nentries, cnt);
+ c->set_key(c, key);
+ testutil_check(c->modify(c, entries, nentries));
+ }
+
+ /* Commit 90% of the time, else rollback. */
+ if (mmrand(1, 10) != 1) {
+ c->set_key(c, key);
+ testutil_check(c->search(c));
+ testutil_check(c->get_value(c, &v));
+ free(list[lnext].v);
+ list[lnext].v = dstrdup(v);
+
+ trace("modify read-ts=%" PRIu64 ", commit-ts=%" PRIu64, ts, ts + 1);
+ trace("returned {%s}", v);
+
+ testutil_check(__wt_snprintf(tmp, sizeof(tmp), "commit_timestamp=%" PRIx64, ts + 1));
+ testutil_check(session->timestamp_transaction(session, tmp));
+ testutil_check(session->commit_transaction(session, NULL));
+
+ list[lnext].ts = ts + 1; /* Reread at commit timestamp */
+ ++lnext;
+ } else
+ testutil_check(session->rollback_transaction(session, NULL));
+
+ ++ts;
+}
+
+/*
+ * repeat --
+ * Reread all previously committed modifications.
+ */
+static void
+repeat(WT_SESSION *session, WT_CURSOR *c)
+{
+ u_int i;
+ const char *v;
+
+ for (i = 0; i < lnext; ++i) {
+ testutil_check(session->begin_transaction(session, "isolation=snapshot"));
+ testutil_check(__wt_snprintf(tmp, sizeof(tmp), "read_timestamp=%" PRIx64, list[i].ts));
+ testutil_check(session->timestamp_transaction(session, tmp));
+
+ c->set_key(c, key);
+ testutil_check(c->search(c));
+ testutil_check(c->get_value(c, &v));
+
+ trace("repeat ts=%" PRIu64, list[i].ts);
+ trace("expected {%s}", list[i].v);
+ trace(" found {%s}", v);
+
+ testutil_assert(strcmp(v, list[i].v) == 0);
+
+ testutil_check(session->rollback_transaction(session, NULL));
+ }
+}
+
+/*
+ * reset --
+ * Force eviction of the underlying page.
+ */
+static void
+evict(WT_CURSOR *c)
+{
+ trace("%s", "eviction");
+
+ c->set_key(c, key);
+ testutil_check(c->search(c));
+ F_SET(c, WT_CURSTD_DEBUG_RESET_EVICT);
+ testutil_check(c->reset(c));
+ F_CLR(c, WT_CURSTD_DEBUG_RESET_EVICT);
+}
+
+/*
+ * trace_die --
+ * Dump the trace.
+ */
+static void
+trace_die(void)
+{
+ u_int i;
+
+ fprintf(stderr, "\n");
+ for (i = 0; i < tnext; ++i)
+ fprintf(stderr, "%s\n", tlist[i]);
+}
+
+#define SET_VALUE(key, value) \
+ do { \
+ char *__p; \
+ memset(value, '.', sizeof(value)); \
+ value[sizeof(value) - 1] = '\0'; \
+ testutil_check(__wt_snprintf(value, sizeof(value), "%010u.value", (u_int)key)); \
+ for (__p = value; *__p != '\0'; ++__p) \
+ ; \
+ *__p = '.'; \
+ } while (0)
+
+int
+main(int argc, char *argv[])
+{
+ WT_CONNECTION *conn;
+ WT_CURSOR *c;
+ WT_SESSION *session;
+ u_int i, j;
+ int ch;
+ char path[1024], value[VALUE_SIZE];
+ const char *home, *v;
+ bool no_checkpoint, no_eviction;
+
+ (void)testutil_set_progname(argv);
+ custom_die = trace_die;
+
+ __wt_random_init_seed(NULL, &rnd);
+ modify_repl_init();
+
+ no_checkpoint = no_eviction = false;
+ home = "WT_TEST.wt6185_modify_ts";
+ while ((ch = __wt_getopt(progname, argc, argv, "ceh:S:")) != EOF)
+ switch (ch) {
+ case 'c':
+ no_checkpoint = true;
+ break;
+ case 'e':
+ no_eviction = true;
+ break;
+ case 'h':
+ home = __wt_optarg;
+ break;
+ case 'S':
+ rnd.v = strtoul(__wt_optarg, NULL, 10);
+ break;
+ default:
+ usage();
+ }
+ argc -= __wt_optind;
+ if (argc != 0)
+ usage();
+
+ testutil_work_dir_from_path(path, sizeof(path), home);
+ testutil_make_work_dir(path);
+
+ /* Load 100 records. */
+ testutil_check(wiredtiger_open(path, NULL, "create", &conn));
+ testutil_check(conn->open_session(conn, NULL, NULL, &session));
+ testutil_check(session->create(session, "file:xxx", "key_format=S,value_format=S"));
+ testutil_check(session->open_cursor(session, "file:xxx", NULL, NULL, &c));
+ for (i = 0; i <= 100; ++i) {
+ testutil_check(__wt_snprintf(key, sizeof(key), "%010u.key", i));
+ c->set_key(c, key);
+ SET_VALUE(i, value);
+ c->set_value(c, value);
+ testutil_check(c->insert(c));
+ }
+
+ /* Flush, reopen and verify a record. */
+ testutil_check(conn->close(conn, NULL));
+ testutil_check(wiredtiger_open(path, NULL, NULL, &conn));
+ testutil_check(conn->open_session(conn, NULL, NULL, &session));
+ testutil_check(session->create(session, "file:xxx", NULL));
+ testutil_check(session->open_cursor(session, "file:xxx", NULL, NULL, &c));
+ testutil_check(__wt_snprintf(key, sizeof(key), "%010d.key", KEYNO));
+ c->set_key(c, key);
+ testutil_check(c->search(c));
+ testutil_check(c->get_value(c, &v));
+ SET_VALUE(KEYNO, value);
+ testutil_assert(strcmp(v, value) == 0);
+
+ testutil_check(conn->set_timestamp(conn, "oldest_timestamp=1"));
+
+ /*
+ * Loop doing N operations per loop. Each operation consists of modify operations and re-reading
+ * all previous committed transactions, then optional page evictions and checkpoints.
+ */
+ for (i = 0, ts = 1; i < RUNS; ++i) {
+ lnext = tnext = 0;
+ trace("run %u, seed %" PRIu64, i, rnd.v);
+
+ for (j = mmrand(10, MAX_OPS); j > 0; --j) {
+ modify(session, c);
+ repeat(session, c);
+
+ /* 20% chance we evict the page. */
+ if (!no_eviction && mmrand(1, 10) > 8)
+ evict(c);
+
+ /* 80% chance we checkpoint. */
+ if (!no_checkpoint && mmrand(1, 10) > 8) {
+ trace("%s", "checkpoint");
+ testutil_check(session->checkpoint(session, NULL));
+ }
+ }
+ testutil_assert(write(STDOUT_FILENO, ".", 1) == 1);
+ }
+ testutil_assert(write(STDOUT_FILENO, "\n", 1) == 1);
+
+ testutil_check(conn->close(conn, NULL));
+
+ cleanup();
+ return (EXIT_SUCCESS);
+}
diff --git a/src/third_party/wiredtiger/test/evergreen.yml b/src/third_party/wiredtiger/test/evergreen.yml
index 07f3d98502c..f0354b089c1 100755
--- a/src/third_party/wiredtiger/test/evergreen.yml
+++ b/src/third_party/wiredtiger/test/evergreen.yml
@@ -1167,6 +1167,21 @@ tasks:
${test_env_vars|} $(pwd)/test/csuite/test_wt4891_meta_ckptlist_get_alloc 2>&1
+ - name: csuite-wt6185-modify-ts-test
+ tags: ["pull_request"]
+ depends_on:
+ - name: compile
+ commands:
+ - func: "fetch artifacts"
+ - command: shell.exec
+ params:
+ working_dir: "wiredtiger/build_posix"
+ script: |
+ set -o errexit
+ set -o verbose
+
+ ${test_env_vars|} $(pwd)/test/csuite/test_wt6185_modify_ts 2>&1
+
- name: csuite-rwlock-test
tags: ["pull_request"]
depends_on:
diff --git a/src/third_party/wiredtiger/test/format/Makefile.am b/src/third_party/wiredtiger/test/format/Makefile.am
index 59dd1c8a4d4..8d0c3971494 100644
--- a/src/third_party/wiredtiger/test/format/Makefile.am
+++ b/src/third_party/wiredtiger/test/format/Makefile.am
@@ -4,8 +4,8 @@ AM_CPPFLAGS +=-I$(top_srcdir)/test/utility
noinst_PROGRAMS = t
t_SOURCES =\
- backup.c bulk.c checkpoint.c compact.c config.c config_compat.c hs.c kv.c ops.c random.c \
- rebalance.c salvage.c snap.c t.c trace.c util.c wts.c
+ alter.c backup.c bulk.c checkpoint.c compact.c config.c config_compat.c hs.c kv.c ops.c \
+ random.c rebalance.c salvage.c snap.c t.c trace.c util.c wts.c
t_LDADD = $(top_builddir)/test/utility/libtest_util.la
t_LDADD +=$(top_builddir)/libwiredtiger.la
diff --git a/src/third_party/wiredtiger/test/format/alter.c b/src/third_party/wiredtiger/test/format/alter.c
new file mode 100644
index 00000000000..2b0d432783c
--- /dev/null
+++ b/src/third_party/wiredtiger/test/format/alter.c
@@ -0,0 +1,76 @@
+/*-
+ * Public Domain 2014-2020 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.
+ */
+
+#include "format.h"
+
+/*
+ * alter --
+ * Periodically alter a table's metadata.
+ */
+WT_THREAD_RET
+alter(void *arg)
+{
+ WT_CONNECTION *conn;
+ WT_DECL_RET;
+ WT_SESSION *session;
+ u_int period;
+ char buf[32];
+ bool access_value;
+
+ (void)(arg);
+ conn = g.wts_conn;
+
+ /*
+ * Only alter the access pattern hint. If we alter the cache resident setting we may end up with
+ * a setting that fills cache and doesn't allow it to be evicted.
+ */
+ access_value = false;
+
+ /* Open a session */
+ testutil_check(conn->open_session(conn, NULL, NULL, &session));
+
+ while (!g.workers_finished) {
+ period = mmrand(NULL, 1, 10);
+
+ testutil_check(__wt_snprintf(
+ buf, sizeof(buf), "access_pattern_hint=%s", access_value ? "random" : "none"));
+ access_value = !access_value;
+ /*
+ * Alter can return EBUSY if concurrent with other operations.
+ */
+ while ((ret = session->alter(session, g.uri, buf)) != 0 && ret != EBUSY)
+ testutil_die(ret, "session.alter");
+ while (period > 0 && !g.workers_finished) {
+ --period;
+ __wt_sleep(1, 0);
+ }
+ }
+
+ testutil_check(session->close(session, NULL));
+ return (WT_THREAD_RET_VALUE);
+}
diff --git a/src/third_party/wiredtiger/test/format/bulk.c b/src/third_party/wiredtiger/test/format/bulk.c
index e0694c3c058..02e4cd404bd 100644
--- a/src/third_party/wiredtiger/test/format/bulk.c
+++ b/src/third_party/wiredtiger/test/format/bulk.c
@@ -87,7 +87,7 @@ wts_load(void)
testutil_check(conn->open_session(conn, NULL, NULL, &session));
- tracemsg("%s", "=============== bulk load start");
+ trace_msg("%s", "=============== bulk load start");
/*
* No bulk load with custom collators, the order of insertion will not match the collation
@@ -134,23 +134,21 @@ wts_load(void)
cursor->set_key(cursor, keyno);
cursor->set_value(cursor, *(uint8_t *)value.data);
if (g.trace_all)
- tracemsg(
- "%-10s %" PRIu32 " {0x%02" PRIx8 "}", "bulk", keyno, ((uint8_t *)value.data)[0]);
+ trace_msg("bulk %" PRIu32 " {0x%02" PRIx8 "}", keyno, ((uint8_t *)value.data)[0]);
break;
case VAR:
if (!is_bulk)
cursor->set_key(cursor, keyno);
cursor->set_value(cursor, &value);
if (g.trace_all)
- tracemsg(
- "%-10s %" PRIu32 " {%.*s}", "bulk", keyno, (int)value.size, (char *)value.data);
+ trace_msg("bulk %" PRIu32 " {%.*s}", keyno, (int)value.size, (char *)value.data);
break;
case ROW:
cursor->set_key(cursor, &key);
cursor->set_value(cursor, &value);
if (g.trace_all)
- tracemsg("%-10s %" PRIu32 " {%.*s}, {%.*s}", "bulk", keyno, (int)key.size,
- (char *)key.data, (int)value.size, (char *)value.data);
+ trace_msg("bulk %" PRIu32 " {%.*s}, {%.*s}", keyno, (int)key.size, (char *)key.data,
+ (int)value.size, (char *)value.data);
break;
}
@@ -199,7 +197,7 @@ wts_load(void)
testutil_check(cursor->close(cursor));
- tracemsg("%s", "=============== bulk load stop");
+ trace_msg("%s", "=============== bulk load stop");
testutil_check(session->close(session, NULL));
diff --git a/src/third_party/wiredtiger/test/format/format.h b/src/third_party/wiredtiger/test/format/format.h
index 7f5230709fe..af5e16cc60b 100644
--- a/src/third_party/wiredtiger/test/format/format.h
+++ b/src/third_party/wiredtiger/test/format/format.h
@@ -345,6 +345,8 @@ typedef struct {
uint64_t insert_list[256]; /* column-store inserted records */
u_int insert_list_cnt;
+ WT_ITEM vprint; /* Temporary buffer for printable values */
+
#define TINFO_RUNNING 1 /* Running */
#define TINFO_COMPLETE 2 /* Finished */
#define TINFO_JOINED 3 /* Resolved */
diff --git a/src/third_party/wiredtiger/test/format/format.i b/src/third_party/wiredtiger/test/format/format.i
index 43055bb2809..97e95c97f0c 100644
--- a/src/third_party/wiredtiger/test/format/format.i
+++ b/src/third_party/wiredtiger/test/format/format.i
@@ -231,7 +231,8 @@ lock_writeunlock(WT_SESSION *session, RWLOCK *lock)
testutil_check(pthread_rwlock_unlock(&lock->l.pthread));
}
}
-#define tracemsg(fmt, ...) \
+
+#define trace_msg(fmt, ...) \
do { \
if (g.trace) { \
struct timespec __ts; \
@@ -242,7 +243,7 @@ lock_writeunlock(WT_SESSION *session, RWLOCK *lock)
(uintmax_t)__ts.tv_nsec / WT_THOUSAND, g.tidbuf, __VA_ARGS__)); \
} \
} while (0)
-#define traceop(tinfo, fmt, ...) \
+#define trace_op(tinfo, fmt, ...) \
do { \
if (g.trace) { \
struct timespec __ts; \
@@ -253,3 +254,16 @@ lock_writeunlock(WT_SESSION *session, RWLOCK *lock)
(uintmax_t)__ts.tv_nsec / WT_THOUSAND, tinfo->tidbuf, __VA_ARGS__)); \
} \
} while (0)
+
+/*
+ * trace_bytes --
+ * Return a byte string formatted for display.
+ */
+static inline const char *
+trace_bytes(TINFO *tinfo, const uint8_t *data, size_t size)
+{
+ testutil_check(
+ __wt_raw_to_esc_hex((WT_SESSION_IMPL *)tinfo->session, data, size, &tinfo->vprint));
+ return (tinfo->vprint.mem);
+}
+#define trace_item(tinfo, buf) trace_bytes(tinfo, (buf)->data, (buf)->size)
diff --git a/src/third_party/wiredtiger/test/format/ops.c b/src/third_party/wiredtiger/test/format/ops.c
index 82aa22d5f40..0d4692f0472 100644
--- a/src/third_party/wiredtiger/test/format/ops.c
+++ b/src/third_party/wiredtiger/test/format/ops.c
@@ -154,7 +154,7 @@ operations(u_int ops_seconds, bool lastrun)
}
testutil_check(conn->open_session(conn, NULL, NULL, &session));
- tracemsg("%s", "=============== thread ops start");
+ trace_msg("%s", "=============== thread ops start");
/* Initialize locks to single-thread backups, failures, and timestamp updates. */
lock_init(session, &g.backup_lock);
@@ -277,12 +277,14 @@ operations(u_int ops_seconds, bool lastrun)
lock_destroy(session, &g.backup_lock);
lock_destroy(session, &g.ts_lock);
- tracemsg("%s", "=============== thread ops stop");
+ trace_msg("%s", "=============== thread ops stop");
testutil_check(session->close(session, NULL));
for (i = 0; i < g.c_threads; ++i) {
tinfo = tinfo_list[i];
+ __wt_buf_free(NULL, &tinfo->vprint);
+
/*
* Assert records were not removed unless configured to do so, otherwise subsequent runs can
* incorrectly report scan errors.
@@ -334,7 +336,7 @@ begin_transaction_ts(TINFO *tinfo, u_int *iso_configp)
ret = session->timestamp_transaction(session, buf);
if (ret == 0) {
snap_init(tinfo, ts, true);
- traceop(tinfo, "begin snapshot read-ts=%" PRIu64 " (repeatable)", ts);
+ trace_op(tinfo, "begin snapshot read-ts=%" PRIu64 " (repeatable)", ts);
return;
}
if (ret != EINVAL)
@@ -362,7 +364,7 @@ begin_transaction_ts(TINFO *tinfo, u_int *iso_configp)
lock_writeunlock(session, &g.ts_lock);
snap_init(tinfo, ts, false);
- traceop(tinfo, "begin snapshot read-ts=%" PRIu64 " (not repeatable)", ts);
+ trace_op(tinfo, "begin snapshot read-ts=%" PRIu64 " (not repeatable)", ts);
}
/*
@@ -374,7 +376,7 @@ begin_transaction(TINFO *tinfo, u_int *iso_configp)
{
WT_SESSION *session;
u_int v;
- const char *config, *log;
+ const char *config;
session = tinfo->session;
@@ -383,18 +385,15 @@ begin_transaction(TINFO *tinfo, u_int *iso_configp)
switch (v) {
case 1:
v = ISOLATION_READ_UNCOMMITTED;
- log = "read-uncommitted";
config = "isolation=read-uncommitted";
break;
case 2:
v = ISOLATION_READ_COMMITTED;
- log = "read-committed";
config = "isolation=read-committed";
break;
case 3:
default:
v = ISOLATION_SNAPSHOT;
- log = "snapshot";
config = "isolation=snapshot";
break;
}
@@ -403,7 +402,7 @@ begin_transaction(TINFO *tinfo, u_int *iso_configp)
wiredtiger_begin_transaction(session, config);
snap_init(tinfo, WT_TS_NONE, false);
- traceop(tinfo, "begin %s", log);
+ trace_op(tinfo, "begin %s", config);
}
/*
@@ -442,7 +441,7 @@ commit_transaction(TINFO *tinfo, bool prepared)
/* Remember our oldest commit timestamp. */
tinfo->commit_ts = ts;
- traceop(
+ trace_op(
tinfo, "commit read-ts=%" PRIu64 ", commit-ts=%" PRIu64, tinfo->read_ts, tinfo->commit_ts);
}
@@ -461,7 +460,7 @@ rollback_transaction(TINFO *tinfo)
testutil_check(session->rollback_transaction(session, NULL));
- traceop(tinfo, "abort read-ts=%" PRIu64, tinfo->read_ts);
+ trace_op(tinfo, "abort read-ts=%" PRIu64, tinfo->read_ts);
}
/*
@@ -497,7 +496,7 @@ prepare_transaction(TINFO *tinfo)
testutil_check(__wt_snprintf(buf, sizeof(buf), "prepare_timestamp=%" PRIx64, ts));
ret = session->prepare_transaction(session, buf);
- traceop(tinfo, "prepare ts=%" PRIu64, ts);
+ trace_op(tinfo, "prepare ts=%" PRIu64, ts);
lock_writeunlock(session, &g.ts_lock);
@@ -1130,20 +1129,17 @@ read_row_worker(
switch (g.type) {
case FIX:
if (tinfo == NULL && g.trace_all)
- tracemsg("%-10s%" PRIu64 " {0x%02x}", "read", keyno, ((char *)value->data)[0]);
+ trace_msg("read %" PRIu64 " {0x%02x}", keyno, ((char *)value->data)[0]);
if (tinfo != NULL)
- traceop(
- tinfo, "%-10s%" PRIu64 " {0x%02x}", "read", keyno, ((char *)value->data)[0]);
+ trace_op(tinfo, "read %" PRIu64 " {0x%02x}", keyno, ((char *)value->data)[0]);
break;
case ROW:
case VAR:
if (tinfo == NULL && g.trace_all)
- tracemsg(
- "%-10s%" PRIu64 " {%.*s}", "read", keyno, (int)value->size, (char *)value->data);
+ trace_msg("read %" PRIu64 " {%.*s}", keyno, (int)value->size, (char *)value->data);
if (tinfo != NULL)
- traceop(tinfo, "%-10s%" PRIu64 " {%.*s}", "read", keyno, (int)value->size,
- (char *)value->data);
+ trace_op(tinfo, "read %" PRIu64 " {%s}", keyno, trace_item(tinfo, value));
break;
}
@@ -1279,15 +1275,14 @@ order_error_row:
if (g.trace_all && ret == 0)
switch (g.type) {
case FIX:
- traceop(tinfo, "%-10s%" PRIu64 " {0x%02x}", which, keyno, ((char *)value.data)[0]);
+ trace_op(tinfo, "%s %" PRIu64 " {0x%02x}", which, keyno, ((char *)value.data)[0]);
break;
case ROW:
- traceop(tinfo, "%-10s%" PRIu64 " {%.*s}, {%.*s}", which, keyno, (int)key.size,
- (char *)key.data, (int)value.size, (char *)value.data);
+ trace_op(tinfo, "%s %" PRIu64 " {%.*s}, {%s}", which, keyno, (int)key.size,
+ (char *)key.data, trace_item(tinfo, &value));
break;
case VAR:
- traceop(
- tinfo, "%-10s%" PRIu64 " {%.*s}", which, keyno, (int)value.size, (char *)value.data);
+ trace_op(tinfo, "%s %" PRIu64 " {%s}", which, keyno, trace_item(tinfo, &value));
break;
}
@@ -1311,7 +1306,7 @@ row_reserve(TINFO *tinfo, WT_CURSOR *cursor, bool positioned)
if ((ret = cursor->reserve(cursor)) != 0)
return (ret);
- traceop(tinfo, "%-10s%" PRIu64 " {%.*s}", "reserve", tinfo->keyno, (int)tinfo->key->size,
+ trace_op(tinfo, "reserve %" PRIu64 " {%.*s}", tinfo->keyno, (int)tinfo->key->size,
(char *)tinfo->key->data);
return (0);
@@ -1332,7 +1327,7 @@ col_reserve(TINFO *tinfo, WT_CURSOR *cursor, bool positioned)
if ((ret = cursor->reserve(cursor)) != 0)
return (ret);
- traceop(tinfo, "%-10s%" PRIu64, "reserve", tinfo->keyno);
+ trace_op(tinfo, "reserve %" PRIu64, tinfo->keyno);
return (0);
}
@@ -1383,8 +1378,8 @@ row_modify(TINFO *tinfo, WT_CURSOR *cursor, bool positioned)
testutil_check(cursor->get_value(cursor, tinfo->value));
- traceop(tinfo, "%-10s%" PRIu64 " {%.*s}, {%.*s}", "modify", tinfo->keyno, (int)tinfo->key->size,
- (char *)tinfo->key->data, (int)tinfo->value->size, (char *)tinfo->value->data);
+ trace_op(tinfo, "modify %" PRIu64 " {%.*s}, {%s}", tinfo->keyno, (int)tinfo->key->size,
+ (char *)tinfo->key->data, trace_item(tinfo, tinfo->value));
return (0);
}
@@ -1409,8 +1404,7 @@ col_modify(TINFO *tinfo, WT_CURSOR *cursor, bool positioned)
testutil_check(cursor->get_value(cursor, tinfo->value));
- traceop(tinfo, "%-10s%" PRIu64 ", {%.*s}", "modify", tinfo->keyno, (int)tinfo->value->size,
- (char *)tinfo->value->data);
+ trace_op(tinfo, "modify %" PRIu64 ", {%s}", tinfo->keyno, trace_item(tinfo, tinfo->value));
return (0);
}
@@ -1457,7 +1451,7 @@ row_truncate(TINFO *tinfo, WT_CURSOR *cursor)
if (ret != 0)
return (ret);
- traceop(tinfo, "%-10s%" PRIu64 ", %" PRIu64, "truncate", tinfo->keyno, tinfo->last);
+ trace_op(tinfo, "truncate %" PRIu64 ", %" PRIu64, "truncate", tinfo->keyno, tinfo->last);
return (0);
}
@@ -1499,7 +1493,7 @@ col_truncate(TINFO *tinfo, WT_CURSOR *cursor)
if (ret != 0)
return (ret);
- traceop(tinfo, "%-10s%" PRIu64 "-%" PRIu64, "truncate", tinfo->keyno, tinfo->last);
+ trace_op(tinfo, "truncate %" PRIu64 "-%" PRIu64, tinfo->keyno, tinfo->last);
return (0);
}
@@ -1523,8 +1517,8 @@ row_update(TINFO *tinfo, WT_CURSOR *cursor, bool positioned)
if ((ret = cursor->update(cursor)) != 0)
return (ret);
- traceop(tinfo, "%-10s%" PRIu64 " {%.*s}, {%.*s}", "update", tinfo->keyno, (int)tinfo->key->size,
- (char *)tinfo->key->data, (int)tinfo->value->size, (char *)tinfo->value->data);
+ trace_op(tinfo, "update %" PRIu64 " {%.*s}, {%s}", tinfo->keyno, (int)tinfo->key->size,
+ (char *)tinfo->key->data, trace_item(tinfo, tinfo->value));
return (0);
}
@@ -1550,11 +1544,10 @@ col_update(TINFO *tinfo, WT_CURSOR *cursor, bool positioned)
return (ret);
if (g.type == FIX)
- traceop(tinfo, "%-10s%" PRIu64 " {0x%02" PRIx8 "}", "update", tinfo->keyno,
+ trace_op(tinfo, "update %" PRIu64 " {0x%02" PRIx8 "}", tinfo->keyno,
((uint8_t *)tinfo->value->data)[0]);
else
- traceop(tinfo, "%-10s%" PRIu64 " {%.*s}", "update", tinfo->keyno, (int)tinfo->value->size,
- (char *)tinfo->value->data);
+ trace_op(tinfo, "update %" PRIu64 " {%s}", tinfo->keyno, trace_item(tinfo, tinfo->value));
return (0);
}
@@ -1583,8 +1576,8 @@ row_insert(TINFO *tinfo, WT_CURSOR *cursor, bool positioned)
return (ret);
/* Log the operation */
- traceop(tinfo, "%-10s%" PRIu64 " {%.*s}, {%.*s}", "insert", tinfo->keyno, (int)tinfo->key->size,
- (char *)tinfo->key->data, (int)tinfo->value->size, (char *)tinfo->value->data);
+ trace_op(tinfo, "insert %" PRIu64 " {%.*s}, {%s}", tinfo->keyno, (int)tinfo->key->size,
+ (char *)tinfo->key->data, trace_item(tinfo, tinfo->value));
return (0);
}
@@ -1669,11 +1662,10 @@ col_insert(TINFO *tinfo, WT_CURSOR *cursor)
col_insert_add(tinfo); /* Extend the object. */
if (g.type == FIX)
- traceop(tinfo, "%-10s%" PRIu64 " {0x%02" PRIx8 "}", "insert", tinfo->keyno,
+ trace_op(tinfo, "insert %" PRIu64 " {0x%02" PRIx8 "}", tinfo->keyno,
((uint8_t *)tinfo->value->data)[0]);
else
- traceop(tinfo, "%-10s%" PRIu64 " {%.*s}", "insert", tinfo->keyno, (int)tinfo->value->size,
- (char *)tinfo->value->data);
+ trace_op(tinfo, "insert %" PRIu64 " {%s}", tinfo->keyno, trace_item(tinfo, tinfo->value));
return (0);
}
@@ -1699,7 +1691,7 @@ row_remove(TINFO *tinfo, WT_CURSOR *cursor, bool positioned)
if (ret != 0 && ret != WT_NOTFOUND)
return (ret);
- traceop(tinfo, "%-10s%" PRIu64, "remove", tinfo->keyno);
+ trace_op(tinfo, "remove %" PRIu64, tinfo->keyno);
return (ret);
}
@@ -1723,7 +1715,7 @@ col_remove(TINFO *tinfo, WT_CURSOR *cursor, bool positioned)
if (ret != 0 && ret != WT_NOTFOUND)
return (ret);
- traceop(tinfo, "%-10s%" PRIu64, "remove", tinfo->keyno);
+ trace_op(tinfo, "remove %" PRIu64, tinfo->keyno);
return (ret);
}
diff --git a/src/third_party/wiredtiger/test/format/snap.c b/src/third_party/wiredtiger/test/format/snap.c
index 15c82a649fb..3f82e5b6499 100644
--- a/src/third_party/wiredtiger/test/format/snap.c
+++ b/src/third_party/wiredtiger/test/format/snap.c
@@ -101,22 +101,17 @@ snap_track(TINFO *tinfo, thread_op op)
static void
print_item_data(const char *tag, const uint8_t *data, size_t size)
{
- static const char hex[] = "0123456789abcdef";
- u_char ch;
+ WT_ITEM tmp;
- fprintf(stderr, "%s {", tag);
- if (g.type == FIX)
- fprintf(stderr, "0x%02x", data[0]);
- else
- for (; size > 0; --size, ++data) {
- ch = data[0];
- if (__wt_isprint(ch))
- fprintf(stderr, "%c", (int)ch);
- else
- fprintf(
- stderr, "%x%x", (u_int)hex[(data[0] & 0xf0) >> 4], (u_int)hex[data[0] & 0x0f]);
- }
- fprintf(stderr, "}\n");
+ if (g.type == FIX) {
+ fprintf(stderr, "%s {0x%02x}\n", tag, data[0]);
+ return;
+ }
+
+ memset(&tmp, 0, sizeof(tmp));
+ testutil_check(__wt_raw_to_esc_hex(NULL, data, size, &tmp));
+ fprintf(stderr, "%s {%s}\n", tag, (char *)tmp.mem);
+ __wt_buf_free(NULL, &tmp);
}
/*
@@ -481,8 +476,8 @@ snap_repeat_single(WT_CURSOR *cursor, TINFO *tinfo)
ret = session->timestamp_transaction(session, buf);
if (ret == 0) {
- traceop(tinfo, "%-10s%" PRIu64 " ts=%" PRIu64 " {%.*s}", "repeat", snap->keyno, snap->ts,
- (int)snap->vsize, (char *)snap->vdata);
+ trace_op(tinfo, "repeat %" PRIu64 " ts=%" PRIu64 " {%s}", snap->keyno, snap->ts,
+ trace_bytes(tinfo, snap->vdata, snap->vsize));
/* The only expected error is rollback. */
ret = snap_verify(cursor, tinfo, snap);
diff --git a/src/third_party/wiredtiger/test/format/t.c b/src/third_party/wiredtiger/test/format/t.c
index 65eb53eb2ac..47748d3efd2 100644
--- a/src/third_party/wiredtiger/test/format/t.c
+++ b/src/third_party/wiredtiger/test/format/t.c
@@ -404,7 +404,7 @@ usage(void)
"\t-q run quietly\n"
"\t-R run on an existing database\n"
"\t-T all|local\n"
- "\t-t log operations\n");
+ "\t-t trace operations\n");
config_error();
exit(EXIT_FAILURE);
diff --git a/src/third_party/wiredtiger/test/format/util.c b/src/third_party/wiredtiger/test/format/util.c
index c8be232e1d5..787488c15b7 100644
--- a/src/third_party/wiredtiger/test/format/util.c
+++ b/src/third_party/wiredtiger/test/format/util.c
@@ -230,53 +230,6 @@ timestamp(void *arg)
}
/*
- * alter --
- * Periodically alter a table's metadata.
- */
-WT_THREAD_RET
-alter(void *arg)
-{
- WT_CONNECTION *conn;
- WT_DECL_RET;
- WT_SESSION *session;
- u_int period;
- char buf[32];
- bool access_value;
-
- (void)(arg);
- conn = g.wts_conn;
-
- /*
- * Only alter the access pattern hint. If we alter the cache resident setting we may end up with
- * a setting that fills cache and doesn't allow it to be evicted.
- */
- access_value = false;
-
- /* Open a session */
- testutil_check(conn->open_session(conn, NULL, NULL, &session));
-
- while (!g.workers_finished) {
- period = mmrand(NULL, 1, 10);
-
- testutil_check(__wt_snprintf(
- buf, sizeof(buf), "access_pattern_hint=%s", access_value ? "random" : "none"));
- access_value = !access_value;
- /*
- * Alter can return EBUSY if concurrent with other operations.
- */
- while ((ret = session->alter(session, g.uri, buf)) != 0 && ret != EBUSY)
- testutil_die(ret, "session.alter");
- while (period > 0 && !g.workers_finished) {
- --period;
- __wt_sleep(1, 0);
- }
- }
-
- testutil_check(session->close(session, NULL));
- return (WT_THREAD_RET_VALUE);
-}
-
-/*
* 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 9fc7e9be2f5..cc27ec32213 100644
--- a/src/third_party/wiredtiger/test/format/wts.c
+++ b/src/third_party/wiredtiger/test/format/wts.c
@@ -497,7 +497,7 @@ wts_verify(WT_CONNECTION *conn, const char *tag)
track("verify", 0ULL, NULL);
testutil_check(conn->open_session(conn, NULL, NULL, &session));
- tracemsg("%s", "=============== verify start");
+ trace_msg("%s", "=============== verify start");
/*
* Verify can return EBUSY if the handle isn't available. Don't yield and retry, in the case of
@@ -506,7 +506,7 @@ wts_verify(WT_CONNECTION *conn, const char *tag)
ret = session->verify(session, g.uri, "strict");
testutil_assertfmt(ret == 0 || ret == EBUSY, "session.verify: %s: %s", g.uri, tag);
- tracemsg("%s", "=============== verify stop");
+ trace_msg("%s", "=============== verify stop");
testutil_check(session->close(session, NULL));
}
diff --git a/src/third_party/wiredtiger/test/suite/test_hs08.py b/src/third_party/wiredtiger/test/suite/test_hs08.py
index 905cc84db1a..9899842d529 100644
--- a/src/third_party/wiredtiger/test/suite/test_hs08.py
+++ b/src/third_party/wiredtiger/test/suite/test_hs08.py
@@ -140,7 +140,7 @@ class test_hs08(wttest.WiredTigerTestCase):
# Call checkpoint again.
self.session.checkpoint('use_timestamp=true')
- # Validate that we squashed two modifies. Note that we cant count the exact number
+ # Validate that we squashed two modifies. Note we can't count the exact number
# we squashed, just that we did squash.
hs_writes = self.get_stat(stat.conn.cache_write_hs)
squashed_write = self.get_stat(stat.conn.cache_hs_write_squash)