diff options
-rw-r--r-- | buildscripts/resmokeconfig/suites/read_only_sharded.yml | 2 | ||||
-rw-r--r-- | jstests/readonly/validate.js | 41 | ||||
-rw-r--r-- | src/mongo/db/catalog/index_catalog_entry_impl.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/commands/validate.cpp | 13 |
4 files changed, 59 insertions, 2 deletions
diff --git a/buildscripts/resmokeconfig/suites/read_only_sharded.yml b/buildscripts/resmokeconfig/suites/read_only_sharded.yml index 26e3c978b3e..eb9e3be0379 100644 --- a/buildscripts/resmokeconfig/suites/read_only_sharded.yml +++ b/buildscripts/resmokeconfig/suites/read_only_sharded.yml @@ -6,6 +6,8 @@ selector: exclude_files: # The test below use applyOps, SERVER-1439. - jstests/readonly/temp_collection.js + exclude_with_any_tags: + - assumes_against_mongod_not_mongos executor: config: diff --git a/jstests/readonly/validate.js b/jstests/readonly/validate.js new file mode 100644 index 00000000000..5819f065953 --- /dev/null +++ b/jstests/readonly/validate.js @@ -0,0 +1,41 @@ +// Tests that running validate in read-only mode doesn't try to fix metadata +// @tags: [assumes_against_mongod_not_mongos] + +load("jstests/readonly/lib/read_only_test.js"); + +// We skip doing the data consistency checks while terminating the cluster because we leave data in +// an inconsitent state on purpose. +TestData.skipCollectionAndIndexValidation = true; + +runReadOnlyTest(function() { + 'use strict'; + return { + name: 'validate', + load: function(writableCollection) { + const db = writableCollection.getDB(); + assert.commandWorked( + db.adminCommand({configureFailPoint: "skipUpdateIndexMultikey", mode: "alwaysOn"})); + assert.commandWorked(writableCollection.createIndex({a: 1, b: 1}, {name: 'idx'})); + assert.commandWorked(writableCollection.insert({_id: 0, a: [0, 1]})); + assert.commandWorked( + db.adminCommand({configureFailPoint: "skipUpdateIndexMultikey", mode: "off"})); + }, + exec: function(readableCollection) { + // Make sure we don't try to adjust multikey indices in read-only mode + const res = readableCollection.validate({full: true}); + assert.eq(1, res.ok, "Expected success of validate on read-only mode"); + assert.eq(false, res.valid); + assert.eq(1, res.errors.length); + + const idx = res.indexDetails.idx; + assert.eq(false, idx.valid); + assert.eq(1, idx.errors.length); + + // Test that validate { repair: true } fails in read-only mode. + assert.commandFailedWithCode( + readableCollection.validate({full: true, repair: true}), + ErrorCodes.InvalidOptions, + "Expected validate to fail because repairing a read-only database is not possible"); + } + }; +}()); diff --git a/src/mongo/db/catalog/index_catalog_entry_impl.cpp b/src/mongo/db/catalog/index_catalog_entry_impl.cpp index 0093b66fb40..94e09994b0c 100644 --- a/src/mongo/db/catalog/index_catalog_entry_impl.cpp +++ b/src/mongo/db/catalog/index_catalog_entry_impl.cpp @@ -57,6 +57,7 @@ #include "mongo/util/scopeguard.h" namespace mongo { +MONGO_FAIL_POINT_DEFINE(skipUpdateIndexMultikey); using std::string; @@ -206,6 +207,10 @@ void IndexCatalogEntryImpl::setMultikey(OperationContext* opCtx, } } + if (MONGO_unlikely(skipUpdateIndexMultikey.shouldFail())) { + return; + } + MultikeyPaths paths = indexTracksMultikeyPathsInCatalog ? multikeyPaths : MultikeyPaths{}; // On a primary, we can simply assign this write the same timestamp as the index creation, diff --git a/src/mongo/db/commands/validate.cpp b/src/mongo/db/commands/validate.cpp index fb494ab74eb..c6724076b9f 100644 --- a/src/mongo/db/commands/validate.cpp +++ b/src/mongo/db/commands/validate.cpp @@ -148,15 +148,20 @@ public: } const bool repair = cmdObj["repair"].trueValue(); + if (storageGlobalParams.readOnly && repair) { + uasserted(ErrorCodes::InvalidOptions, + str::stream() << "Running the validate command with { repair: true } in" + << " read-only mode is not supported."); + } if (background && repair) { uasserted(ErrorCodes::InvalidOptions, - str::stream() << "Running the validate command with both {background: true }" + str::stream() << "Running the validate command with both { background: true }" << " and { repair: true } is not supported."); } if (enforceFastCount && repair) { uasserted(ErrorCodes::InvalidOptions, str::stream() - << "Running the validate command with both {enforceFastCount: true }" + << "Running the validate command with both { enforceFastCount: true }" << " and { repair: true } is not supported."); } repl::ReplicationCoordinator* replCoord = repl::ReplicationCoordinator::get(opCtx); @@ -221,6 +226,10 @@ public: }(); auto repairMode = [&] { + if (storageGlobalParams.readOnly) { + // On read-only mode we can't make any adjustments. + return CollectionValidation::RepairMode::kNone; + } switch (mode) { case CollectionValidation::ValidateMode::kForeground: case CollectionValidation::ValidateMode::kForegroundFull: |