diff options
author | Judah Schvimer <judah@mongodb.com> | 2017-11-09 10:37:47 -0500 |
---|---|---|
committer | Judah Schvimer <judah@mongodb.com> | 2017-11-09 10:37:47 -0500 |
commit | 54a3f40dcfbff57f46859ba0b88249e6008597ea (patch) | |
tree | 73621af61ad9b3c217f1c3b8399c8d9d2cb8caea /src/mongo | |
parent | 271879b7a67c9d9b36778692f2a77e04c6403a1f (diff) | |
download | mongo-54a3f40dcfbff57f46859ba0b88249e6008597ea.tar.gz |
SERVER-31805 Set local collection validation options correctly in rollbackViaRefetchNoUUID
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/repl/SConscript | 3 | ||||
-rw-r--r-- | src/mongo/db/repl/rollback_test_fixture.cpp | 163 | ||||
-rw-r--r-- | src/mongo/db/repl/rollback_test_fixture.h | 79 | ||||
-rw-r--r-- | src/mongo/db/repl/rs_rollback_no_uuid.cpp | 21 | ||||
-rw-r--r-- | src/mongo/db/repl/rs_rollback_no_uuid_test.cpp | 181 | ||||
-rw-r--r-- | src/mongo/db/repl/rs_rollback_test.cpp | 191 |
6 files changed, 330 insertions, 308 deletions
diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript index 363fe9334a4..f456284ecf9 100644 --- a/src/mongo/db/repl/SConscript +++ b/src/mongo/db/repl/SConscript @@ -538,6 +538,7 @@ env.Library( 'rollback_test_fixture.cpp', ], LIBDEPS=[ + 'oplog_interface_mock', 'optime', 'replication_process', 'replmocks', @@ -556,7 +557,6 @@ env.CppUnitTest( ], LIBDEPS=[ 'oplog_interface_local', - 'oplog_interface_mock', 'rollback_test_fixture', 'rs_rollback', ], @@ -569,7 +569,6 @@ env.CppUnitTest( ], LIBDEPS=[ 'oplog_interface_local', - 'oplog_interface_mock', 'rollback_test_fixture', 'rs_rollback_no_uuid', ], diff --git a/src/mongo/db/repl/rollback_test_fixture.cpp b/src/mongo/db/repl/rollback_test_fixture.cpp index 7208953e6b5..83e2ed8687a 100644 --- a/src/mongo/db/repl/rollback_test_fixture.cpp +++ b/src/mongo/db/repl/rollback_test_fixture.cpp @@ -32,13 +32,18 @@ #include <string> +#include "mongo/db/catalog/collection_catalog_entry.h" +#include "mongo/db/catalog/database_holder.h" #include "mongo/db/client.h" +#include "mongo/db/db_raii.h" #include "mongo/db/repl/oplog.h" #include "mongo/db/repl/replication_consistency_markers_mock.h" #include "mongo/db/repl/replication_coordinator.h" #include "mongo/db/repl/replication_coordinator_mock.h" #include "mongo/db/repl/replication_process.h" #include "mongo/db/repl/replication_recovery_mock.h" +#include "mongo/db/repl/rs_rollback.h" +#include "mongo/db/repl/rs_rollback_no_uuid.h" #include "mongo/db/session_catalog.h" #include "mongo/logger/log_component.h" #include "mongo/logger/logger.h" @@ -132,5 +137,163 @@ Status RollbackTest::ReplicationCoordinatorRollbackMock::setFollowerMode( return ReplicationCoordinatorMock::setFollowerMode(newState); } +std::pair<BSONObj, RecordId> RollbackTest::makeCommandOp( + Timestamp ts, OptionalCollectionUUID uuid, StringData nss, BSONObj cmdObj, int recordId) { + + BSONObjBuilder bob; + bob.append("ts", ts); + bob.append("h", 1LL); + bob.append("op", "c"); + if (uuid) { // Not all ops have UUID fields. + uuid.get().appendToBuilder(&bob, "ui"); + } + bob.append("ns", nss); + bob.append("o", cmdObj); + + return std::make_pair(bob.obj(), RecordId(recordId)); +} + +Collection* RollbackTest::_createCollection(OperationContext* opCtx, + const NamespaceString& nss, + const CollectionOptions& options) { + Lock::DBLock dbLock(opCtx, nss.db(), MODE_X); + mongo::WriteUnitOfWork wuow(opCtx); + auto db = dbHolder().openDb(opCtx, nss.db()); + ASSERT_TRUE(db); + db->dropCollection(opCtx, nss.ns()).transitional_ignore(); + auto coll = db->createCollection(opCtx, nss.ns(), options); + ASSERT_TRUE(coll); + wuow.commit(); + return coll; +} + +Collection* RollbackTest::_createCollection(OperationContext* opCtx, + const std::string& nss, + const CollectionOptions& options) { + return _createCollection(opCtx, NamespaceString(nss), options); +} + +RollbackSourceMock::RollbackSourceMock(std::unique_ptr<OplogInterface> oplog) + : _oplog(std::move(oplog)) {} + +const OplogInterface& RollbackSourceMock::getOplog() const { + return *_oplog; +} + +const HostAndPort& RollbackSourceMock::getSource() const { + return _source; +} + +int RollbackSourceMock::getRollbackId() const { + return 0; +} + +BSONObj RollbackSourceMock::getLastOperation() const { + auto iter = _oplog->makeIterator(); + auto result = iter->next(); + ASSERT_OK(result.getStatus()); + return result.getValue().first; +} + +BSONObj RollbackSourceMock::findOne(const NamespaceString& nss, const BSONObj& filter) const { + return BSONObj(); +} + +std::pair<BSONObj, NamespaceString> RollbackSourceMock::findOneByUUID(const std::string& db, + UUID uuid, + const BSONObj& filter) const { + return {BSONObj(), NamespaceString()}; +} + +void RollbackSourceMock::copyCollectionFromRemote(OperationContext* opCtx, + const NamespaceString& nss) const {} + +StatusWith<BSONObj> RollbackSourceMock::getCollectionInfo(const NamespaceString& nss) const { + return BSON("name" << nss.ns() << "options" << BSONObj()); +} + +StatusWith<BSONObj> RollbackSourceMock::getCollectionInfoByUUID(const std::string& db, + const UUID& uuid) const { + return BSON("options" << BSONObj() << "info" << BSON("uuid" << uuid)); +} + +RollbackResyncsCollectionOptionsTest::RollbackSourceWithCollectionOptions:: + RollbackSourceWithCollectionOptions(std::unique_ptr<OplogInterface> oplog, + BSONObj collOptionsObj) + : RollbackSourceMock(std::move(oplog)), collOptionsObj(collOptionsObj) {} + + +StatusWith<BSONObj> +RollbackResyncsCollectionOptionsTest::RollbackSourceWithCollectionOptions::getCollectionInfo( + const NamespaceString& nss) const { + calledNoUUID = true; + return BSON("options" << collOptionsObj); +} + +StatusWith<BSONObj> +RollbackResyncsCollectionOptionsTest::RollbackSourceWithCollectionOptions::getCollectionInfoByUUID( + const std::string& db, const UUID& uuid) const { + calledWithUUID = true; + return BSON("options" << collOptionsObj << "info" << BSON("uuid" << uuid)); +} + +void RollbackResyncsCollectionOptionsTest::resyncCollectionOptionsTest( + CollectionOptions localCollOptions, BSONObj remoteCollOptionsObj) { + createOplog(_opCtx.get()); + + auto dbName = "test"; + auto collName = "coll"; + auto nss = NamespaceString(dbName, collName); + + auto coll = _createCollection(_opCtx.get(), nss.toString(), localCollOptions); + auto commonOperation = + std::make_pair(BSON("ts" << Timestamp(Seconds(1), 0) << "h" << 1LL), RecordId(1)); + + // 'collMod' operation used to trigger metadata re-sync. + BSONObj collModCmd = BSON("collMod" << collName << "noPadding" << false); + auto collectionModificationOperation = + makeCommandOp(Timestamp(Seconds(2), 0), coll->uuid(), nss.toString(), collModCmd, 2); + + RollbackSourceWithCollectionOptions rollbackSource( + std::unique_ptr<OplogInterface>(new OplogInterfaceMock({commonOperation})), + remoteCollOptionsObj); + + if (coll->uuid()) { + ASSERT_OK( + syncRollback(_opCtx.get(), + OplogInterfaceMock({collectionModificationOperation, commonOperation}), + rollbackSource, + {}, + _coordinator, + _replicationProcess.get())); + + ASSERT_TRUE(rollbackSource.calledWithUUID); + ASSERT_FALSE(rollbackSource.calledNoUUID); + } else { + ASSERT_OK(syncRollbackNoUUID( + _opCtx.get(), + OplogInterfaceMock({collectionModificationOperation, commonOperation}), + rollbackSource, + {}, + _coordinator, + _replicationProcess.get())); + + ASSERT_TRUE(rollbackSource.calledNoUUID); + ASSERT_FALSE(rollbackSource.calledWithUUID); + } + + // Make sure the collection options are correct. + AutoGetCollectionForReadCommand autoColl(_opCtx.get(), NamespaceString(nss.toString())); + auto collAfterRollbackOptions = + autoColl.getCollection()->getCatalogEntry()->getCollectionOptions(_opCtx.get()); + + BSONObjBuilder expectedOptionsBob; + if (localCollOptions.uuid) { + localCollOptions.uuid.get().appendToBuilder(&expectedOptionsBob, "uuid"); + } + expectedOptionsBob.appendElements(remoteCollOptionsObj); + + ASSERT_BSONOBJ_EQ(expectedOptionsBob.obj(), collAfterRollbackOptions.toBSON()); +} } // namespace repl } // namespace mongo diff --git a/src/mongo/db/repl/rollback_test_fixture.h b/src/mongo/db/repl/rollback_test_fixture.h index 0f86cf4d97c..c24ba1bcffa 100644 --- a/src/mongo/db/repl/rollback_test_fixture.h +++ b/src/mongo/db/repl/rollback_test_fixture.h @@ -29,8 +29,11 @@ #pragma once #include "mongo/db/repl/drop_pending_collection_reaper.h" +#include "mongo/db/repl/oplog_interface.h" +#include "mongo/db/repl/oplog_interface_mock.h" #include "mongo/db/repl/replication_coordinator_mock.h" #include "mongo/db/repl/replication_process.h" +#include "mongo/db/repl/rollback_source.h" #include "mongo/db/repl/storage_interface_impl.h" #include "mongo/db/service_context.h" #include "mongo/db/service_context_d_test_fixture.h" @@ -63,6 +66,22 @@ public: */ void tearDown() override; + /** + * Creates a collection with the given namespace and options. + */ + static Collection* _createCollection(OperationContext* opCtx, + const NamespaceString& nss, + const CollectionOptions& options); + static Collection* _createCollection(OperationContext* opCtx, + const std::string& nss, + const CollectionOptions& options); + + /** + * Creates an oplog entry with a recordId for a command operation. + */ + static std::pair<BSONObj, RecordId> makeCommandOp( + Timestamp ts, OptionalCollectionUUID uuid, StringData nss, BSONObj cmdObj, int recordId); + protected: // Test fixture used to manage the service context and global storage engine. ServiceContextMongoDTest _serviceContextMongoDTest; @@ -118,5 +137,65 @@ private: ErrorCodes::Error _failSetFollowerModeWithThisCode = ErrorCodes::InternalError; }; +class RollbackSourceMock : public RollbackSource { +public: + RollbackSourceMock(std::unique_ptr<OplogInterface> oplog); + int getRollbackId() const override; + const OplogInterface& getOplog() const override; + const HostAndPort& getSource() const override; + BSONObj getLastOperation() const override; + BSONObj findOne(const NamespaceString& nss, const BSONObj& filter) const override; + + std::pair<BSONObj, NamespaceString> findOneByUUID(const std::string& db, + UUID uuid, + const BSONObj& filter) const override; + + void copyCollectionFromRemote(OperationContext* opCtx, + const NamespaceString& nss) const override; + StatusWith<BSONObj> getCollectionInfoByUUID(const std::string& db, + const UUID& uuid) const override; + StatusWith<BSONObj> getCollectionInfo(const NamespaceString& nss) const override; + +private: + std::unique_ptr<OplogInterface> _oplog; + HostAndPort _source; +}; + +/** + * Test fixture to ensure that rollback re-syncs collection options from a sync source and updates + * the local collection options correctly. A test operates on a single test collection, and is + * parameterized on two arguments: + * + * 'localCollOptions': the collection options that the local test collection is initially created + * with. + * + * 'remoteCollOptionsObj': the collection options object that the sync source will respond with to + * the rollback node when it fetches collection metadata. + * + * A collMod operation with a 'noPadding' argument is used to trigger a collection metadata resync, + * since the rollback of collMod operations does not take into account the actual command object. It + * simply re-syncs all the collection options. + */ +class RollbackResyncsCollectionOptionsTest : public RollbackTest { + + class RollbackSourceWithCollectionOptions : public RollbackSourceMock { + public: + RollbackSourceWithCollectionOptions(std::unique_ptr<OplogInterface> oplog, + BSONObj collOptionsObj); + + StatusWith<BSONObj> getCollectionInfo(const NamespaceString& nss) const override; + StatusWith<BSONObj> getCollectionInfoByUUID(const std::string& db, + const UUID& uuid) const override; + + mutable bool calledNoUUID = false; + mutable bool calledWithUUID = false; + BSONObj collOptionsObj; + }; + +public: + void resyncCollectionOptionsTest(CollectionOptions localCollOptions, + BSONObj remoteCollOptionsObj); +}; + } // namespace repl } // namespace mongo diff --git a/src/mongo/db/repl/rs_rollback_no_uuid.cpp b/src/mongo/db/repl/rs_rollback_no_uuid.cpp index b1a633abf7e..088c28a2e7b 100644 --- a/src/mongo/db/repl/rs_rollback_no_uuid.cpp +++ b/src/mongo/db/repl/rs_rollback_no_uuid.cpp @@ -557,22 +557,11 @@ void syncFixUp(OperationContext* opCtx, cce->updateFlags(opCtx, options.flags); } - auto status = collection->setValidator(opCtx, options.validator); - if (!status.isOK()) { - throw RSFatalException(str::stream() << "Failed to set validator: " - << status.toString()); - } - status = collection->setValidationAction(opCtx, options.validationAction); - if (!status.isOK()) { - throw RSFatalException(str::stream() << "Failed to set validationAction: " - << status.toString()); - } - - status = collection->setValidationLevel(opCtx, options.validationLevel); - if (!status.isOK()) { - throw RSFatalException(str::stream() << "Failed to set validationLevel: " - << status.toString()); - } + // Set any document validation options. We update the validator fields without + // parsing/validation, since we fetched the options object directly from the sync + // source, and we should set our validation options to match it exactly. + cce->updateValidator( + opCtx, options.validator, options.validationLevel, options.validationAction); wuow.commit(); } diff --git a/src/mongo/db/repl/rs_rollback_no_uuid_test.cpp b/src/mongo/db/repl/rs_rollback_no_uuid_test.cpp index a08d9594033..26d918f87c2 100644 --- a/src/mongo/db/repl/rs_rollback_no_uuid_test.cpp +++ b/src/mongo/db/repl/rs_rollback_no_uuid_test.cpp @@ -34,6 +34,7 @@ #include <utility> #include "mongo/db/catalog/collection.h" +#include "mongo/db/catalog/collection_catalog_entry.h" #include "mongo/db/catalog/drop_indexes.h" #include "mongo/db/catalog/index_catalog.h" #include "mongo/db/catalog/index_create.h" @@ -64,72 +65,6 @@ using namespace mongo::repl::rollback_internal_no_uuid; const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2; -class RollbackSourceMock : public RollbackSource { -public: - RollbackSourceMock(std::unique_ptr<OplogInterface> oplog); - int getRollbackId() const override; - const OplogInterface& getOplog() const override; - const HostAndPort& getSource() const override; - BSONObj getLastOperation() const override; - BSONObj findOne(const NamespaceString& nss, const BSONObj& filter) const override; - std::pair<BSONObj, NamespaceString> findOneByUUID(const std::string& db, - UUID uuid, - const BSONObj& filter) const override; - void copyCollectionFromRemote(OperationContext* opCtx, - const NamespaceString& nss) const override; - StatusWith<BSONObj> getCollectionInfoByUUID(const std::string& db, - const UUID& uuid) const override; - StatusWith<BSONObj> getCollectionInfo(const NamespaceString& nss) const override; - -private: - std::unique_ptr<OplogInterface> _oplog; - HostAndPort _source; -}; - -RollbackSourceMock::RollbackSourceMock(std::unique_ptr<OplogInterface> oplog) - : _oplog(std::move(oplog)) {} - -const OplogInterface& RollbackSourceMock::getOplog() const { - return *_oplog; -} - -const HostAndPort& RollbackSourceMock::getSource() const { - return _source; -} - -int RollbackSourceMock::getRollbackId() const { - return 0; -} - -BSONObj RollbackSourceMock::getLastOperation() const { - auto iter = _oplog->makeIterator(); - auto result = iter->next(); - ASSERT_OK(result.getStatus()); - return result.getValue().first; -} - -BSONObj RollbackSourceMock::findOne(const NamespaceString& nss, const BSONObj& filter) const { - return BSONObj(); -} - -std::pair<BSONObj, NamespaceString> RollbackSourceMock::findOneByUUID(const std::string& db, - UUID uuid, - const BSONObj& filter) const { - return {BSONObj(), NamespaceString()}; -} - -void RollbackSourceMock::copyCollectionFromRemote(OperationContext* opCtx, - const NamespaceString& nss) const {} - -StatusWith<BSONObj> RollbackSourceMock::getCollectionInfoByUUID(const std::string& db, - const UUID& uuid) const { - return BSON("options" << BSONObj() << "info" << BSON("uuid" << uuid)); -} - -StatusWith<BSONObj> RollbackSourceMock::getCollectionInfo(const NamespaceString& nss) const { - return BSON("name" << nss.ns() << "options" << BSONObj()); -} - class RSRollbackTest : public RollbackTest { private: void setUp() override; @@ -260,30 +195,6 @@ TEST_F(RSRollbackTest, BothOplogsAtCommonPoint) { } /** - * Create test collection. - * Returns collection. - */ -Collection* _createCollection(OperationContext* opCtx, - const NamespaceString& nss, - const CollectionOptions& options) { - Lock::DBLock dbLock(opCtx, nss.db(), MODE_X); - mongo::WriteUnitOfWork wuow(opCtx); - auto db = dbHolder().openDb(opCtx, nss.db()); - ASSERT_TRUE(db); - db->dropCollection(opCtx, nss.ns()).transitional_ignore(); - auto coll = db->createCollection(opCtx, nss.ns(), options); - ASSERT_TRUE(coll); - wuow.commit(); - return coll; -} - -Collection* _createCollection(OperationContext* opCtx, - const std::string& nss, - const CollectionOptions& options) { - return _createCollection(opCtx, NamespaceString(nss), options); -} - -/** * Test function to roll back a delete operation. * Returns number of records in collection after rolling back delete operation. * If collection does not exist after rolling back, returns -1. @@ -1153,26 +1064,24 @@ TEST_F(RSRollbackTest, RollbackCreateCollectionCommand) { TEST_F(RSRollbackTest, RollbackCollectionModificationCommand) { createOplog(_opCtx.get()); + _createCollection(_opCtx.get(), "test.t", CollectionOptions()); auto commonOperation = std::make_pair(BSON("ts" << Timestamp(Seconds(1), 0) << "h" << 1LL), RecordId(1)); + BSONObj collModCmd = BSON("collMod" + << "t" + << "noPadding" + << false); auto collectionModificationOperation = - std::make_pair(BSON("ts" << Timestamp(Seconds(2), 0) << "h" << 1LL << "op" - << "c" - << "ns" - << "test.t" - << "o" - << BSON("collMod" - << "t" - << "noPadding" - << false)), - RecordId(2)); + makeCommandOp(Timestamp(Seconds(2), 0), boost::none, "test.t", collModCmd, 2); class RollbackSourceLocal : public RollbackSourceMock { public: RollbackSourceLocal(std::unique_ptr<OplogInterface> oplog) : RollbackSourceMock(std::move(oplog)), called(false) {} + + // Remote collection options are empty. StatusWith<BSONObj> getCollectionInfo(const NamespaceString& nss) const { called = true; - return RollbackSourceMock::getCollectionInfo(nss); + return BSON("options" << BSONObj()); } mutable bool called; }; @@ -1194,6 +1103,76 @@ TEST_F(RSRollbackTest, RollbackCollectionModificationCommand) { ASSERT_TRUE(message.find("ignoring op with no _id during rollback. ns: test.t") == std::string::npos); } + + // Make sure the collection options are correct. + AutoGetCollectionForReadCommand autoColl(_opCtx.get(), NamespaceString("test.t")); + auto collAfterRollbackOptions = + autoColl.getCollection()->getCatalogEntry()->getCollectionOptions(_opCtx.get()); + ASSERT(collAfterRollbackOptions.toBSON().isEmpty()); +} + +TEST_F(RollbackResyncsCollectionOptionsTest, + FullRemoteCollectionValidationOptionsAndEmptyLocalValidationOptions) { + // Empty local collection options. + CollectionOptions localCollOptions; + + // Full remote collection validation options. + BSONObj remoteCollOptionsObj = + BSON("validator" << BSON("x" << BSON("$exists" << 1)) << "validationLevel" + << "moderate" + << "validationAction" + << "warn"); + + resyncCollectionOptionsTest(localCollOptions, remoteCollOptionsObj); +} + +TEST_F(RollbackResyncsCollectionOptionsTest, + PartialRemoteCollectionValidationOptionsAndEmptyLocalValidationOptions) { + CollectionOptions localCollOptions; + + BSONObj remoteCollOptionsObj = BSON("validationLevel" + << "moderate" + << "validationAction" + << "warn"); + + resyncCollectionOptionsTest(localCollOptions, remoteCollOptionsObj); +} + +TEST_F(RollbackResyncsCollectionOptionsTest, + PartialRemoteCollectionValidationOptionsAndFullLocalValidationOptions) { + CollectionOptions localCollOptions; + localCollOptions.validator = BSON("x" << BSON("$exists" << 1)); + localCollOptions.validationLevel = "moderate"; + localCollOptions.validationAction = "warn"; + + BSONObj remoteCollOptionsObj = BSON("validationLevel" + << "strict" + << "validationAction" + << "error"); + + + resyncCollectionOptionsTest(localCollOptions, remoteCollOptionsObj); +} + +TEST_F(RollbackResyncsCollectionOptionsTest, + EmptyRemoteCollectionValidationOptionsAndEmptyLocalValidationOptions) { + CollectionOptions localCollOptions; + + BSONObj remoteCollOptionsObj = BSONObj(); + + resyncCollectionOptionsTest(localCollOptions, remoteCollOptionsObj); +} + +TEST_F(RollbackResyncsCollectionOptionsTest, + EmptyRemoteCollectionValidationOptionsAndFullLocalValidationOptions) { + CollectionOptions localCollOptions; + localCollOptions.validator = BSON("x" << BSON("$exists" << 1)); + localCollOptions.validationLevel = "moderate"; + localCollOptions.validationAction = "warn"; + + BSONObj remoteCollOptionsObj = BSONObj(); + + resyncCollectionOptionsTest(localCollOptions, remoteCollOptionsObj); } TEST_F(RSRollbackTest, RollbackCollectionModificationCommandInvalidCollectionOptions) { diff --git a/src/mongo/db/repl/rs_rollback_test.cpp b/src/mongo/db/repl/rs_rollback_test.cpp index 6e93453ea1c..4b656e2e61e 100644 --- a/src/mongo/db/repl/rs_rollback_test.cpp +++ b/src/mongo/db/repl/rs_rollback_test.cpp @@ -67,75 +67,6 @@ using namespace mongo::repl::rollback_internal; const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2; -class RollbackSourceMock : public RollbackSource { -public: - RollbackSourceMock(std::unique_ptr<OplogInterface> oplog); - int getRollbackId() const override; - const OplogInterface& getOplog() const override; - const HostAndPort& getSource() const override; - BSONObj getLastOperation() const override; - BSONObj findOne(const NamespaceString& nss, const BSONObj& filter) const override; - - std::pair<BSONObj, NamespaceString> findOneByUUID(const std::string& db, - UUID uuid, - const BSONObj& filter) const override; - - void copyCollectionFromRemote(OperationContext* opCtx, - const NamespaceString& nss) const override; - StatusWith<BSONObj> getCollectionInfoByUUID(const std::string& db, - const UUID& uuid) const override; - StatusWith<BSONObj> getCollectionInfo(const NamespaceString& nss) const override; - -private: - std::unique_ptr<OplogInterface> _oplog; - HostAndPort _source; -}; - -RollbackSourceMock::RollbackSourceMock(std::unique_ptr<OplogInterface> oplog) - : _oplog(std::move(oplog)) {} - -const OplogInterface& RollbackSourceMock::getOplog() const { - return *_oplog; -} - -const HostAndPort& RollbackSourceMock::getSource() const { - return _source; -} - -int RollbackSourceMock::getRollbackId() const { - return 0; -} - -BSONObj RollbackSourceMock::getLastOperation() const { - auto iter = _oplog->makeIterator(); - auto result = iter->next(); - ASSERT_OK(result.getStatus()); - return result.getValue().first; -} - -BSONObj RollbackSourceMock::findOne(const NamespaceString& nss, const BSONObj& filter) const { - return BSONObj(); -} - -std::pair<BSONObj, NamespaceString> RollbackSourceMock::findOneByUUID(const std::string& db, - UUID uuid, - const BSONObj& filter) const { - return {BSONObj(), NamespaceString()}; -} - -void RollbackSourceMock::copyCollectionFromRemote(OperationContext* opCtx, - const NamespaceString& nss) const {} - -StatusWith<BSONObj> RollbackSourceMock::getCollectionInfo(const NamespaceString& nss) const { - return BSON("name" << nss.ns() << "options" << BSONObj()); -} - -StatusWith<BSONObj> RollbackSourceMock::getCollectionInfoByUUID(const std::string& db, - const UUID& uuid) const { - return BSON("options" << BSONObj() << "info" << BSON("uuid" << uuid)); -} - - class RSRollbackTest : public RollbackTest { private: void setUp() override; @@ -357,30 +288,6 @@ TEST_F(RSRollbackTest, BothOplogsAtCommonPoint) { } /** - * Create test collection. - * Returns collection. - */ -Collection* _createCollection(OperationContext* opCtx, - const NamespaceString& nss, - const CollectionOptions& options) { - Lock::DBLock dbLock(opCtx, nss.db(), MODE_X); - mongo::WriteUnitOfWork wuow(opCtx); - auto db = dbHolder().openDb(opCtx, nss.db()); - ASSERT_TRUE(db); - db->dropCollection(opCtx, nss.ns()).transitional_ignore(); - auto coll = db->createCollection(opCtx, nss.ns(), options); - ASSERT_TRUE(coll); - wuow.commit(); - return coll; -} - -Collection* _createCollection(OperationContext* opCtx, - const std::string& nss, - const CollectionOptions& options) { - return _createCollection(opCtx, NamespaceString(nss), options); -} - -/** * Test function to roll back a delete operation. * Returns number of records in collection after rolling back delete operation. * If collection does not exist after rolling back, returns -1. @@ -1275,10 +1182,10 @@ void _testRollbackRenamingCollectionsToEachOther(OperationContext* opCtx, const CollectionOptions& coll2Options) { createOplog(opCtx); - auto collection1 = _createCollection(opCtx, "test.y", coll1Options); + auto collection1 = RollbackTest::_createCollection(opCtx, "test.y", coll1Options); auto collection1UUID = collection1->uuid().get(); - auto collection2 = _createCollection(opCtx, "test.x", coll2Options); + auto collection2 = RollbackTest::_createCollection(opCtx, "test.x", coll2Options); auto collection2UUID = collection2->uuid().get(); ASSERT_NOT_EQUALS(collection1UUID, collection2UUID); @@ -1824,22 +1731,6 @@ TEST_F(RSRollbackTest, RollbackCreateCollectionCommand) { } } -std::pair<BSONObj, RecordId> makeCommandOp( - Timestamp ts, OptionalCollectionUUID uuid, StringData nss, BSONObj cmdObj, int recordId) { - - BSONObjBuilder bob; - bob.append("ts", ts); - bob.append("h", 1LL); - bob.append("op", "c"); - if (uuid) { // Not all ops have UUID fields. - uuid.get().appendToBuilder(&bob, "ui"); - } - bob.append("ns", nss); - bob.append("o", cmdObj); - - return std::make_pair(bob.obj(), RecordId(recordId)); -} - TEST_F(RSRollbackTest, RollbackCollectionModificationCommand) { createOplog(_opCtx.get()); CollectionOptions options; @@ -1893,84 +1784,6 @@ TEST_F(RSRollbackTest, RollbackCollectionModificationCommand) { ASSERT_BSONOBJ_EQ(BSON("uuid" << *options.uuid), collAfterRollbackOptions.toBSON()); } -/** - * Test fixture to ensure that rollback re-syncs collection options from a sync source and updates - * the local collection options correctly. A test operates on a single test collection, with a fixed - * UUID, and is parameterized on two arguments: - * - * 'localCollOptions': the collection options that the local test collection is initially created - * with. - * - * 'remoteCollOptionsObj': the collection options object that the sync source will respond with to - * the rollback node when it fetches collection metadata. - * - * A collMod operation with a 'noPadding' argument is used to trigger a collection metadata resync, - * since the rollback of collMod operations does not take into account the actual command object. It - * simply re-syncs all the collection options. - */ -class RollbackResyncsCollectionOptionsTest : public RollbackTest { - - - class RollbackSourceWithCollectionOptions : public RollbackSourceMock { - public: - RollbackSourceWithCollectionOptions(std::unique_ptr<OplogInterface> oplog, - BSONObj collOptionsObj) - : RollbackSourceMock(std::move(oplog)), collOptionsObj(collOptionsObj) {} - - StatusWith<BSONObj> getCollectionInfoByUUID(const std::string& db, const UUID& uuid) const { - called = true; - return BSON("options" << collOptionsObj << "info" << BSON("uuid" << uuid)); - } - - mutable bool called = false; - BSONObj collOptionsObj; - }; - -public: - void resyncCollectionOptionsTest(CollectionOptions localCollOptions, - BSONObj remoteCollOptionsObj) { - createOplog(_opCtx.get()); - - auto dbName = "test"; - auto collName = "coll"; - auto nss = NamespaceString(dbName, collName); - - auto coll = _createCollection(_opCtx.get(), nss.toString(), localCollOptions); - auto commonOperation = - std::make_pair(BSON("ts" << Timestamp(Seconds(1), 0) << "h" << 1LL), RecordId(1)); - - // 'collMod' operation used to trigger metadata re-sync. - BSONObj collModCmd = BSON("collMod" << collName << "noPadding" << false); - auto collectionModificationOperation = makeCommandOp( - Timestamp(Seconds(2), 0), coll->uuid().get(), nss.toString(), collModCmd, 2); - - RollbackSourceWithCollectionOptions rollbackSource( - std::unique_ptr<OplogInterface>(new OplogInterfaceMock({commonOperation})), - remoteCollOptionsObj); - - ASSERT_OK( - syncRollback(_opCtx.get(), - OplogInterfaceMock({collectionModificationOperation, commonOperation}), - rollbackSource, - {}, - _coordinator, - _replicationProcess.get())); - - ASSERT_TRUE(rollbackSource.called); - - // Make sure the collection options are correct. - AutoGetCollectionForReadCommand autoColl(_opCtx.get(), NamespaceString(nss.toString())); - auto collAfterRollbackOptions = - autoColl.getCollection()->getCatalogEntry()->getCollectionOptions(_opCtx.get()); - - BSONObjBuilder expectedOptionsBob; - localCollOptions.uuid.get().appendToBuilder(&expectedOptionsBob, "uuid"); - expectedOptionsBob.appendElements(remoteCollOptionsObj); - - ASSERT_BSONOBJ_EQ(expectedOptionsBob.obj(), collAfterRollbackOptions.toBSON()); - } -}; - TEST_F(RollbackResyncsCollectionOptionsTest, FullRemoteCollectionValidationOptionsAndEmptyLocalValidationOptions) { // Empty local collection options. |