Skip to content

Commit e1010a6

Browse files
wt-vendoring-bot[bot]MongoDB Bot
authored andcommitted
Import wiredtiger: 7bfbedde948aee7a58f325dac6bb3e4b18d5a871 from branch mongodb-7.0 (#31884)
GitOrigin-RevId: 9365884c2e63715cadda89fcaba9036a069cb161
1 parent 29f8c18 commit e1010a6

File tree

10 files changed

+400
-42
lines changed

10 files changed

+400
-42
lines changed

src/third_party/wiredtiger/dist/s_string.ok

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,6 +1124,7 @@ recurse
11241124
reentrant
11251125
refp
11261126
regionp
1127+
reinstantiated
11271128
relocked
11281129
repl
11291130
repositioned

src/third_party/wiredtiger/import.data

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"vendor": "wiredtiger",
33
"github": "wiredtiger/wiredtiger",
44
"branch": "mongodb-7.0",
5-
"commit": "f49c810f58d706c592a7aa54ae44c3dd0c3f3bb9"
5+
"commit": "7bfbedde948aee7a58f325dac6bb3e4b18d5a871"
66
}

src/third_party/wiredtiger/src/btree/bt_page.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,6 @@ __page_inmem_prepare_update(WT_SESSION_IMPL *session, WT_ITEM *value, WT_CELL_UN
143143
upd->durable_ts = unpack->tw.durable_start_ts;
144144
upd->start_ts = unpack->tw.start_ts;
145145
upd->txnid = unpack->tw.start_txn;
146-
F_SET(upd, WT_UPDATE_PREPARE_RESTORED_FROM_DS);
147146

148147
/*
149148
* Instantiate both update and tombstone if the prepared update is a tombstone. This is required
@@ -169,13 +168,16 @@ __page_inmem_prepare_update(WT_SESSION_IMPL *session, WT_ITEM *value, WT_CELL_UN
169168
unpack->tw.start_txn == unpack->tw.stop_txn) {
170169
upd->durable_ts = WT_TS_NONE;
171170
upd->prepare_state = WT_PREPARE_INPROGRESS;
172-
}
171+
F_SET(upd, WT_UPDATE_PREPARE_RESTORED_FROM_DS);
172+
} else
173+
F_SET(upd, WT_UPDATE_RESTORED_FROM_DS);
173174

174175
tombstone->next = upd;
175176
*updp = tombstone;
176177
} else {
177178
upd->durable_ts = WT_TS_NONE;
178179
upd->prepare_state = WT_PREPARE_INPROGRESS;
180+
F_SET(upd, WT_UPDATE_PREPARE_RESTORED_FROM_DS);
179181
*updp = upd;
180182
}
181183

src/third_party/wiredtiger/src/include/extern.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2525,6 +2525,8 @@ extern int __ut_ovfl_discard_verbose(WT_SESSION_IMPL *session, WT_PAGE *page, WT
25252525
const char *tag) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
25262526
extern int __ut_ovfl_discard_wrapup(WT_SESSION_IMPL *session, WT_PAGE *page)
25272527
WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
2528+
extern int __ut_session_config_int(WT_SESSION_IMPL *session, const char *config)
2529+
WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
25282530
extern void __ut_block_off_srch(WT_EXT **head, wt_off_t off, WT_EXT ***stack, bool skip_off);
25292531
extern void __ut_block_size_srch(WT_SIZE **head, wt_off_t size, WT_SIZE ***stack);
25302532

src/third_party/wiredtiger/src/reconcile/rec_visibility.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,15 @@ static int
7070
__rec_append_orig_value(
7171
WT_SESSION_IMPL *session, WT_PAGE *page, WT_UPDATE *upd, WT_CELL_UNPACK_KV *unpack)
7272
{
73+
WT_CONNECTION_IMPL *conn;
7374
WT_DECL_ITEM(tmp);
7475
WT_DECL_RET;
7576
WT_UPDATE *append, *oldest_upd, *tombstone;
7677
size_t size, total_size;
7778
bool tombstone_globally_visible;
7879

80+
conn = S2C(session);
81+
7982
WT_ASSERT_ALWAYS(session,
8083
upd != NULL && unpack != NULL && unpack->type != WT_CELL_DEL && !unpack->tw.prepare,
8184
"__rec_append_orig_value requires an onpage, non-prepared update");
@@ -105,7 +108,7 @@ __rec_append_orig_value(
105108
* its transaction id to WT_TXN_NONE and its timestamps to WT_TS_NONE when we write the
106109
* update to the time window.
107110
*/
108-
if (F_ISSET(S2C(session), WT_CONN_IN_MEMORY) && unpack->tw.start_ts == upd->start_ts &&
111+
if (F_ISSET(conn, WT_CONN_IN_MEMORY) && unpack->tw.start_ts == upd->start_ts &&
109112
unpack->tw.start_txn == upd->txnid && upd->type != WT_UPDATE_TOMBSTONE)
110113
return (0);
111114

@@ -160,7 +163,15 @@ __rec_append_orig_value(
160163

161164
WT_ERR(__wt_upd_alloc_tombstone(session, &tombstone, &size));
162165
total_size += size;
163-
tombstone->txnid = unpack->tw.stop_txn;
166+
/*
167+
* When reconciling during recovery, we need to clear the transaction id as we haven't
168+
* done so when we read the page into memory to avoid using the transaction id from the
169+
* previous run.
170+
*/
171+
if (F_ISSET(conn, WT_CONN_RECOVERING))
172+
tombstone->txnid = WT_TXN_NONE;
173+
else
174+
tombstone->txnid = unpack->tw.stop_txn;
164175
tombstone->start_ts = unpack->tw.stop_ts;
165176
tombstone->durable_ts = unpack->tw.durable_stop_ts;
166177
F_SET(tombstone, WT_UPDATE_RESTORED_FROM_DS);
@@ -190,7 +201,15 @@ __rec_append_orig_value(
190201
unpack->cell == NULL || __wt_cell_type_raw(unpack->cell) != WT_CELL_VALUE_OVFL_RM);
191202
WT_ERR(__wt_upd_alloc(session, tmp, WT_UPDATE_STANDARD, &append, &size));
192203
total_size += size;
193-
append->txnid = unpack->tw.start_txn;
204+
/*
205+
* When reconciling during recovery, we need to clear the transaction id as we haven't done
206+
* so when we read the page into memory to avoid using the transaction id from the previous
207+
* run.
208+
*/
209+
if (F_ISSET(conn, WT_CONN_RECOVERING))
210+
append->txnid = WT_TXN_NONE;
211+
else
212+
append->txnid = unpack->tw.start_txn;
194213
append->start_ts = unpack->tw.start_ts;
195214
append->durable_ts = unpack->tw.durable_start_ts;
196215
F_SET(append, WT_UPDATE_RESTORED_FROM_DS);
@@ -758,7 +777,8 @@ __rec_fill_tw_from_upd_select(
758777
*/
759778
if (last_upd->next != NULL) {
760779
WT_ASSERT_ALWAYS(session,
761-
last_upd->next->txnid == vpack->tw.start_txn &&
780+
last_upd->next->txnid ==
781+
(F_ISSET(S2C(session), WT_CONN_RECOVERING) ? WT_TXN_NONE : vpack->tw.start_txn) &&
762782
last_upd->next->start_ts == vpack->tw.start_ts &&
763783
last_upd->next->type == WT_UPDATE_STANDARD && last_upd->next->next == NULL,
764784
"Tombstone is globally visible, but the tombstoned update is on the update "

src/third_party/wiredtiger/src/rollback_to_stable/rts_btree.c

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,28 @@ __rts_btree_abort_update(WT_SESSION_IMPL *session, WT_ITEM *key, WT_UPDATE *firs
6868
}
6969
}
7070

71-
/*
72-
* Clear the history store flags for the stable update to indicate that this update should be
73-
* written to the history store later. The next time when this update is moved into the history
74-
* store, it will have a different stop time point.
75-
*/
7671
if (stable_upd != NULL) {
72+
/*
73+
* During recovery, there shouldn't be any updates in the update chain except when the
74+
* updates are from a prepared transaction or from a reinstantiated fast deleted page. Reset
75+
* the transaction ID of the stable update that was restored. Ignore the history store as we
76+
* cannot have a prepared transaction on it and a fast deleted page in the history store
77+
* should never be reinstantiated as it is globally visible.
78+
*/
79+
if (F_ISSET(S2C(session), WT_CONN_RECOVERING) && !WT_IS_HS(session->dhandle)) {
80+
WT_ASSERT(session, first_upd->type == WT_UPDATE_TOMBSTONE);
81+
WT_ASSERT(session,
82+
F_ISSET(
83+
first_upd, WT_UPDATE_PREPARE_RESTORED_FROM_DS | WT_UPDATE_RESTORED_FAST_TRUNCATE));
84+
WT_ASSERT(session, stable_upd->next == NULL);
85+
stable_upd->txnid = WT_TXN_NONE;
86+
}
87+
88+
/*
89+
* Clear the history store flags for the stable update to indicate that this update should
90+
* be written to the history store later. The next time when this update is moved into the
91+
* history store, it will have a different stop time point.
92+
*/
7793
if (F_ISSET(stable_upd, WT_UPDATE_HS | WT_UPDATE_TO_DELETE_FROM_HS)) {
7894
/* Find the update following a stable tombstone. */
7995
if (stable_upd->type == WT_UPDATE_TOMBSTONE) {

src/third_party/wiredtiger/src/session/session_api.c

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -427,48 +427,32 @@ __wt_session_close_internal(WT_SESSION_IMPL *session)
427427
}
428428

429429
/*
430-
* __session_reconfigure --
431-
* WT_SESSION->reconfigure method.
430+
* __session_config_int --
431+
* Configure basic flags and values on the session. Tested via a unit test.
432432
*/
433433
static int
434-
__session_reconfigure(WT_SESSION *wt_session, const char *config)
434+
__session_config_int(WT_SESSION_IMPL *session, const char *config)
435435
{
436436
WT_CONFIG_ITEM cval;
437437
WT_DECL_RET;
438-
WT_SESSION_IMPL *session;
439-
440-
session = (WT_SESSION_IMPL *)wt_session;
441-
SESSION_API_CALL_PREPARE_NOT_ALLOWED(session, reconfigure, config, cfg);
442-
WT_UNUSED(cfg);
443-
444-
WT_ERR(__wt_txn_context_check(session, false));
445438

446-
WT_ERR(__wt_session_reset_cursors(session, false));
447-
448-
/*
449-
* Note that this method only checks keys that are passed in by the application: we don't want
450-
* to reset other session settings to their default values.
451-
*/
452-
WT_ERR(__wt_txn_reconfigure(session, config));
453-
454-
ret = __wt_config_getones(session, config, "ignore_cache_size", &cval);
455-
if (ret == 0) {
439+
if ((ret = __wt_config_getones(session, config, "ignore_cache_size", &cval)) == 0) {
456440
if (cval.val)
457441
F_SET(session, WT_SESSION_IGNORE_CACHE_SIZE);
458442
else
459443
F_CLR(session, WT_SESSION_IGNORE_CACHE_SIZE);
460444
}
461-
WT_ERR_NOTFOUND_OK(ret, false);
445+
WT_RET_NOTFOUND_OK(ret);
462446

463-
ret = __wt_config_getones(session, config, "cache_cursors", &cval);
464-
if (ret == 0) {
447+
if ((ret = __wt_config_getones(session, config, "cache_cursors", &cval)) == 0) {
465448
if (cval.val)
466449
F_SET(session, WT_SESSION_CACHE_CURSORS);
467450
else {
468451
F_CLR(session, WT_SESSION_CACHE_CURSORS);
469-
WT_ERR(__session_close_cached_cursors(session));
452+
WT_RET(__session_close_cached_cursors(session));
470453
}
471454
}
455+
WT_RET_NOTFOUND_OK(ret);
472456

473457
/*
474458
* There is a session debug configuration which can be set to evict pages as they are released
@@ -480,15 +464,41 @@ __session_reconfigure(WT_SESSION *wt_session, const char *config)
480464
else
481465
F_CLR(session, WT_SESSION_DEBUG_RELEASE_EVICT);
482466
}
467+
WT_RET_NOTFOUND_OK(ret);
483468

484-
WT_ERR_NOTFOUND_OK(ret, false);
485-
486-
ret = __wt_config_getones(session, config, "cache_max_wait_ms", &cval);
487-
if (ret == 0 && cval.val)
469+
if ((ret = __wt_config_getones(session, config, "cache_max_wait_ms", &cval)) == 0)
488470
session->cache_max_wait_us = (uint64_t)(cval.val * WT_THOUSAND);
489-
WT_ERR_NOTFOUND_OK(ret, false);
471+
WT_RET_NOTFOUND_OK(ret);
472+
473+
return (0);
474+
}
475+
476+
/*
477+
* __session_reconfigure --
478+
* WT_SESSION->reconfigure method.
479+
*/
480+
static int
481+
__session_reconfigure(WT_SESSION *wt_session, const char *config)
482+
{
483+
WT_DECL_RET;
484+
WT_SESSION_IMPL *session;
485+
486+
session = (WT_SESSION_IMPL *)wt_session;
487+
SESSION_API_CALL_PREPARE_NOT_ALLOWED(session, reconfigure, config, cfg);
488+
WT_UNUSED(cfg);
489+
490+
WT_ERR(__wt_txn_context_check(session, false));
491+
492+
WT_ERR(__wt_session_reset_cursors(session, false));
493+
494+
/*
495+
* Note that this method only checks keys that are passed in by the application: we don't want
496+
* to reset other session settings to their default values.
497+
*/
498+
WT_ERR(__wt_txn_reconfigure(session, config));
499+
500+
WT_ERR(__session_config_int(session, config));
490501

491-
WT_ERR_NOTFOUND_OK(ret, false);
492502
err:
493503
API_END_RET_NOTFOUND_MAP(session, ret);
494504
}
@@ -2688,3 +2698,11 @@ __wt_open_internal_session(WT_CONNECTION_IMPL *conn, const char *name, bool open
26882698
*sessionp = session;
26892699
return (0);
26902700
}
2701+
2702+
#ifdef HAVE_UNITTEST
2703+
int
2704+
__ut_session_config_int(WT_SESSION_IMPL *session, const char *config)
2705+
{
2706+
return (__session_config_int(session, config));
2707+
}
2708+
#endif
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/usr/bin/env python
2+
#
3+
# Public Domain 2014-present MongoDB, Inc.
4+
# Public Domain 2008-2014 WiredTiger, Inc.
5+
#
6+
# This is free and unencumbered software released into the public domain.
7+
#
8+
# Anyone is free to copy, modify, publish, use, compile, sell, or
9+
# distribute this software, either in source code form or as a compiled
10+
# binary, for any purpose, commercial or non-commercial, and by any
11+
# means.
12+
#
13+
# In jurisdictions that recognize copyright laws, the author or authors
14+
# of this software dedicate any and all copyright interest in the
15+
# software to the public domain. We make this dedication for the benefit
16+
# of the public at large and to the detriment of our heirs and
17+
# successors. We intend this dedication to be an overt act of
18+
# relinquishment in perpetuity of all present and future rights to this
19+
# software under copyright law.
20+
#
21+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24+
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25+
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26+
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27+
# OTHER DEALINGS IN THE SOFTWARE.
28+
29+
import wttest
30+
from helper import simulate_crash_restart
31+
from wtscenario import make_scenarios
32+
33+
# test_prepare29.py
34+
# Test that updates preceding an unstable prepared tombstone are restored with the correct
35+
# transaction IDs.
36+
class test_prepare29(wttest.WiredTigerTestCase):
37+
38+
format_values = [
39+
('column', dict(key_format='r', key=1, value_format='S')),
40+
('column-fix', dict(key_format='r', key=1, value_format='8t')),
41+
('string-row', dict(key_format='S', key=str(1), value_format='S')),
42+
]
43+
44+
scenarios = make_scenarios(format_values)
45+
46+
def evict_cursor(self, uri, key):
47+
session_evict = self.conn.open_session("debug=(release_evict_page=true)")
48+
session_evict.begin_transaction("ignore_prepare=true")
49+
cursor = session_evict.open_cursor(uri, None, None)
50+
cursor.set_key(key)
51+
cursor.search()
52+
cursor.reset()
53+
cursor.close()
54+
session_evict.rollback_transaction()
55+
56+
def test_prepare29(self):
57+
uri = 'table:test_prepare29'
58+
create_params = 'key_format={},value_format={}'.format(self.key_format, self.value_format)
59+
self.session.create(uri, create_params)
60+
61+
if self.value_format == '8t':
62+
value1 = 97
63+
else:
64+
value1 = 'a' * 5
65+
66+
# Pin oldest timestamp.
67+
self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(1))
68+
69+
# Insert some data.
70+
ts = 100
71+
cursor = self.session.open_cursor(uri)
72+
key = self.key
73+
self.session.begin_transaction()
74+
cursor[key] = value1
75+
self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(ts))
76+
77+
# Update stable timestamp and checkpoint.
78+
ts = 200
79+
self.conn.set_timestamp('stable_timestamp=' + self.timestamp_str(ts))
80+
self.session.checkpoint()
81+
82+
# Remove the previously inserted key in a prepared transaction.
83+
ts = 300
84+
self.session.begin_transaction()
85+
cursor.set_key(key)
86+
cursor.remove()
87+
self.session.prepare_transaction('prepare_timestamp=' + self.timestamp_str(ts))
88+
cursor.reset()
89+
cursor.close()
90+
91+
# Evict the key.
92+
self.evict_cursor(uri, key)
93+
session = self.conn.open_session("")
94+
session.checkpoint()
95+
96+
# Perform an unclean shutdown. The last remove operation is unstable and unresolved.
97+
simulate_crash_restart(self, '.', 'RESTART')
98+
99+
# Try to perform an operation in a transaction that is after the stable timestamp.
100+
# We should get a WT_ROLLBACK error due to the write conflict if we don't properly
101+
# reset the txn ID.
102+
cursor = self.session.open_cursor(uri)
103+
self.session.begin_transaction()
104+
cursor.set_key(key)
105+
cursor.remove()
106+
107+
self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(201))

0 commit comments

Comments
 (0)