summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Wlodarek <gregory.wlodarek@mongodb.com>2023-02-03 14:16:03 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2023-02-10 22:27:11 +0000
commiteeebf8387291cf2c0e92ab092e3db4882042b50b (patch)
treed6e7e57b13f90bcfd535eb5265e30de4583e0ba6
parentbefb5b1bf6b71bd168f73467d1c3d7c66d737ed2 (diff)
downloadmongo-eeebf8387291cf2c0e92ab092e3db4882042b50b.tar.gz
SERVER-73481 Ensure validate detects out-of-order keys with {full: false}
(cherry picked from commit 288fee69456c966751a49870eefead1b7fa6ae76)
-rw-r--r--jstests/noPassthrough/validate_out_of_order.js37
-rw-r--r--src/mongo/db/catalog/validate_adaptor.cpp8
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp11
3 files changed, 47 insertions, 9 deletions
diff --git a/jstests/noPassthrough/validate_out_of_order.js b/jstests/noPassthrough/validate_out_of_order.js
new file mode 100644
index 00000000000..27142a71c5f
--- /dev/null
+++ b/jstests/noPassthrough/validate_out_of_order.js
@@ -0,0 +1,37 @@
+/**
+ * Tests that out-of-order keys are detected by validation during both the collection and index scan
+ * phases.
+ */
+(function() {
+"use strict";
+
+const rst = new ReplSetTest({nodes: 1});
+rst.startSet();
+rst.initiate();
+
+let primary = rst.getPrimary();
+let coll = primary.getCollection('test.out_of_order');
+assert.commandWorked(coll.createIndex({x: 1}));
+
+for (let i = 0; i < 5; i++) {
+ assert.commandWorked(coll.insert({x: i}));
+}
+
+// Test record store out-of-order detection.
+assert.commandWorked(
+ primary.adminCommand({configureFailPoint: "WTRecordStoreUassertOutOfOrder", mode: "alwaysOn"}));
+let res = assert.commandWorked(coll.validate());
+assert(!res.valid);
+assert.commandWorked(
+ primary.adminCommand({configureFailPoint: "WTRecordStoreUassertOutOfOrder", mode: "off"}));
+
+// Test index entry out-of-order detection.
+assert.commandWorked(
+ primary.adminCommand({configureFailPoint: "failIndexKeyOrdering", mode: "alwaysOn"}));
+res = assert.commandWorked(coll.validate());
+assert(!res.valid);
+assert.commandWorked(
+ primary.adminCommand({configureFailPoint: "failIndexKeyOrdering", mode: "off"}));
+
+rst.stopSet();
+})();
diff --git a/src/mongo/db/catalog/validate_adaptor.cpp b/src/mongo/db/catalog/validate_adaptor.cpp
index b6cf1a5fa9c..f83aa7512ba 100644
--- a/src/mongo/db/catalog/validate_adaptor.cpp
+++ b/src/mongo/db/catalog/validate_adaptor.cpp
@@ -63,6 +63,7 @@ namespace mongo {
namespace {
MONGO_FAIL_POINT_DEFINE(crashOnMultikeyValidateFailure);
+MONGO_FAIL_POINT_DEFINE(failIndexKeyOrdering);
// Set limit for size of corrupted records that will be reported.
const long long kMaxErrorSizeBytes = 1 * 1024 * 1024;
@@ -288,7 +289,7 @@ void _validateKeyOrder(OperationContext* opCtx,
// 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 (currKey.compare(prevKey) <= 0 || MONGO_unlikely(failIndexKeyOrdering.shouldFail())) {
if (results && results->valid) {
results->errors.push_back(str::stream()
<< "index '" << descriptor->indexName()
@@ -570,11 +571,6 @@ void ValidateAdaptor::traverseRecordStore(OperationContext* opCtx,
size_t validatedSize = 0;
Status status = validateRecord(opCtx, record->id, record->data, &validatedSize, results);
- // RecordStores are required to return records in RecordId order.
- if (prevRecordId.isValid()) {
- invariant(prevRecordId < record->id);
- }
-
// validatedSize = dataSize is not a general requirement as some storage engines may use
// padding, but we still require that they return the unpadded record data.
if (!status.isOK() || validatedSize != static_cast<size_t>(dataSize)) {
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp
index 6c6d7ad19f7..0ce8fa2eb47 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp
@@ -134,6 +134,7 @@ std::size_t computeRecordIdSize(const RecordId& id) {
} // namespace
MONGO_FAIL_POINT_DEFINE(WTCompactRecordStoreEBUSY);
+MONGO_FAIL_POINT_DEFINE(WTRecordStoreUassertOutOfOrder);
MONGO_FAIL_POINT_DEFINE(WTWriteConflictException);
MONGO_FAIL_POINT_DEFINE(WTWriteConflictExceptionForReads);
MONGO_FAIL_POINT_DEFINE(slowOplogSamplingReads);
@@ -2208,9 +2209,13 @@ boost::optional<Record> WiredTigerRecordStoreCursorBase::next() {
return {};
}
- if (_forward && _lastReturnedId >= id) {
- // Crash when testing diagnostics are enabled.
- invariant(!TestingProctor::instance().isEnabled(), "next was not greater than last");
+ if ((_forward && _lastReturnedId >= id) ||
+ MONGO_unlikely(WTRecordStoreUassertOutOfOrder.shouldFail())) {
+ if (!WTRecordStoreUassertOutOfOrder.shouldFail()) {
+ // Crash when testing diagnostics are enabled and not explicitly uasserting on
+ // out-of-order keys.
+ invariant(!TestingProctor::instance().isEnabled(), "cursor returned out-of-order keys");
+ }
// uassert with 'DataCorruptionDetected' after logging.
LOGV2_ERROR_OPTIONS(22406,