summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShin Yee Tan <shinyee.tan@mongodb.com>2022-09-14 14:58:16 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-09-14 16:03:35 +0000
commit790dde10c5f653c65b394cf397e96d099e2f5d03 (patch)
treeae728449017756277e1e08ac64787081d257c560 /src
parent60706428cdc4f89864a1c524ebb518f5932a6bd8 (diff)
downloadmongo-790dde10c5f653c65b394cf397e96d099e2f5d03.tar.gz
SERVER-65528 Set bounds when restoring index cursors
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp99
1 files changed, 64 insertions, 35 deletions
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
index 5ef6d9ef85d..8e5df7fdf82 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
@@ -1059,16 +1059,34 @@ public:
invariant(WiredTigerRecoveryUnit::get(_opCtx)->getSession() == _cursor->getSession());
if (!_eof) {
+ // When using search_near, WiredTiger will traverse over deleted keys until it finds its
+ // first non-deleted key. This can make it costly to search for a key that we just
+ // deleted if there are many deleted values (e.g. TTL deletes). We never want to see a
+ // key that comes logically before the last key we returned. Thus, we improve
+ // performance by setting a bound to indicate to WiredTiger to only consider returning
+ // keys that are relevant to us. The cursor bound is by default inclusive of the key
+ // being searched for so search_near is able to return that key if it exists and avoid
+ // looking logically before the last key we returned.
+ WT_CURSOR* c = _cursor->get();
+ const WiredTigerItem searchKey(_key.getBuffer(), _key.getSize());
+ setKey(c, searchKey.Get());
+ if (_forward) {
+ c->bound(c, "bound=lower");
+ } else {
+ c->bound(c, "bound=upper");
+ }
+
// Standard (non-unique) indices *do* include the record id in their KeyStrings. This
// means that restoring to the same key with a new record id will return false, and we
// will *not* skip the key with the new record id.
//
// Unique indexes can have both kinds of KeyStrings, ie with or without the record id.
// Restore for unique indexes gets handled separately in it's own implementation.
- _lastMoveSkippedKey = !seekWTCursor(_key.getValueCopy());
+ _lastMoveSkippedKey = !seekWTCursorInternal(searchKey, /*bounded*/ true);
LOGV2_TRACE_CURSOR(20099,
"restore _lastMoveSkippedKey: {lastMoveSkippedKey}",
"lastMoveSkippedKey"_attr = _lastMoveSkippedKey);
+ c->bound(c, "action=clear");
}
}
@@ -1161,9 +1179,15 @@ protected:
WT_CURSOR* c = _cursor->get();
- int cmp = -1;
const WiredTigerItem searchKey(query.getBuffer(), query.getSize());
setKey(c, searchKey.Get());
+ return seekWTCursorInternal(searchKey, /*bounded*/ false);
+ }
+
+ bool seekWTCursorInternal(const WiredTigerItem searchKey, bool bounded) {
+
+ int cmp = -1;
+ WT_CURSOR* c = _cursor->get();
int ret = wiredTigerPrepareConflictRetry(_opCtx, [&] { return c->search_near(c, &cmp); });
if (ret == WT_NOTFOUND) {
@@ -1192,39 +1216,44 @@ protected:
return true;
}
- // Make sure we land on a matching key (after/before for forward/reverse).
- // If this operation is ignoring prepared updates and search_near() lands on a key that
- // compares lower than the search key (for a forward cursor), calling next() is not
- // guaranteed to return a key that compares greater than the search key. This is because
- // ignoring prepare conflicts does not provide snapshot isolation and the call to next()
- // may land on a newly-committed prepared entry. We must advance our cursor until we find a
- // key that compares greater than the search key. The same principle applies to reverse
- // cursors. See SERVER-56839.
- const bool enforcingPrepareConflicts =
- _opCtx->recoveryUnit()->getPrepareConflictBehavior() ==
- PrepareConflictBehavior::kEnforce;
- WT_ITEM curKey;
- while (_forward ? cmp < 0 : cmp > 0) {
- advanceWTCursor();
- if (_cursorAtEof) {
- break;
- }
-
- if (!kDebugBuild && enforcingPrepareConflicts) {
- break;
- }
-
- getKey(c, &curKey);
- cmp = std::memcmp(curKey.data, searchKey.data, std::min(searchKey.size, curKey.size));
-
- LOGV2_TRACE_CURSOR(5683900, "cmp after advance: {cmp}", "cmp"_attr = cmp);
-
- if (enforcingPrepareConflicts) {
- // If we are enforcing prepare conflicts, calling next() or prev() must always give
- // us a key that compares, respectively, greater than or less than our search key.
- // An exact match is also possible in the case of _id indexes, because the recordid
- // is not a part of the key.
- dassert(_forward ? cmp >= 0 : cmp <= 0);
+ if (bounded) {
+ dassert(_forward ? cmp >= 0 : cmp <= 0);
+ } else {
+ // Make sure we land on a matching key (after/before for forward/reverse).
+ // If this operation is ignoring prepared updates and search_near() lands on a key that
+ // compares lower than the search key (for a forward cursor), calling next() is not
+ // guaranteed to return a key that compares greater than the search key. This is because
+ // ignoring prepare conflicts does not provide snapshot isolation and the call to next()
+ // may land on a newly-committed prepared entry. We must advance our cursor until we
+ // find a key that compares greater than the search key. The same principle applies to
+ // reverse cursors. See SERVER-56839.
+ const bool enforcingPrepareConflicts =
+ _opCtx->recoveryUnit()->getPrepareConflictBehavior() ==
+ PrepareConflictBehavior::kEnforce;
+ WT_ITEM curKey;
+ while (_forward ? cmp < 0 : cmp > 0) {
+ advanceWTCursor();
+ if (_cursorAtEof) {
+ break;
+ }
+
+ if (!kDebugBuild && enforcingPrepareConflicts) {
+ break;
+ }
+
+ getKey(c, &curKey);
+ cmp =
+ std::memcmp(curKey.data, searchKey.data, std::min(searchKey.size, curKey.size));
+
+ LOGV2_TRACE_CURSOR(5683900, "cmp after advance: {cmp}", "cmp"_attr = cmp);
+
+ if (enforcingPrepareConflicts) {
+ // If we are enforcing prepare conflicts, calling next() or prev() must always
+ // give us a key that compares, respectively, greater than or less than our
+ // search key. An exact match is also possible in the case of _id indexes,
+ // because the recordid is not a part of the key.
+ dassert(_forward ? cmp >= 0 : cmp <= 0);
+ }
}
}