diff options
author | Louis Williams <louis.williams@mongodb.com> | 2020-02-25 17:49:45 -0500 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-03-03 20:22:43 +0000 |
commit | 8cdcfd2ab0d28dca863557a02cafc86ae80f960e (patch) | |
tree | 61eb159e53415614e0e2a226029d015dc339d0bc /src/mongo/db/catalog | |
parent | 5f3625880188f9ca76bacb02c541abc2bd2d0f96 (diff) | |
download | mongo-8cdcfd2ab0d28dca863557a02cafc86ae80f960e.tar.gz |
SERVER-46410 Validate should check for duplicate keys in unique indexes
Diffstat (limited to 'src/mongo/db/catalog')
-rw-r--r-- | src/mongo/db/catalog/validate_adaptor.cpp | 61 |
1 files changed, 52 insertions, 9 deletions
diff --git a/src/mongo/db/catalog/validate_adaptor.cpp b/src/mongo/db/catalog/validate_adaptor.cpp index ec37e24c913..84183e6dce2 100644 --- a/src/mongo/db/catalog/validate_adaptor.cpp +++ b/src/mongo/db/catalog/validate_adaptor.cpp @@ -139,6 +139,55 @@ Status ValidateAdaptor::validateRecord(OperationContext* opCtx, return status; } +namespace { +// Ensures that index entries are in increasing or decreasing order. +void _validateKeyOrder(OperationContext* opCtx, + const IndexCatalogEntry* index, + const KeyString::Value& currKey, + const KeyString::Value& prevKey, + ValidateResults* results) { + auto descriptor = index->descriptor(); + bool unique = descriptor->unique(); + + // KeyStrings will be in strictly increasing order because all keys are sorted and they are in + // the format (Key, RID), and all RecordIDs are unique. + if (currKey.compare(prevKey) <= 0) { + if (results && results->valid) { + results->errors.push_back(str::stream() + << "index '" << descriptor->indexName() + << "' is not in strictly ascending or descending order"); + } + if (results) { + results->valid = false; + } + return; + } + + if (unique) { + // Unique indexes must not have duplicate keys. + int cmp = currKey.compareWithoutRecordId(prevKey); + if (cmp != 0) { + return; + } + + if (results && results->valid) { + auto bsonKey = KeyString::toBson(currKey, Ordering::make(descriptor->keyPattern())); + auto firstRecordId = + KeyString::decodeRecordIdAtEnd(prevKey.getBuffer(), prevKey.getSize()); + auto secondRecordId = + KeyString::decodeRecordIdAtEnd(currKey.getBuffer(), currKey.getSize()); + results->errors.push_back(str::stream() << "Unique index '" << descriptor->indexName() + << "' has duplicate key: " << bsonKey + << ", first record: " << firstRecordId + << ", second record: " << secondRecordId); + } + if (results) { + results->valid = false; + } + } +} +} // namespace + void ValidateAdaptor::traverseIndex(OperationContext* opCtx, const IndexCatalogEntry* index, int64_t* numTraversedKeys, @@ -173,16 +222,10 @@ void ValidateAdaptor::traverseIndex(OperationContext* opCtx, for (auto indexEntry = indexCursor->seekForKeyString(opCtx, firstKeyString.getValueCopy()); indexEntry; indexEntry = indexCursor->nextKeyString(opCtx)) { - // Ensure that the index entries are in increasing or decreasing order. - if (!isFirstEntry && indexEntry->keyString < prevIndexKeyStringValue) { - if (results && results->valid) { - results->errors.push_back( - "one or more indexes are not in strictly ascending or descending order"); - } - if (results) { - results->valid = false; - } + if (!isFirstEntry) { + _validateKeyOrder( + opCtx, index, indexEntry->keyString, prevIndexKeyStringValue, results); } const RecordId kWildcardMultikeyMetadataRecordId{ |