diff --git a/src/mongo/db/pipeline/document_source_sample_from_random_cursor.cpp b/src/mongo/db/pipeline/document_source_sample_from_random_cursor.cpp index 4d0205d3186..567b72e02e0 100644 --- a/src/mongo/db/pipeline/document_source_sample_from_random_cursor.cpp +++ b/src/mongo/db/pipeline/document_source_sample_from_random_cursor.cpp @@ -120,7 +120,7 @@ DocumentSource::GetNextResult DocumentSourceSampleFromRandomCursor::doGetNext() DocumentSource::GetNextResult DocumentSourceSampleFromRandomCursor::getNextNonDuplicateDocument() { // We may get duplicate documents back from the random cursor, and should not return duplicate // documents, so keep trying until we get a new one. - const int kMaxAttempts = 100; + const int kMaxAttempts = 50; for (int i = 0; i < kMaxAttempts; ++i) { auto nextInput = pSource->getNext(); switch (nextInput.getStatus()) { @@ -139,7 +139,7 @@ DocumentSource::GetNextResult DocumentSourceSampleFromRandomCursor::getNextNonDu return nextInput; } LOGV2_DEBUG(20903, - 1, + 0, "$sample encountered duplicate document: {nextInput_getDocument}", "nextInput_getDocument"_attr = nextInput.getDocument().toString()); break; // Try again with the next document. diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp index a0c70e09a1f..fa9ccf66f3f 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp @@ -473,9 +473,16 @@ public: } bool restore(bool tolerateCappedRepositioning = true) final { + std::stringstream ss; // We can't use the CursorCache since this cursor needs a special config string. WT_SESSION* session = WiredTigerRecoveryUnit::get(_opCtx)->getSession()->getSession(); + + ss << session; + LOGV2_DEBUG(20903, + 0, + "restore session WT_TESTING: {nextInput_getDocument}", + "nextInput_getDocument"_attr = ss.str()); if (!_cursor) { auto status = wtRCToStatus( session->open_cursor(session, _uri.c_str(), nullptr, _config.c_str(), &_cursor), diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp index bdcfb222c29..6190e2a6447 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp @@ -181,8 +181,15 @@ void WiredTigerRecoveryUnit::doAbortUnitOfWork() { } void WiredTigerRecoveryUnit::_ensureSession() { + std::stringstream ss; + if (!_session) { _session = _sessionCache->getSession(); + ss << _session->getSession(); + LOGV2_DEBUG(22903, + 0, + "ensureSession session WT_TESTING: {nextInput_getDocument}", + "nextInput_getDocument"_attr = ss.str()); } } diff --git a/src/mongo/util/version/releases.h.tpl b/src/mongo/util/version/releases.h.tpl index 2d5256111df..8de622a5d0c 100644 --- a/src/mongo/util/version/releases.h.tpl +++ b/src/mongo/util/version/releases.h.tpl @@ -319,3 +319,4 @@ constexpr bool isStandardFCV(FeatureCompatibilityVersion v) { } // namespace mongo::multiversion /* vim: set filetype=cpp: */ + diff --git a/src/third_party/wiredtiger/src/btree/bt_cursor.c b/src/third_party/wiredtiger/src/btree/bt_cursor.c index 4b989bd66d3..08d8aced1af 100644 --- a/src/third_party/wiredtiger/src/btree/bt_cursor.c +++ b/src/third_party/wiredtiger/src/btree/bt_cursor.c @@ -708,7 +708,7 @@ __cursor_reposition_timing_stress(WT_SESSION_IMPL *session) conn = S2C(session); if (FLD_ISSET(conn->timing_stress_flags, WT_TIMING_STRESS_EVICT_REPOSITION) && - __wt_random(&session->rnd) % 10 == 0) + __wt_random2(session, &session->rnd) % 10 == 0) return (true); return (false); diff --git a/src/third_party/wiredtiger/src/btree/bt_random.c b/src/third_party/wiredtiger/src/btree/bt_random.c index 214be58ad13..864d742e75c 100644 --- a/src/third_party/wiredtiger/src/btree/bt_random.c +++ b/src/third_party/wiredtiger/src/btree/bt_random.c @@ -8,6 +8,23 @@ #include "wt_internal.h" +#define WT_MOD(session, r, n) __wt_mod(session, r, n, __FILE__, __LINE__) + +uint64_t +__wt_mod(WT_SESSION_IMPL *session, WT_RAND_STATE *rnd, uint64_t n, const char *file, int linenum) +{ + uint64_t random; + uint64_t result; + + random = __wt_random2(session, rnd); + result = random % n; + WT_RET(__wt_msg(session, + "WT_MOD called from %s:%d: random=%" PRIu64 ", modulus=%" PRIu64 " (0x%" PRIx64 + "), result=%" PRIu64 "\n", + file, linenum, random, n, n, result)); + return (result); +} + /* * __random_insert_valid -- * Check if the inserted key/value pair is valid. @@ -121,7 +138,7 @@ __random_leaf_skip(WT_CURSOR_BTREE *cbt, WT_INSERT_HEAD *ins_head, uint32_t entr * records before our target so we can look around in case our chosen record isn't valid. */ saved_ins = NULL; - i = __wt_random(&session->rnd) % entries; + i = __wt_random2(session, &session->rnd) % entries; for (ins = WT_SKIP_FIRST(ins_head); ins != NULL; ins = WT_SKIP_NEXT(ins)) { if (--i == 0) break; @@ -188,7 +205,7 @@ __random_leaf_insert(WT_CURSOR_BTREE *cbt, bool *validp) * decrease the required number of records required to select from the list. */ if (page->entries > 0) { - start = __wt_random(&session->rnd) % page->entries; + start = __wt_random2(session, &session->rnd) % page->entries; for (slot = start; slot < page->entries; ++slot) { ins_head = WT_ROW_INSERT(page, &page->pg_row[slot]); entries = __random_skip_entries(cbt, ins_head); @@ -243,7 +260,7 @@ __random_leaf_disk(WT_CURSOR_BTREE *cbt, bool *validp) /* This is a relatively cheap test, so try several times. */ for (retry = 0; retry < WT_RANDOM_DISK_RETRY; ++retry) { - slot = __wt_random(&session->rnd) % entries; + slot = __wt_random2(session, &session->rnd) % entries; WT_RET(__wt_row_leaf_key(session, page, page->pg_row + slot, cbt->tmp, false)); WT_RET(__random_slot_valid(cbt, slot, validp)); if (*validp) @@ -253,7 +270,7 @@ __random_leaf_disk(WT_CURSOR_BTREE *cbt, bool *validp) } /* Magic constant: cursor up to 250 next/previous records before selecting a key. */ -#define WT_RANDOM_CURSOR_MOVE 250 +#define WT_RANDOM_CURSOR_MOVE 50 /* Magic constant: 1000 disk-based entries in a page is enough to always select from them. */ #define WT_RANDOM_DISK_ENOUGH WT_THOUSAND @@ -315,7 +332,7 @@ __random_leaf(WT_CURSOR_BTREE *cbt) __cursor_pos_clear(cbt); cbt->slot = 0; next = true; /* Forward from the beginning of the page. */ - for (i = __wt_random(&session->rnd) % WT_RANDOM_CURSOR_MOVE;;) { + for (i = WT_MOD(session, &session->rnd, WT_RANDOM_CURSOR_MOVE);;) { ret = next ? __wt_btcur_next(cbt, false) : __wt_btcur_prev(cbt, false); if (ret == WT_NOTFOUND) { next = !next; /* Reverse direction. */ @@ -339,7 +356,7 @@ __random_leaf(WT_CURSOR_BTREE *cbt) if (WT_DATA_IN_ITEM(cbt->tmp) && cursor->key.size == cbt->tmp->size && memcmp(cursor->key.data, cbt->tmp->data, cbt->tmp->size) == 0) { cbt->tmp->size = 0; - i = __wt_random(&session->rnd) % WT_RANDOM_CURSOR_MOVE; + i = __wt_random2(session, &session->rnd) % WT_RANDOM_CURSOR_MOVE; } else { WT_RET(__wt_buf_set(session, cbt->tmp, cursor->key.data, cursor->key.size)); break; @@ -397,7 +414,7 @@ restart: /* Eviction just wants any random child. */ if (eviction) { - descent = pindex->index[__wt_random(&session->rnd) % entries]; + descent = pindex->index[__wt_random2(session, &session->rnd) % entries]; goto descend; } @@ -412,7 +429,7 @@ restart: */ descent = NULL; for (i = 0; i < entries; ++i) { - descent = pindex->index[__wt_random(&session->rnd) % entries]; + descent = pindex->index[WT_MOD(session, &session->rnd, entries)]; if (descent->state == WT_REF_DISK || descent->state == WT_REF_MEM) break; } diff --git a/src/third_party/wiredtiger/src/include/extern.h b/src/third_party/wiredtiger/src/include/extern.h index 6a8964bfc7e..af7f7b9acf8 100644 --- a/src/third_party/wiredtiger/src/include/extern.h +++ b/src/third_party/wiredtiger/src/include/extern.h @@ -1774,6 +1774,9 @@ extern uint32_t __wt_nlpo2(uint32_t v) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_r extern uint32_t __wt_nlpo2_round(uint32_t v) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)); extern uint32_t __wt_random(WT_RAND_STATE volatile *rnd_state) WT_GCC_FUNC_DECL_ATTRIBUTE( (visibility("default"))) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)); +extern uint32_t __wt_random2(WT_SESSION_IMPL *session, WT_RAND_STATE volatile *rnd_state) + WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default"))) + WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)); extern uint32_t __wt_rduppo2(uint32_t n, uint32_t po2) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)); extern uint32_t __wt_split_page_size(int split_pct, uint32_t maxpagesize, uint32_t allocsize) @@ -1786,6 +1789,8 @@ extern uint64_t __wt_hash_city64(const void *s, size_t len) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)); extern uint64_t __wt_hash_fnv64(const void *string, size_t len) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)); +extern uint64_t __wt_mod(WT_SESSION_IMPL *session, WT_RAND_STATE *rnd, uint64_t n, const char *file, + int linenum) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)); extern uint64_t __wt_session_gen(WT_SESSION_IMPL *session, int which) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)); extern uint64_t __wt_strtouq(const char *nptr, char **endptr, int base) WT_GCC_FUNC_DECL_ATTRIBUTE( diff --git a/src/third_party/wiredtiger/src/session/session_api.c b/src/third_party/wiredtiger/src/session/session_api.c index 28ebb0e24de..cb716615cdb 100644 --- a/src/third_party/wiredtiger/src/session/session_api.c +++ b/src/third_party/wiredtiger/src/session/session_api.c @@ -2521,8 +2521,12 @@ __open_session(WT_CONNECTION_IMPL *conn, WT_EVENT_HANDLER *event_handler, const * problem because sessions are long-lived and will diverge into different parts of the value * space, and what we care about are small values, that is, the low-order bits. */ - if (WT_SESSION_FIRST_USE(session_ret)) + if (WT_SESSION_FIRST_USE(session_ret)) { + WT_RET(__wt_msg(session, "resetting random seed id: %p, %p", session_ret, session_ret->hazard)); __wt_random_init(&session_ret->rnd); + } else { + WT_RET(__wt_msg(session, "using same random seed id: %p %p", session_ret, session_ret->hazard)); + } __wt_event_handler_set( session_ret, event_handler == NULL ? session->event_handler : event_handler); diff --git a/src/third_party/wiredtiger/src/support/rand.c b/src/third_party/wiredtiger/src/support/rand.c index 1c59466ac4b..fa4e683cfa8 100644 --- a/src/third_party/wiredtiger/src/support/rand.c +++ b/src/third_party/wiredtiger/src/support/rand.c @@ -174,3 +174,53 @@ __wt_random(WT_RAND_STATE volatile *rnd_state) WT_GCC_FUNC_ATTRIBUTE((visibility return ((z << 16) + (w & 65535)); #endif } + +/* + * __wt_random -- + * Return a 32-bit pseudo-random number. + */ +uint32_t +__wt_random2(WT_SESSION_IMPL *session, WT_RAND_STATE volatile *rnd_state) + WT_GCC_FUNC_ATTRIBUTE((visibility("default"))) +{ +#ifdef ENABLE_ANTITHESIS + return (uint32_t)(fuzz_get_random()); +#else + WT_RAND_STATE rnd; + uint32_t w, z; + + /* + * Generally, every thread should have their own RNG state, but it's not guaranteed. Take a copy + * of the random state so we can ensure that the calculation operates on the state consistently + * regardless of concurrent calls with the same random state. + */ + WT_ORDERED_READ(rnd, *rnd_state); + w = M_W(rnd); + z = M_Z(rnd); + + /* + * Check if either of the two values goes to 0 (from which we won't recover), and reset it to + * the default initial state. This would never happen with the default seed, but we need this + * for the other cases. + * + * We do this one component at a time, so that if the random number generator was initialized + * from an explicitly provided seed, it would not reset the entire state and then effectively + * result in random number generators from different seeds converging. They would eventually + * converge if both W and Z become 0 at the same time, but this is very unlikely. + * + * This has additional benefits if a caller fails to initialize the state, or initializes with a + * seed that results in a short period. + */ + if (w == 0) + w = DEFAULT_SEED_W; + if (z == 0) + z = DEFAULT_SEED_Z; + + M_W(rnd) = w = 18000 * (w & 65535) + (w >> 16); + M_Z(rnd) = z = 36969 * (z & 65535) + (z >> 16); + *rnd_state = rnd; + + WT_RET(__wt_msg(session, "seed w %u and z %u %p", w, z, session->hazard)); + return ((z << 16) + (w & 65535)); +#endif +}