diff options
author | Xiangyu Yao <xiangyu.yao@mongodb.com> | 2019-08-26 21:04:09 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2019-08-26 21:04:09 +0000 |
commit | def30acb316289d5cb95ecdf2654c3ca919c6a46 (patch) | |
tree | 3110ea8550bcdd45cea88cb479912e94c48d45b5 /src | |
parent | fdc2af124b38652be53ff46ad658e86f7dd1f47a (diff) | |
download | mongo-def30acb316289d5cb95ecdf2654c3ca919c6a46.tar.gz |
SERVER-42354 Remove SortedDataInterface::seek() which accepts a SeekPoint
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/exec/distinct_scan.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/exec/index_scan.cpp | 13 | ||||
-rw-r--r-- | src/mongo/db/index/wildcard_access_method.cpp | 101 | ||||
-rw-r--r-- | src/mongo/db/storage/biggie/biggie_sorted_impl.cpp | 54 | ||||
-rw-r--r-- | src/mongo/db/storage/biggie/biggie_sorted_impl.h | 11 | ||||
-rw-r--r-- | src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp | 26 | ||||
-rw-r--r-- | src/mongo/db/storage/index_entry_comparison.cpp | 13 | ||||
-rw-r--r-- | src/mongo/db/storage/index_entry_comparison.h | 16 | ||||
-rw-r--r-- | src/mongo/db/storage/key_string.cpp | 88 | ||||
-rw-r--r-- | src/mongo/db/storage/key_string.h | 8 | ||||
-rw-r--r-- | src/mongo/db/storage/mobile/mobile_index.cpp | 17 | ||||
-rw-r--r-- | src/mongo/db/storage/sorted_data_interface.h | 17 | ||||
-rw-r--r-- | src/mongo/db/storage/sorted_data_interface_test_cursor_advanceto.cpp | 151 | ||||
-rw-r--r-- | src/mongo/db/storage/sorted_data_interface_test_insert.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp | 22 |
15 files changed, 382 insertions, 166 deletions
diff --git a/src/mongo/db/exec/distinct_scan.cpp b/src/mongo/db/exec/distinct_scan.cpp index 22af764672f..3b18a3e6bbd 100644 --- a/src/mongo/db/exec/distinct_scan.cpp +++ b/src/mongo/db/exec/distinct_scan.cpp @@ -79,7 +79,12 @@ PlanStage::StageState DistinctScan::doWork(WorkingSetID* out) { try { if (!_cursor) _cursor = indexAccessMethod()->newCursor(getOpCtx(), _scanDirection == 1); - kv = _cursor->seek(_seekPoint); + kv = _cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + _seekPoint, + indexAccessMethod()->getSortedDataInterface()->getKeyStringVersion(), + indexAccessMethod()->getSortedDataInterface()->getOrdering(), + _scanDirection == 1)); + } catch (const WriteConflictException&) { *out = WorkingSet::INVALID_ID; return PlanStage::NEED_YIELD; diff --git a/src/mongo/db/exec/index_scan.cpp b/src/mongo/db/exec/index_scan.cpp index 7e5c9c19152..4fee1efa50d 100644 --- a/src/mongo/db/exec/index_scan.cpp +++ b/src/mongo/db/exec/index_scan.cpp @@ -114,8 +114,11 @@ boost::optional<IndexKeyEntry> IndexScan::initIndexScan() { if (!_checker->getStartSeekPoint(&_seekPoint)) return boost::none; - - return _indexCursor->seek(_seekPoint); + return _indexCursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + _seekPoint, + indexAccessMethod()->getSortedDataInterface()->getKeyStringVersion(), + indexAccessMethod()->getSortedDataInterface()->getOrdering(), + _forward)); } } } @@ -133,7 +136,11 @@ PlanStage::StageState IndexScan::doWork(WorkingSetID* out) { break; case NEED_SEEK: ++_specificStats.seeks; - kv = _indexCursor->seek(_seekPoint); + kv = _indexCursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + _seekPoint, + indexAccessMethod()->getSortedDataInterface()->getKeyStringVersion(), + indexAccessMethod()->getSortedDataInterface()->getOrdering(), + _forward)); break; case HIT_END: return PlanStage::IS_EOF; diff --git a/src/mongo/db/index/wildcard_access_method.cpp b/src/mongo/db/index/wildcard_access_method.cpp index 8a6a5564e0a..cabf81df2c6 100644 --- a/src/mongo/db/index/wildcard_access_method.cpp +++ b/src/mongo/db/index/wildcard_access_method.cpp @@ -90,51 +90,62 @@ std::set<FieldRef> WildcardAccessMethod::_getMultikeyPathSet( OperationContext* opCtx, const IndexBounds& indexBounds, MultikeyMetadataAccessStats* stats) const { - return writeConflictRetry(opCtx, - "wildcard multikey path retrieval", - _descriptor->parentNS().ns(), - [&]() -> std::set<FieldRef> { - stats->numSeeks = 0; - stats->keysExamined = 0; - auto cursor = newCursor(opCtx); - - constexpr int kForward = 1; - const auto keyPattern = BSON("" << 1 << "" << 1); - IndexBoundsChecker checker(&indexBounds, keyPattern, kForward); - IndexSeekPoint seekPoint; - if (!checker.getStartSeekPoint(&seekPoint)) { - return {}; - } - - std::set<FieldRef> multikeyPaths{}; - auto entry = cursor->seek(seekPoint); - ++stats->numSeeks; - while (entry) { - ++stats->keysExamined; - - switch (checker.checkKey(entry->key, &seekPoint)) { - case IndexBoundsChecker::VALID: - multikeyPaths.emplace( - extractMultikeyPathFromIndexKey(*entry)); - entry = cursor->next(); - break; - - case IndexBoundsChecker::MUST_ADVANCE: - ++stats->numSeeks; - entry = cursor->seek(seekPoint); - break; - - case IndexBoundsChecker::DONE: - entry = boost::none; - break; - - default: - MONGO_UNREACHABLE; - } - } - - return multikeyPaths; - }); + return writeConflictRetry( + opCtx, + "wildcard multikey path retrieval", + _descriptor->parentNS().ns(), + [&]() -> std::set<FieldRef> { + stats->numSeeks = 0; + stats->keysExamined = 0; + auto cursor = newCursor(opCtx); + + constexpr int kForward = 1; + const auto keyPattern = BSON("" << 1 << "" << 1); + IndexBoundsChecker checker(&indexBounds, keyPattern, kForward); + IndexSeekPoint seekPoint; + if (!checker.getStartSeekPoint(&seekPoint)) { + return {}; + } + + std::set<FieldRef> multikeyPaths{}; + auto entry = cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, + getSortedDataInterface()->getKeyStringVersion(), + getSortedDataInterface()->getOrdering(), + kForward)); + + + ++stats->numSeeks; + while (entry) { + ++stats->keysExamined; + + switch (checker.checkKey(entry->key, &seekPoint)) { + case IndexBoundsChecker::VALID: + multikeyPaths.emplace(extractMultikeyPathFromIndexKey(*entry)); + entry = cursor->next(); + break; + + case IndexBoundsChecker::MUST_ADVANCE: + ++stats->numSeeks; + entry = cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, + getSortedDataInterface()->getKeyStringVersion(), + getSortedDataInterface()->getOrdering(), + kForward)); + + break; + + case IndexBoundsChecker::DONE: + entry = boost::none; + break; + + default: + MONGO_UNREACHABLE; + } + } + + return multikeyPaths; + }); } diff --git a/src/mongo/db/storage/biggie/biggie_sorted_impl.cpp b/src/mongo/db/storage/biggie/biggie_sorted_impl.cpp index 7e80c580f4b..eba274f6c62 100644 --- a/src/mongo/db/storage/biggie/biggie_sorted_impl.cpp +++ b/src/mongo/db/storage/biggie/biggie_sorted_impl.cpp @@ -729,12 +729,11 @@ boost::optional<IndexKeyEntry> SortedDataInterface::Cursor::next(RequestedInfo p return keyStringToIndexKeyEntry(_reverseIt->first, _reverseIt->second, _order); } -boost::optional<IndexKeyEntry> SortedDataInterface::Cursor::seekAfterProcessing(BSONObj finalKey, - bool inclusive) { +boost::optional<IndexKeyEntry> SortedDataInterface::Cursor::seekAfterProcessing(BSONObj finalKey) { std::string workingCopyBound; KeyString::Builder ks(KeyString::Version::V1, finalKey, _order); - auto ksEntry = seekAfterProcessing(ks.getValueCopy(), inclusive); + auto ksEntry = seekAfterProcessing(ks.getValueCopy()); const BSONObj bson = KeyString::toBson(ksEntry->keyString.getBuffer(), ksEntry->keyString.getSize(), @@ -744,7 +743,24 @@ boost::optional<IndexKeyEntry> SortedDataInterface::Cursor::seekAfterProcessing( } boost::optional<KeyStringEntry> SortedDataInterface::Cursor::seekAfterProcessing( - const KeyString::Value& keyStringVal, bool inclusive) { + const KeyString::Value& keyStringVal) { + + KeyString::Discriminator discriminator = KeyString::decodeDiscriminator( + keyStringVal.getBuffer(), keyStringVal.getSize(), _order, keyStringVal.getTypeBits()); + + bool inclusive; + switch (discriminator) { + case KeyString::Discriminator::kInclusive: + inclusive = true; + break; + case KeyString::Discriminator::kExclusiveBefore: + inclusive = _forward; + break; + case KeyString::Discriminator::kExclusiveAfter: + inclusive = !_forward; + break; + } + std::string workingCopyBound; // Similar to above, if forward and inclusive or reverse and not inclusive, then use min() for // recordId. Else, we should use max(). @@ -818,23 +834,15 @@ boost::optional<IndexKeyEntry> SortedDataInterface::Cursor::seek(const BSONObj& bool inclusive, RequestedInfo) { BSONObj finalKey = BSONObj::stripFieldNames(key); - KeyString::Builder keyString(KeyString::Version::V1, finalKey, _order); - auto ksValue = seek(keyString.getValueCopy(), inclusive); - if (ksValue) { - BSONObj bson = KeyString::toBson(ksValue->keyString.getBuffer(), - ksValue->keyString.getSize(), - _order, - ksValue->keyString.getTypeBits()); - return IndexKeyEntry(bson, ksValue->loc); - } - return boost::none; + const auto discriminator = _forward == inclusive ? KeyString::Discriminator::kExclusiveBefore + : KeyString::Discriminator::kExclusiveAfter; + KeyString::Builder keyString(KeyString::Version::V1, finalKey, _order, discriminator); + return seek(keyString.getValueCopy()); } -boost::optional<IndexKeyEntry> SortedDataInterface::Cursor::seek(const IndexSeekPoint& seekPoint, +boost::optional<IndexKeyEntry> SortedDataInterface::Cursor::seek(const KeyString::Value& keyString, RequestedInfo parts) { - const BSONObj key = IndexEntryComparison::makeQueryObject(seekPoint, _forward); - KeyString::Builder keyString(KeyString::Version::V1, key, _order); - auto ksValue = seek(keyString.getValueCopy(), true); + boost::optional<KeyStringEntry> ksValue = seekForKeyString(keyString); if (ksValue) { BSONObj bson = KeyString::toBson(ksValue->keyString.getBuffer(), ksValue->keyString.getSize(), @@ -845,11 +853,11 @@ boost::optional<IndexKeyEntry> SortedDataInterface::Cursor::seek(const IndexSeek return boost::none; } -boost::optional<KeyStringEntry> SortedDataInterface::Cursor::seek( - const KeyString::Value& keyStringValue, bool inclusive) { +boost::optional<KeyStringEntry> SortedDataInterface::Cursor::seekForKeyString( + const KeyString::Value& keyStringValue) { _lastMoveWasRestore = false; _atEOF = false; - return seekAfterProcessing(keyStringValue, inclusive); + return seekAfterProcessing(keyStringValue); } boost::optional<IndexKeyEntry> SortedDataInterface::Cursor::seekExact(const BSONObj& key, @@ -862,7 +870,7 @@ boost::optional<IndexKeyEntry> SortedDataInterface::Cursor::seekExact(const BSON ksEntry->keyString.getSize(), _order, ksEntry->keyString.getTypeBits()); - auto kv = seekAfterProcessing(bson, true); + auto kv = seekAfterProcessing(bson); if (kv) { return kv; } @@ -872,7 +880,7 @@ boost::optional<IndexKeyEntry> SortedDataInterface::Cursor::seekExact(const BSON boost::optional<KeyStringEntry> SortedDataInterface::Cursor::seekExact( const KeyString::Value& keyStringValue) { - auto ksEntry = seek(keyStringValue, true); + auto ksEntry = seekForKeyString(keyStringValue); if (!ksEntry) { return {}; } diff --git a/src/mongo/db/storage/biggie/biggie_sorted_impl.h b/src/mongo/db/storage/biggie/biggie_sorted_impl.h index e315602492b..5e208c039e3 100644 --- a/src/mongo/db/storage/biggie/biggie_sorted_impl.h +++ b/src/mongo/db/storage/biggie/biggie_sorted_impl.h @@ -123,10 +123,10 @@ public: virtual boost::optional<IndexKeyEntry> seek(const BSONObj& key, bool inclusive, RequestedInfo parts = kKeyAndLoc) override; - virtual boost::optional<IndexKeyEntry> seek(const IndexSeekPoint& seekPoint, + virtual boost::optional<IndexKeyEntry> seek(const KeyString::Value& keyString, RequestedInfo parts = kKeyAndLoc) override; - virtual boost::optional<KeyStringEntry> seek(const KeyString::Value& keyStringValue, - bool inclusive) override; + virtual boost::optional<KeyStringEntry> seekForKeyString( + const KeyString::Value& keyStringValue) override; virtual boost::optional<IndexKeyEntry> seekExact(const BSONObj& key, RequestedInfo parts = kKeyAndLoc) override; virtual boost::optional<KeyStringEntry> seekExact( @@ -142,9 +142,8 @@ public: // This is a helper function to check if the cursor is valid or not. bool checkCursorValid(); // This is a helper function for seek. - boost::optional<IndexKeyEntry> seekAfterProcessing(BSONObj finalKey, bool inclusive); - boost::optional<KeyStringEntry> seekAfterProcessing(const KeyString::Value& keyString, - bool inclusive); + boost::optional<IndexKeyEntry> seekAfterProcessing(BSONObj finalKey); + boost::optional<KeyStringEntry> seekAfterProcessing(const KeyString::Value& keyString); OperationContext* _opCtx; // This is the "working copy" of the master "branch" in the git analogy. StringStore* _workingCopy; diff --git a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp index 7c64337d5b1..7e5f213a0c9 100644 --- a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp +++ b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp @@ -324,10 +324,11 @@ public: return *_it; } - boost::optional<IndexKeyEntry> seek(const IndexSeekPoint& seekPoint, - RequestedInfo) override { - // Query encodes exclusive case so it can be treated as an inclusive query. - const BSONObj query = IndexEntryComparison::makeQueryObject(seekPoint, _forward); + boost::optional<IndexKeyEntry> seek( + const KeyString::Value& keyString, + RequestedInfo parts = RequestedInfo::kKeyAndLoc) override { + const BSONObj query = KeyString::toBsonSafeWithDiscriminator( + keyString.getBuffer(), keyString.getSize(), _ordering, keyString.getTypeBits()); locate(query, _forward ? RecordId::min() : RecordId::max()); _lastMoveWasRestore = false; if (_isEOF) @@ -336,17 +337,12 @@ public: return *_it; } - boost::optional<KeyStringEntry> seek(const KeyString::Value& keyStringValue, - bool inclusive) override { - const BSONObj query = KeyString::toBson(keyStringValue.getBuffer(), - keyStringValue.getSize(), - _ordering, - keyStringValue.getTypeBits()); - auto kv = seek(query, inclusive, kKeyAndLoc); - if (kv) { - KeyString::Builder ks(KeyString::Version::V1, kv->key, _ordering); - ks.appendRecordId(kv->loc); - return KeyStringEntry(ks.getValueCopy(), kv->loc); + boost::optional<KeyStringEntry> seekForKeyString(const KeyString::Value& keyStringValue) { + auto indexKeyEntry = seek(keyStringValue); + if (indexKeyEntry) { + KeyString::Builder builder(KeyString::Version::V1, indexKeyEntry->key, _ordering); + builder.appendRecordId(indexKeyEntry->loc); + return KeyStringEntry(builder.getValueCopy(), indexKeyEntry->loc); } else { return {}; } diff --git a/src/mongo/db/storage/index_entry_comparison.cpp b/src/mongo/db/storage/index_entry_comparison.cpp index a3d4fcd98d4..14823066fba 100644 --- a/src/mongo/db/storage/index_entry_comparison.cpp +++ b/src/mongo/db/storage/index_entry_comparison.cpp @@ -169,6 +169,19 @@ BSONObj IndexEntryComparison::makeQueryObject(const BSONObj& keyPrefix, return bb.obj(); } +KeyString::Value IndexEntryComparison::makeKeyStringForSeekPoint(const IndexSeekPoint& seekPoint, + KeyString::Version version, + Ordering ord, + bool isForward) { + BSONObj key = IndexEntryComparison::makeQueryObject(seekPoint, isForward); + + const auto discriminator = isForward ? KeyString::Discriminator::kExclusiveBefore + : KeyString::Discriminator::kExclusiveAfter; + + KeyString::Builder builder(version, key, ord, discriminator); + return builder.getValueCopy(); +} + Status buildDupKeyErrorStatus(const BSONObj& key, const NamespaceString& collectionNamespace, const std::string& indexName, diff --git a/src/mongo/db/storage/index_entry_comparison.h b/src/mongo/db/storage/index_entry_comparison.h index 0bed9e79200..35dc1def735 100644 --- a/src/mongo/db/storage/index_entry_comparison.h +++ b/src/mongo/db/storage/index_entry_comparison.h @@ -232,6 +232,22 @@ public: isForward ? 1 : -1); } + /** + * Encodes the SeekPoint into a Keystring object suitable to pass in to compare(). + * + * A KeyString is used for seeking an iterator to a position in a sorted index. The difference + * between a query KeyString and the KeyStrings inserted into indexes is that query KeyString + * can be exclusive. This means that the first matching entry in the index is the first key in + * the index after the query. The meaning of "after" depends on isForward. + * + * Returned KeyString are for use in lookups only and should never be inserted into the + * database. + */ + static KeyString::Value makeKeyStringForSeekPoint(const IndexSeekPoint& seekPoint, + KeyString::Version version, + Ordering ord, + bool isForward); + private: // Ordering is used in comparison() to compare BSONElements const Ordering _order; diff --git a/src/mongo/db/storage/key_string.cpp b/src/mongo/db/storage/key_string.cpp index 92005ed1ab2..2e959cc349f 100644 --- a/src/mongo/db/storage/key_string.cpp +++ b/src/mongo/db/storage/key_string.cpp @@ -2380,6 +2380,94 @@ size_t getKeySize(const char* buffer, size_t len, Ordering ord, const TypeBits& return (len - (remainingBytes - 1)); } +// Unlike toBsonSafe(), this function will convert the discriminator byte back. +// This discriminator byte only exists in KeyStrings for queries, not in KeyStrings stored in an +// index. This function is only used by EphemeralForTest because it uses BSON with discriminator +// rather than KeyString to compare. +BSONObj toBsonSafeWithDiscriminator(const char* buffer, + size_t len, + Ordering ord, + const TypeBits& typeBits) { + boost::optional<std::string> discriminatorBit; + int fieldNo = -1; + + // First pass, get the discriminatorBit if there is any. + { + BSONObjBuilder builder; + BufReader reader(buffer, len); + TypeBits::Reader typeBitsReader(typeBits); + for (int i = 0; reader.remaining(); i++) { + const bool invert = (ord.get(i) == -1); + uint8_t ctype = readType<uint8_t>(&reader, invert); + if (ctype == kLess || ctype == kGreater) { + discriminatorBit = ctype == kLess ? "l" : "r"; + fieldNo = i - 1; + ctype = readType<uint8_t>(&reader, invert); + invariant(ctype == kEnd); + } + + if (ctype == kEnd) { + break; + } + + toBsonValue( + ctype, &reader, &typeBitsReader, invert, typeBits.version, &(builder << ""), 1); + } + // Early return if there is no discriminatorBit. + if (!discriminatorBit) + return builder.obj(); + } + + // Second pass, add discriminatorBit as the fieldName. + { + BSONObjBuilder builder; + BufReader reader(buffer, len); + TypeBits::Reader typeBitsReader(typeBits); + for (int i = 0; reader.remaining(); i++) { + const bool invert = (ord.get(i) == -1); + uint8_t ctype = readType<uint8_t>(&reader, invert); + if (ctype == kLess || ctype == kGreater) { + ctype = readType<uint8_t>(&reader, invert); + invariant(ctype == kEnd); + } + + if (ctype == kEnd) { + break; + } + + auto fn = i == fieldNo ? discriminatorBit.get() : ""; + toBsonValue( + ctype, &reader, &typeBitsReader, invert, typeBits.version, &(builder << fn), 1); + } + return builder.obj(); + } +} + +// This discriminator byte only exists in KeyStrings for queries, not in KeyStrings stored in an +// index. This function is only used by Biggie because it needs to extract the discriminator to do +// the query. +Discriminator decodeDiscriminator(const char* buffer, + size_t len, + Ordering ord, + const TypeBits& typeBits) { + BSONObjBuilder builder; + BufReader reader(buffer, len); + TypeBits::Reader typeBitsReader(typeBits); + for (int i = 0; reader.remaining(); i++) { + const bool invert = (ord.get(i) == -1); + uint8_t ctype = readType<uint8_t>(&reader, invert); + if (ctype == kLess || ctype == kGreater) { + return ctype == kLess ? Discriminator::kExclusiveBefore + : Discriminator::kExclusiveAfter; + } + + if (ctype == kEnd) + break; + toBsonValue(ctype, &reader, &typeBitsReader, invert, typeBits.version, &(builder << ""), 1); + } + return Discriminator::kInclusive; +} + BSONObj toBsonSafe(const char* buffer, size_t len, Ordering ord, const TypeBits& typeBits) { BSONObjBuilder builder; BufReader reader(buffer, len); diff --git a/src/mongo/db/storage/key_string.h b/src/mongo/db/storage/key_string.h index 82410924f67..f82dd4a2259 100644 --- a/src/mongo/db/storage/key_string.h +++ b/src/mongo/db/storage/key_string.h @@ -803,6 +803,14 @@ size_t getKeySize(const char* buffer, size_t len, Ordering ord, const TypeBits& BSONObj toBson(StringData data, Ordering ord, const TypeBits& types); BSONObj toBson(const char* buffer, size_t len, Ordering ord, const TypeBits& types) noexcept; BSONObj toBsonSafe(const char* buffer, size_t len, Ordering ord, const TypeBits& types); +BSONObj toBsonSafeWithDiscriminator(const char* buffer, + size_t len, + Ordering ord, + const TypeBits& typeBits); +Discriminator decodeDiscriminator(const char* buffer, + size_t len, + Ordering ord, + const TypeBits& typeBits); template <class T> BSONObj toBson(const T& keyString, Ordering ord) noexcept { diff --git a/src/mongo/db/storage/mobile/mobile_index.cpp b/src/mongo/db/storage/mobile/mobile_index.cpp index 1b4621d2502..0ed2e365e47 100644 --- a/src/mongo/db/storage/mobile/mobile_index.cpp +++ b/src/mongo/db/storage/mobile/mobile_index.cpp @@ -413,29 +413,24 @@ public: : KeyString::Discriminator::kExclusiveAfter; _startPosition.resetToKey( BSONObj::stripFieldNames(key), _index.getOrdering(), discriminator); - seek(_startPosition.getValueCopy(), inclusive /* unused by implementation */); + seekForKeyString(_startPosition.getValueCopy()); if (_isEOF) { return {}; } return getCurrentEntry(parts); } - boost::optional<IndexKeyEntry> seek(const IndexSeekPoint& seekPoint, + boost::optional<IndexKeyEntry> seek(const KeyString::Value& keyString, RequestedInfo parts) override { - BSONObj startKey = IndexEntryComparison::makeQueryObject(seekPoint, _isForward); - - const auto discriminator = _isForward ? KeyString::Discriminator::kExclusiveBefore - : KeyString::Discriminator::kExclusiveAfter; - _startPosition.resetToKey(startKey, _index.getOrdering(), discriminator); - - seek(_startPosition.getValueCopy(), true /* unused by implementation */); + seekForKeyString(keyString); if (_isEOF) { return {}; } return getCurrentEntry(parts); } - boost::optional<KeyStringEntry> seek(const KeyString::Value& keyStringValue, bool) override { + boost::optional<KeyStringEntry> seekForKeyString( + const KeyString::Value& keyStringValue) override { _startPosition.resetFromBuffer(keyStringValue.getBuffer(), keyStringValue.getSize()); _doSeek(); _updatePosition(); @@ -484,7 +479,7 @@ public: } boost::optional<KeyStringEntry> seekExact(const KeyString::Value& keyStringValue) override { - auto ksEntry = seek(keyStringValue, true); + auto ksEntry = seekForKeyString(keyStringValue); if (!ksEntry) { return {}; } diff --git a/src/mongo/db/storage/sorted_data_interface.h b/src/mongo/db/storage/sorted_data_interface.h index 53c991a8652..004ab479fd6 100644 --- a/src/mongo/db/storage/sorted_data_interface.h +++ b/src/mongo/db/storage/sorted_data_interface.h @@ -283,16 +283,19 @@ public: RequestedInfo parts = kKeyAndLoc) = 0; /** - * Seeks to the position described by seekPoint and returns the current position. - * - * NOTE: most implementations should just pass seekPoint to - * IndexEntryComparison::makeQueryObject(). + * Seeks to the provided keyString and returns the KeyStringEntry. + * The provided keyString has discriminator information encoded. + */ + virtual boost::optional<KeyStringEntry> seekForKeyString( + const KeyString::Value& keyString) = 0; + + /** + * Seeks to the provided keyString and returns the IndexKeyEntry. + * The provided keyString has discriminator information encoded. */ - virtual boost::optional<IndexKeyEntry> seek(const IndexSeekPoint& seekPoint, + virtual boost::optional<IndexKeyEntry> seek(const KeyString::Value& keyString, RequestedInfo parts = kKeyAndLoc) = 0; - virtual boost::optional<KeyStringEntry> seek(const KeyString::Value& keyString, - bool inclusive) = 0; /** * Seeks to a key with a hint to the implementation that you only want exact matches. If * an exact match can't be found, boost::none will be returned and the resulting diff --git a/src/mongo/db/storage/sorted_data_interface_test_cursor_advanceto.cpp b/src/mongo/db/storage/sorted_data_interface_test_cursor_advanceto.cpp index 7b459a9b22b..084242d145b 100644 --- a/src/mongo/db/storage/sorted_data_interface_test_cursor_advanceto.cpp +++ b/src/mongo/db/storage/sorted_data_interface_test_cursor_advanceto.cpp @@ -89,16 +89,24 @@ TEST(SortedDataInterface, AdvanceTo) { seekPoint.keyPrefix = key1; seekPoint.prefixLen = 1; seekPoint.prefixExclusive = false; - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key1, loc1)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + IndexKeyEntry(key1, loc1)); seekPoint.keyPrefix = key2; - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key2, loc4)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + IndexKeyEntry(key2, loc4)); seekPoint.keyPrefix = key3; - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key3, loc5)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + IndexKeyEntry(key3, loc5)); seekPoint.keyPrefix = key4; - ASSERT_EQ(cursor->seek(seekPoint), boost::none); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + boost::none); } } @@ -145,9 +153,10 @@ TEST(SortedDataInterface, AdvanceToReversed) { } { + bool isForward = false; const ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); const std::unique_ptr<SortedDataInterface::Cursor> cursor( - sorted->newCursor(opCtx.get(), false)); + sorted->newCursor(opCtx.get(), isForward)); ASSERT_EQ(cursor->seek(key3, true), IndexKeyEntry(key3, loc5)); @@ -155,16 +164,24 @@ TEST(SortedDataInterface, AdvanceToReversed) { seekPoint.keyPrefix = key3; seekPoint.prefixLen = 1; seekPoint.prefixExclusive = false; - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key3, loc5)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), isForward)), + IndexKeyEntry(key3, loc5)); seekPoint.keyPrefix = key2; - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key2, loc2)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), isForward)), + IndexKeyEntry(key2, loc2)); seekPoint.keyPrefix = key1; - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key1, loc1)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), isForward)), + IndexKeyEntry(key1, loc1)); seekPoint.keyPrefix = key0; - ASSERT_EQ(cursor->seek(seekPoint), boost::none); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), isForward)), + boost::none); } } @@ -208,10 +225,14 @@ TEST(SortedDataInterface, AdvanceToKeyBeforeCursorPosition) { seekPoint.keyPrefix = key0; seekPoint.prefixLen = 1; seekPoint.prefixExclusive = false; - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key1, loc1)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + IndexKeyEntry(key1, loc1)); seekPoint.prefixExclusive = true; - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key1, loc1)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + IndexKeyEntry(key1, loc1)); } } @@ -246,9 +267,10 @@ TEST(SortedDataInterface, AdvanceToKeyAfterCursorPositionReversed) { } { + bool isForward = false; const ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); const std::unique_ptr<SortedDataInterface::Cursor> cursor( - sorted->newCursor(opCtx.get(), false)); + sorted->newCursor(opCtx.get(), isForward)); ASSERT_EQ(cursor->seek(key2, true), IndexKeyEntry(key2, loc2)); @@ -256,10 +278,14 @@ TEST(SortedDataInterface, AdvanceToKeyAfterCursorPositionReversed) { seekPoint.keyPrefix = key3; seekPoint.prefixLen = 1; seekPoint.prefixExclusive = false; - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key2, loc2)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), isForward)), + IndexKeyEntry(key2, loc2)); seekPoint.prefixExclusive = true; - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key2, loc2)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), isForward)), + IndexKeyEntry(key2, loc2)); } } @@ -303,10 +329,14 @@ TEST(SortedDataInterface, AdvanceToKeyAtCursorPosition) { seekPoint.keyPrefix = key1; seekPoint.prefixLen = 1; seekPoint.prefixExclusive = false; - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key1, loc1)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + IndexKeyEntry(key1, loc1)); seekPoint.prefixExclusive = true; - ASSERT_EQ(cursor->seek(seekPoint), boost::none); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + boost::none); } } @@ -341,9 +371,10 @@ TEST(SortedDataInterface, AdvanceToKeyAtCursorPositionReversed) { } { + bool isForward = false; const ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); const std::unique_ptr<SortedDataInterface::Cursor> cursor( - sorted->newCursor(opCtx.get(), false)); + sorted->newCursor(opCtx.get(), isForward)); ASSERT_EQ(cursor->seek(key1, true), IndexKeyEntry(key1, loc1)); @@ -351,10 +382,14 @@ TEST(SortedDataInterface, AdvanceToKeyAtCursorPositionReversed) { seekPoint.keyPrefix = key1; seekPoint.prefixLen = 1; seekPoint.prefixExclusive = false; - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key1, loc1)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), isForward)), + IndexKeyEntry(key1, loc1)); seekPoint.prefixExclusive = true; - ASSERT_EQ(cursor->seek(seekPoint), boost::none); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), isForward)), + boost::none); } } @@ -409,16 +444,24 @@ TEST(SortedDataInterface, AdvanceToExclusive) { seekPoint.keyPrefix = key1; seekPoint.prefixLen = 1; seekPoint.prefixExclusive = true; - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key2, loc4)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + IndexKeyEntry(key2, loc4)); seekPoint.keyPrefix = key2; - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key3, loc5)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + IndexKeyEntry(key3, loc5)); seekPoint.keyPrefix = key3; - ASSERT_EQ(cursor->seek(seekPoint), boost::none); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + boost::none); seekPoint.keyPrefix = key4; - ASSERT_EQ(cursor->seek(seekPoint), boost::none); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + boost::none); } } @@ -464,9 +507,10 @@ TEST(SortedDataInterface, AdvanceToExclusiveReversed) { } { + bool isForward = false; const ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); const std::unique_ptr<SortedDataInterface::Cursor> cursor( - sorted->newCursor(opCtx.get(), false)); + sorted->newCursor(opCtx.get(), isForward)); ASSERT_EQ(cursor->seek(key3, true), IndexKeyEntry(key3, loc5)); @@ -474,16 +518,24 @@ TEST(SortedDataInterface, AdvanceToExclusiveReversed) { seekPoint.keyPrefix = key3; seekPoint.prefixLen = 1; seekPoint.prefixExclusive = true; - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key2, loc2)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), isForward)), + IndexKeyEntry(key2, loc2)); seekPoint.keyPrefix = key2; - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key1, loc1)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), isForward)), + IndexKeyEntry(key1, loc1)); seekPoint.keyPrefix = key1; - ASSERT_EQ(cursor->seek(seekPoint), boost::none); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), isForward)), + boost::none); seekPoint.keyPrefix = key0; - ASSERT_EQ(cursor->seek(seekPoint), boost::none); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), isForward)), + boost::none); } } @@ -534,10 +586,14 @@ TEST(SortedDataInterface, AdvanceToIndirect) { seekPoint.suffixInclusive = {true}; suffix0 = key2.firstElement(); - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key3, loc2)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + IndexKeyEntry(key3, loc2)); suffix0 = key4.firstElement(); - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key5, loc3)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + IndexKeyEntry(key5, loc3)); } } @@ -589,10 +645,14 @@ TEST(SortedDataInterface, AdvanceToIndirectReversed) { seekPoint.suffixInclusive = {true}; suffix0 = key4.firstElement(); - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key3, loc2)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + IndexKeyEntry(key3, loc2)); suffix0 = key2.firstElement(); - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key1, loc1)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + IndexKeyEntry(key1, loc1)); } } @@ -645,15 +705,21 @@ TEST(SortedDataInterface, AdvanceToIndirectExclusive) { seekPoint.suffixInclusive = {false}; suffix0 = key2.firstElement(); - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key3, loc2)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + IndexKeyEntry(key3, loc2)); suffix0 = key4.firstElement(); - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key5, loc3)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + IndexKeyEntry(key5, loc3)); ASSERT_EQ(cursor->seek(key1, true), IndexKeyEntry(key1, loc1)); suffix0 = key3.firstElement(); - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key5, loc3)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), true)), + IndexKeyEntry(key5, loc3)); } } @@ -694,9 +760,10 @@ TEST(SortedDataInterface, AdvanceToIndirectExclusiveReversed) { } { + bool isForward = false; const ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); const std::unique_ptr<SortedDataInterface::Cursor> cursor( - sorted->newCursor(opCtx.get(), false)); + sorted->newCursor(opCtx.get(), isForward)); ASSERT_EQ(cursor->seek(key5, true), IndexKeyEntry(key5, loc3)); @@ -707,15 +774,21 @@ TEST(SortedDataInterface, AdvanceToIndirectExclusiveReversed) { seekPoint.suffixInclusive = {false}; suffix0 = key4.firstElement(); - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key3, loc2)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), isForward)), + IndexKeyEntry(key3, loc2)); suffix0 = key2.firstElement(); - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key1, loc1)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), isForward)), + IndexKeyEntry(key1, loc1)); ASSERT_EQ(cursor->seek(key5, true), IndexKeyEntry(key5, loc3)); suffix0 = key3.firstElement(); - ASSERT_EQ(cursor->seek(seekPoint), IndexKeyEntry(key1, loc1)); + ASSERT_EQ(cursor->seek(IndexEntryComparison::makeKeyStringForSeekPoint( + seekPoint, sorted->getKeyStringVersion(), sorted->getOrdering(), isForward)), + IndexKeyEntry(key1, loc1)); } } diff --git a/src/mongo/db/storage/sorted_data_interface_test_insert.cpp b/src/mongo/db/storage/sorted_data_interface_test_insert.cpp index 49ebc79d238..4eae05ceea6 100644 --- a/src/mongo/db/storage/sorted_data_interface_test_insert.cpp +++ b/src/mongo/db/storage/sorted_data_interface_test_insert.cpp @@ -546,11 +546,11 @@ TEST(SortedDataInterface, InsertAndSeekKeyString) { const std::unique_ptr<SortedDataInterface::Cursor> cursor(sorted->newCursor(opCtx.get())); - auto ksEntry1 = cursor->seek(keyString1WithoutRecordId, true); + auto ksEntry1 = cursor->seekForKeyString(keyString1WithoutRecordId); ASSERT_EQUALS(ksEntry1->keyString.compare(keyString1), 0); ASSERT_EQUALS(ksEntry1->keyString.compare(keyString2), -1); - auto ksEntry2 = cursor->seek(keyString2WithoutRecordId, true); + auto ksEntry2 = cursor->seekForKeyString(keyString2WithoutRecordId); ASSERT_EQUALS(ksEntry2->keyString.compare(keyString2), 0); ASSERT_EQUALS(ksEntry2->keyString.compare(keyString1), 1); } diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp index a0bc61aebcd..a6e0c62d253 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp @@ -44,6 +44,7 @@ #include "mongo/db/json.h" #include "mongo/db/repl/repl_settings.h" #include "mongo/db/service_context.h" +#include "mongo/db/storage/index_entry_comparison.h" #include "mongo/db/storage/storage_options.h" #include "mongo/db/storage/wiredtiger/wiredtiger_customization_hooks.h" #include "mongo/db/storage/wiredtiger/wiredtiger_global_options.h" @@ -830,25 +831,18 @@ public: ? KeyString::Discriminator::kExclusiveBefore : KeyString::Discriminator::kExclusiveAfter; _query.resetToKey(finalKey, _idx.getOrdering(), discriminator); - seek(_query.getValueCopy(), inclusive /* unused by implementation */); + seekForKeyString(_query.getValueCopy()); return curr(parts); } - boost::optional<IndexKeyEntry> seek(const IndexSeekPoint& seekPoint, - RequestedInfo parts) override { - dassert(_opCtx->lockState()->isReadLocked()); - // TODO: don't go to a bson obj then to a KeyString, go straight - BSONObj key = IndexEntryComparison::makeQueryObject(seekPoint, _forward); - - // makeQueryObject handles the discriminator in the real exclusive cases. - const auto discriminator = _forward ? KeyString::Discriminator::kExclusiveBefore - : KeyString::Discriminator::kExclusiveAfter; - _query.resetToKey(key, _idx.getOrdering(), discriminator); - seek(_query.getValueCopy(), true /* unused by implementation */); + boost::optional<IndexKeyEntry> seek(const KeyString::Value& keyString, + RequestedInfo parts = kKeyAndLoc) override { + seekForKeyString(keyString); return curr(parts); } - boost::optional<KeyStringEntry> seek(const KeyString::Value& keyStringValue, bool) override { + boost::optional<KeyStringEntry> seekForKeyString( + const KeyString::Value& keyStringValue) override { dassert(_opCtx->lockState()->isReadLocked()); seekWTCursor(keyStringValue); @@ -899,7 +893,7 @@ public: } boost::optional<KeyStringEntry> seekExact(const KeyString::Value& keyStringValue) override { - auto ksEntry = seek(keyStringValue, true); + auto ksEntry = seekForKeyString(keyStringValue); if (!ksEntry) { return {}; } |