summaryrefslogtreecommitdiff
path: root/src/mongo/db/catalog
diff options
context:
space:
mode:
authorLouis Williams <louis.williams@mongodb.com>2020-02-25 17:49:45 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-03-03 20:22:43 +0000
commit8cdcfd2ab0d28dca863557a02cafc86ae80f960e (patch)
tree61eb159e53415614e0e2a226029d015dc339d0bc /src/mongo/db/catalog
parent5f3625880188f9ca76bacb02c541abc2bd2d0f96 (diff)
downloadmongo-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.cpp61
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{