summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorGregory Noma <gregory.noma@gmail.com>2022-04-07 15:05:30 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-04-07 19:58:16 +0000
commitc9f9b3e5a9124c35b5e8c69ed89c47b4d5ab41a9 (patch)
treef4f936685423e9871aacb7e41df98328d2f68712 /src/mongo/db
parentf4398987e7222d2e55fec776bc7a2e3c44af42cf (diff)
downloadmongo-c9f9b3e5a9124c35b5e8c69ed89c47b4d5ab41a9.tar.gz
SERVER-65146 Run unit tests with `wiredTiger` by default
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/SConscript1
-rw-r--r--src/mongo/db/catalog/catalog_test_fixture.h4
-rw-r--r--src/mongo/db/catalog/collection_test.cpp7
-rw-r--r--src/mongo/db/catalog/collection_validation_test.cpp41
-rw-r--r--src/mongo/db/catalog/database_test.cpp52
-rw-r--r--src/mongo/db/catalog/multi_index_block_test.cpp3
-rw-r--r--src/mongo/db/catalog/rename_collection_test.cpp115
-rw-r--r--src/mongo/db/catalog/throttle_cursor_test.cpp4
-rw-r--r--src/mongo/db/catalog/validate_state_test.cpp2
-rw-r--r--src/mongo/db/commands/mr_test.cpp1
-rw-r--r--src/mongo/db/db_raii_multi_collection_test.cpp2
-rw-r--r--src/mongo/db/db_raii_test.cpp1
-rw-r--r--src/mongo/db/exec/queued_data_stage_test.cpp3
-rw-r--r--src/mongo/db/exec/sbe/sbe_plan_stage_test.cpp1
-rw-r--r--src/mongo/db/exec/sort_test.cpp3
-rw-r--r--src/mongo/db/key_generator_update_test.cpp4
-rw-r--r--src/mongo/db/keys_collection_manager_sharding_test.cpp40
-rw-r--r--src/mongo/db/logical_time_validator_test.cpp4
-rw-r--r--src/mongo/db/op_observer_impl_test.cpp5
-rw-r--r--src/mongo/db/query/classic_stage_builder_test.cpp3
-rw-r--r--src/mongo/db/repl/SConscript1
-rw-r--r--src/mongo/db/repl/idempotency_test_fixture.h2
-rw-r--r--src/mongo/db/repl/mock_repl_coord_server_fixture.cpp9
-rw-r--r--src/mongo/db/repl/mock_repl_coord_server_fixture.h4
-rw-r--r--src/mongo/db/repl/oplog_applier_impl_test_fixture.h9
-rw-r--r--src/mongo/db/repl/primary_only_service_test_fixture.h3
-rw-r--r--src/mongo/db/repl/replication_consistency_markers_impl_test.cpp2
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl_heartbeat_v1_test.cpp2
-rw-r--r--src/mongo/db/repl/replication_coordinator_mock.cpp19
-rw-r--r--src/mongo/db/repl/replication_coordinator_mock.h2
-rw-r--r--src/mongo/db/repl/replication_coordinator_test_fixture.cpp4
-rw-r--r--src/mongo/db/repl/replication_coordinator_test_fixture.h2
-rw-r--r--src/mongo/db/repl/replication_recovery_test.cpp3
-rw-r--r--src/mongo/db/repl/rollback_impl_test.cpp3
-rw-r--r--src/mongo/db/repl/rollback_test_fixture.cpp70
-rw-r--r--src/mongo/db/repl/rollback_test_fixture.h39
-rw-r--r--src/mongo/db/repl/rs_rollback_test.cpp2971
-rw-r--r--src/mongo/db/repl/storage_interface_impl_test.cpp7
-rw-r--r--src/mongo/db/repl/storage_timestamp_test.cpp7
-rw-r--r--src/mongo/db/repl/tenant_migration_donor_service_test.cpp11
-rw-r--r--src/mongo/db/repl/tenant_migration_recipient_service_test.cpp20
-rw-r--r--src/mongo/db/s/balancer/migration_test_fixture.h3
-rw-r--r--src/mongo/db/s/config/config_server_test_fixture.cpp3
-rw-r--r--src/mongo/db/s/config/config_server_test_fixture.h2
-rw-r--r--src/mongo/db/s/config/sharding_catalog_manager_config_initialization_test.cpp3
-rw-r--r--src/mongo/db/s/migration_chunk_cloner_source_legacy_test.cpp10
-rw-r--r--src/mongo/db/s/resharding/resharding_coordinator_service_test.cpp4
-rw-r--r--src/mongo/db/s/resharding/resharding_donor_recipient_common_test.cpp8
-rw-r--r--src/mongo/db/s/resharding/resharding_oplog_batch_applier_test.cpp5
-rw-r--r--src/mongo/db/s/resharding/resharding_oplog_session_application_test.cpp5
-rw-r--r--src/mongo/db/s/resharding/resharding_txn_cloner_test.cpp3
-rw-r--r--src/mongo/db/s/shard_local_test.cpp9
-rw-r--r--src/mongo/db/s/shard_server_test_fixture.cpp3
-rw-r--r--src/mongo/db/s/shard_server_test_fixture.h2
-rw-r--r--src/mongo/db/s/sharding_mongod_test_fixture.cpp11
-rw-r--r--src/mongo/db/s/sharding_mongod_test_fixture.h6
-rw-r--r--src/mongo/db/s/vector_clock_config_server_test.cpp6
-rw-r--r--src/mongo/db/s/vector_clock_shard_server_test.cpp6
-rw-r--r--src/mongo/db/serverless/shard_split_donor_service_test.cpp4
-rw-r--r--src/mongo/db/service_context_d_test_fixture.cpp38
-rw-r--r--src/mongo/db/service_context_d_test_fixture.h48
-rw-r--r--src/mongo/db/service_context_devnull_test_fixture.cpp2
-rw-r--r--src/mongo/db/session_catalog_mongod_test.cpp4
-rw-r--r--src/mongo/db/storage/kv/durable_catalog_test.cpp19
-rw-r--r--src/mongo/db/storage/kv/storage_engine_test.cpp11
-rw-r--r--src/mongo/db/storage/storage_engine_test_fixture.h30
-rw-r--r--src/mongo/db/storage/storage_repair_observer_test.cpp3
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp3
-rw-r--r--src/mongo/db/transaction_participant_test.cpp10
-rw-r--r--src/mongo/db/vector_clock_mongod_test.cpp6
-rw-r--r--src/mongo/db/vector_clock_test.cpp49
-rw-r--r--src/mongo/db/vector_clock_test_fixture.cpp18
-rw-r--r--src/mongo/db/vector_clock_test_fixture.h12
73 files changed, 334 insertions, 3498 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript
index ef1e749de69..53d0a9067e9 100644
--- a/src/mongo/db/SConscript
+++ b/src/mongo/db/SConscript
@@ -2144,6 +2144,7 @@ env.Library(
'$BUILD_DIR/mongo/db/storage/ephemeral_for_test/storage_ephemeral_for_test',
'$BUILD_DIR/mongo/db/storage/storage_control',
'$BUILD_DIR/mongo/db/storage/storage_options',
+ '$BUILD_DIR/mongo/db/storage/wiredtiger/storage_wiredtiger',
'$BUILD_DIR/mongo/util/clock_source_mock',
'index_builds_coordinator_mongod',
'service_context_d',
diff --git a/src/mongo/db/catalog/catalog_test_fixture.h b/src/mongo/db/catalog/catalog_test_fixture.h
index fc30f046d6f..b71933fa317 100644
--- a/src/mongo/db/catalog/catalog_test_fixture.h
+++ b/src/mongo/db/catalog/catalog_test_fixture.h
@@ -47,8 +47,8 @@ public:
* Allows selection of storage engine to back the unit test, defaulting to ephemeralForTest
* when not specified.
*/
- CatalogTestFixture() : CatalogTestFixture("ephemeralForTest") {}
- explicit CatalogTestFixture(std::string engine) : ServiceContextMongoDTest(std::move(engine)) {}
+ explicit CatalogTestFixture(Options options = {})
+ : ServiceContextMongoDTest(std::move(options)) {}
OperationContext* operationContext();
repl::StorageInterface* storageInterface();
diff --git a/src/mongo/db/catalog/collection_test.cpp b/src/mongo/db/catalog/collection_test.cpp
index 759a01fcd52..fd73c68bad8 100644
--- a/src/mongo/db/catalog/collection_test.cpp
+++ b/src/mongo/db/catalog/collection_test.cpp
@@ -56,6 +56,9 @@ using namespace mongo;
class CollectionTest : public CatalogTestFixture {
protected:
+ // TODO (SERVER-65194): Use wiredTiger.
+ CollectionTest() : CatalogTestFixture(Options{}.engine("ephemeralForTest")) {}
+
void makeCapped(NamespaceString nss, long long cappedSize = 8192);
void makeTimeseries(NamespaceString nss);
void makeCollectionForMultikey(NamespaceString nss, StringData indexName);
@@ -639,6 +642,7 @@ TEST_F(CatalogTestFixture, CappedVisibilityEmptyInitialState) {
RecordStore* rs = coll->getRecordStore();
auto doInsert = [&](OperationContext* opCtx) -> RecordId {
+ Lock::GlobalLock globalLock{opCtx, MODE_IX};
std::string data = "data";
return uassertStatusOK(rs->insertRecord(opCtx, data.c_str(), data.size(), Timestamp()));
};
@@ -699,6 +703,7 @@ TEST_F(CatalogTestFixture, CappedVisibilityNonEmptyInitialState) {
RecordStore* rs = coll->getRecordStore();
auto doInsert = [&](OperationContext* opCtx) -> RecordId {
+ Lock::GlobalLock globalLock{opCtx, MODE_IX};
std::string data = "data";
return uassertStatusOK(rs->insertRecord(opCtx, data.c_str(), data.size(), Timestamp()));
};
@@ -768,7 +773,7 @@ TEST_F(CatalogTestFixture, CappedVisibilityNonEmptyInitialState) {
ASSERT_ID_EQ(rs->getCursor(longLivedOpCtx.get())->seekExact(otherId), otherId);
}
-TEST_F(CatalogTestFixture, CappedCursorRollover) {
+TEST_F(CollectionTest, CappedCursorRollover) {
NamespaceString nss("test.t");
CollectionOptions options;
options.capped = true;
diff --git a/src/mongo/db/catalog/collection_validation_test.cpp b/src/mongo/db/catalog/collection_validation_test.cpp
index 28db9ec0f06..4ffff4f653b 100644
--- a/src/mongo/db/catalog/collection_validation_test.cpp
+++ b/src/mongo/db/catalog/collection_validation_test.cpp
@@ -46,20 +46,7 @@ namespace {
const NamespaceString kNss = NamespaceString("test.t");
-/**
- * Test fixture for collection validation with the ephemeralForTest storage engine.
- * Validation with {background:true} is not supported by the ephemeralForTest storage engine.
- */
class CollectionValidationTest : public CatalogTestFixture {
-public:
- CollectionValidationTest() : CollectionValidationTest("ephemeralForTest") {}
-
-protected:
- /**
- * Allow inheriting classes to select a storage engine with which to run unit tests.
- */
- explicit CollectionValidationTest(std::string engine) : CatalogTestFixture(std::move(engine)) {}
-
private:
void setUp() override {
CatalogTestFixture::setUp();
@@ -72,24 +59,6 @@ private:
};
/**
- * Test fixture for testing background collection validation on the wiredTiger engine, which is
- * currently the only storage engine that supports background collection validation.
- *
- * Collection kNss will be created for each unit test, courtesy of inheritance from
- * CollectionValidationTest.
- */
-class BackgroundCollectionValidationTest : public CollectionValidationTest {
-public:
- /**
- * Sets up the wiredTiger storage engine that supports data checkpointing.
- *
- * Background validation runs on a checkpoint, and therefore only on storage engines that
- * support checkpoints.
- */
- BackgroundCollectionValidationTest() : CollectionValidationTest("wiredTiger") {}
-};
-
-/**
* Calls validate on collection kNss with both kValidateFull and kValidateNormal validation levels
* and verifies the results.
*
@@ -242,7 +211,7 @@ TEST_F(CollectionValidationTest, ValidateEmpty) {
/*numInvalidDocuments*/ 0,
/*numErrors*/ 0);
}
-TEST_F(BackgroundCollectionValidationTest, BackgroundValidateEmpty) {
+TEST_F(CollectionValidationTest, BackgroundValidateEmpty) {
// Running on the WT storage engine.
backgroundValidate(operationContext(),
/*valid*/ true,
@@ -261,7 +230,7 @@ TEST_F(CollectionValidationTest, Validate) {
/*numInvalidDocuments*/ 0,
/*numErrors*/ 0);
}
-TEST_F(BackgroundCollectionValidationTest, BackgroundValidate) {
+TEST_F(CollectionValidationTest, BackgroundValidate) {
auto opCtx = operationContext();
backgroundValidate(opCtx,
/*valid*/ true,
@@ -280,7 +249,7 @@ TEST_F(CollectionValidationTest, ValidateError) {
/*numInvalidDocuments*/ 1,
/*numErrors*/ 1);
}
-TEST_F(BackgroundCollectionValidationTest, BackgroundValidateError) {
+TEST_F(CollectionValidationTest, BackgroundValidateError) {
auto opCtx = operationContext();
backgroundValidate(opCtx,
/*valid*/ false,
@@ -314,7 +283,7 @@ void waitUntilValidateFailpointHasBeenReached() {
ASSERT(CollectionValidation::getIsValidationPausedForTest());
}
-TEST_F(BackgroundCollectionValidationTest, BackgroundValidateRunsConcurrentlyWithWrites) {
+TEST_F(CollectionValidationTest, BackgroundValidateRunsConcurrentlyWithWrites) {
auto opCtx = operationContext();
auto serviceContext = opCtx->getServiceContext();
@@ -378,7 +347,7 @@ KeyString::Value makeKeyStringWithoutRecordId(const KeyString::Value& keyStringW
}
// Verify calling validate() on a collection with old (pre-4.2) keys in a WT unique index.
-TEST_F(BackgroundCollectionValidationTest, ValidateOldUniqueIndexKeyWarning) {
+TEST_F(CollectionValidationTest, ValidateOldUniqueIndexKeyWarning) {
auto opCtx = operationContext();
{
diff --git a/src/mongo/db/catalog/database_test.cpp b/src/mongo/db/catalog/database_test.cpp
index cd6f0a97401..dd72c38588c 100644
--- a/src/mongo/db/catalog/database_test.cpp
+++ b/src/mongo/db/catalog/database_test.cpp
@@ -68,6 +68,8 @@ private:
void tearDown() override;
protected:
+ explicit DatabaseTest(Options options = {}) : ServiceContextMongoDTest(std::move(options)) {}
+
ServiceContext::UniqueOperationContext _opCtx;
NamespaceString _nss;
};
@@ -213,30 +215,6 @@ TEST_F(DatabaseTest, DropCollectionDropsCollectionButDoesNotLogOperationIfWrites
ASSERT_EQUALS(repl::OpTime(), dropOpTime);
}
-TEST_F(DatabaseTest,
- DropCollectionRenamesCollectionToPendingDropNamespaceAndLogsOperationIfWritesAreReplicated) {
- ASSERT_TRUE(_opCtx->writesAreReplicated());
- ASSERT_FALSE(
- repl::ReplicationCoordinator::get(_opCtx.get())->isOplogDisabledFor(_opCtx.get(), _nss));
-
- _testDropCollection(_opCtx.get(), _nss, true);
-
- // Drop optime is non-null because an op was written to the oplog.
- auto dropOpTime = repl::ReplClientInfo::forClient(&cc()).getLastOp();
- ASSERT_GREATER_THAN(dropOpTime, repl::OpTime());
-
- // Replicated collection is renamed with a special drop-pending names in the <db>.system.drop.*
- // namespace.
- auto dpns = _nss.makeDropPendingNamespace(dropOpTime);
- ASSERT_TRUE(AutoGetCollectionForRead(_opCtx.get(), dpns).getCollection());
-
- // Reaper should have the drop optime of the collection.
- auto reaperEarliestDropOpTime =
- repl::DropPendingCollectionReaper::get(_opCtx.get())->getEarliestDropOpTime();
- ASSERT_TRUE(reaperEarliestDropOpTime);
- ASSERT_EQUALS(dropOpTime, *reaperEarliestDropOpTime);
-}
-
TEST_F(DatabaseTest, DropCollectionRejectsProvidedDropOpTimeIfWritesAreReplicated) {
ASSERT_TRUE(_opCtx->writesAreReplicated());
ASSERT_FALSE(
@@ -259,32 +237,6 @@ TEST_F(DatabaseTest, DropCollectionRejectsProvidedDropOpTimeIfWritesAreReplicate
ASSERT_EQUALS(ErrorCodes::BadValue, db->dropCollection(opCtx, nss, dropOpTime));
}
-TEST_F(
- DatabaseTest,
- DropCollectionRenamesCollectionToPendingDropNamespaceUsingProvidedDropOpTimeButDoesNotLogOperation) {
- repl::UnreplicatedWritesBlock uwb(_opCtx.get());
- ASSERT_FALSE(_opCtx->writesAreReplicated());
- ASSERT_TRUE(
- repl::ReplicationCoordinator::get(_opCtx.get())->isOplogDisabledFor(_opCtx.get(), _nss));
-
- repl::OpTime dropOpTime(Timestamp(Seconds(100), 0), 1LL);
- _testDropCollection(_opCtx.get(), _nss, true, dropOpTime);
-
- // Last optime in repl client is null because we did not write to the oplog.
- ASSERT_EQUALS(repl::OpTime(), repl::ReplClientInfo::forClient(&cc()).getLastOp());
-
- // Replicated collection is renamed with a special drop-pending names in the <db>.system.drop.*
- // namespace.
- auto dpns = _nss.makeDropPendingNamespace(dropOpTime);
- ASSERT_TRUE(mongo::AutoGetCollectionForRead(_opCtx.get(), dpns).getCollection());
-
- // Reaper should have the drop optime of the collection.
- auto reaperEarliestDropOpTime =
- repl::DropPendingCollectionReaper::get(_opCtx.get())->getEarliestDropOpTime();
- ASSERT_TRUE(reaperEarliestDropOpTime);
- ASSERT_EQUALS(dropOpTime, *reaperEarliestDropOpTime);
-}
-
void _testDropCollectionThrowsExceptionIfThereAreIndexesInProgress(OperationContext* opCtx,
const NamespaceString& nss) {
writeConflictRetry(opCtx, "testDropCollectionWithIndexesInProgress", nss.ns(), [opCtx, nss] {
diff --git a/src/mongo/db/catalog/multi_index_block_test.cpp b/src/mongo/db/catalog/multi_index_block_test.cpp
index f867de098ed..2fb9caf7371 100644
--- a/src/mongo/db/catalog/multi_index_block_test.cpp
+++ b/src/mongo/db/catalog/multi_index_block_test.cpp
@@ -79,9 +79,6 @@ void MultiIndexBlockTest::setUp() {
}
void MultiIndexBlockTest::tearDown() {
- auto service = getServiceContext();
- repl::ReplicationCoordinator::set(service, {});
-
_indexer = {};
CatalogTestFixture::tearDown();
diff --git a/src/mongo/db/catalog/rename_collection_test.cpp b/src/mongo/db/catalog/rename_collection_test.cpp
index 5273e1c7ddf..215069fd9b7 100644
--- a/src/mongo/db/catalog/rename_collection_test.cpp
+++ b/src/mongo/db/catalog/rename_collection_test.cpp
@@ -314,6 +314,9 @@ private:
void tearDown() override;
protected:
+ explicit RenameCollectionTest(Options options = {})
+ : ServiceContextMongoDTest(std::move(options)) {}
+
ServiceContext::UniqueOperationContext _opCtx;
repl::ReplicationCoordinatorMock* _replCoord = nullptr;
OpObserverMock* _opObserver = nullptr;
@@ -765,31 +768,6 @@ TEST_F(RenameCollectionTest,
renameCollection(_opCtx.get(), _sourceNss, _targetNss, options));
}
-TEST_F(RenameCollectionTest, RenameCollectionMakesTargetCollectionDropPendingIfDropTargetIsTrue) {
- _createCollectionWithUUID(_opCtx.get(), _sourceNss);
- auto targetUUID = _createCollectionWithUUID(_opCtx.get(), _targetNss);
- RenameCollectionOptions options;
- options.dropTarget = true;
- ASSERT_OK(renameCollection(_opCtx.get(), _sourceNss, _targetNss, options));
- ASSERT_FALSE(_collectionExists(_opCtx.get(), _sourceNss))
- << "source collection " << _sourceNss << " still exists after successful rename";
- ASSERT_TRUE(_collectionExists(_opCtx.get(), _targetNss))
- << "target collection " << _targetNss << " missing after successful rename";
-
- ASSERT_TRUE(_opObserver->onRenameCollectionCalled);
- ASSERT(_opObserver->onRenameCollectionDropTarget);
- ASSERT_EQUALS(targetUUID, *_opObserver->onRenameCollectionDropTarget);
-
- auto renameOpTime = _opObserver->renameOpTime;
- ASSERT_GREATER_THAN(renameOpTime, repl::OpTime());
-
- // Confirm that the target collection has been renamed to a drop-pending collection.
- auto dpns = _targetNss.makeDropPendingNamespace(renameOpTime);
- ASSERT_TRUE(_collectionExists(_opCtx.get(), dpns))
- << "target collection " << _targetNss
- << " not renamed to drop-pending collection after successful rename";
-}
-
TEST_F(RenameCollectionTest,
RenameCollectionOverridesDropTargetIfTargetCollectionIsMissingAndDropTargetIsTrue) {
_createCollectionWithUUID(_opCtx.get(), _sourceNss);
@@ -817,30 +795,6 @@ TEST_F(RenameCollectionTest, RenameCollectionForApplyOpsRejectsRenameOpTimeIfWri
renameCollectionForApplyOps(_opCtx.get(), dbName, boost::none, cmd, renameOpTime));
}
-TEST_F(RenameCollectionTest,
- RenameCollectionForApplyOpsMakesTargetCollectionDropPendingIfDropTargetIsTrue) {
- repl::UnreplicatedWritesBlock uwb(_opCtx.get());
- ASSERT_FALSE(_opCtx->writesAreReplicated());
-
- // OpObserver::preRenameCollection() must return a null OpTime when writes are not replicated.
- _opObserver->renameOpTime = {};
-
- _createCollection(_opCtx.get(), _sourceNss);
- auto dropTargetUUID = _createCollectionWithUUID(_opCtx.get(), _targetNss);
- auto dbName = _sourceNss.db().toString();
- auto cmd = BSON("renameCollection" << _sourceNss.ns() << "to" << _targetNss.ns() << "dropTarget"
- << dropTargetUUID);
-
- repl::OpTime renameOpTime = {Timestamp(Seconds(200), 1U), 1LL};
- ASSERT_OK(renameCollectionForApplyOps(_opCtx.get(), dbName, boost::none, cmd, renameOpTime));
-
- // Confirm that the target collection has been renamed to a drop-pending collection.
- auto dpns = _targetNss.makeDropPendingNamespace(renameOpTime);
- ASSERT_TRUE(_collectionExists(_opCtx.get(), dpns))
- << "target collection " << _targetNss
- << " not renamed to drop-pending collection after successful rename for applyOps";
-}
-
DEATH_TEST_F(RenameCollectionTest,
RenameCollectionForApplyOpsTriggersFatalAssertionIfLogOpReturnsValidOpTime,
"unexpected renameCollection oplog entry written to the oplog") {
@@ -894,69 +848,6 @@ TEST_F(RenameCollectionTest, RenameCollectionForApplyOpsDropTargetByUUIDEvenIfSo
ASSERT_FALSE(_collectionExists(_opCtx.get(), dropTargetNss));
}
-TEST_F(RenameCollectionTest, RenameCollectionForApplyOpsDropTargetEvenIfSourceIsDropPending) {
- repl::OpTime dropOpTime(Timestamp(Seconds(100), 0), 1LL);
- auto dropPendingNss = _sourceNss.makeDropPendingNamespace(dropOpTime);
-
- auto dropTargetUUID = _createCollectionWithUUID(_opCtx.get(), _targetNss);
- auto uuid = _createCollectionWithUUID(_opCtx.get(), dropPendingNss);
- auto cmd =
- BSON("renameCollection" << dropPendingNss.ns() << "to" << _targetNss.ns() << "dropTarget"
- << "true");
-
- repl::UnreplicatedWritesBlock uwb(_opCtx.get());
- repl::OpTime renameOpTime = {Timestamp(Seconds(200), 1U), 1LL};
- ASSERT_OK(renameCollectionForApplyOps(
- _opCtx.get(), dropPendingNss.db().toString(), uuid, cmd, renameOpTime));
-
- // Source collections stays in drop-pending state.
- ASSERT_TRUE(_collectionExists(_opCtx.get(), dropPendingNss));
- ASSERT_FALSE(_collectionExists(_opCtx.get(), _targetNss));
- ASSERT_EQUALS(_targetNss.makeDropPendingNamespace(renameOpTime),
- _getCollectionNssFromUUID(_opCtx.get(), dropTargetUUID));
-}
-
-TEST_F(RenameCollectionTest, RenameCollectionForApplyOpsDropTargetByUUIDEvenIfSourceIsDropPending) {
- repl::OpTime dropOpTime(Timestamp(Seconds(100), 0), 1LL);
- auto dropPendingNss = _sourceNss.makeDropPendingNamespace(dropOpTime);
- auto dropTargetNss = NamespaceString("test.bar2");
-
- _createCollectionWithUUID(_opCtx.get(), _targetNss);
-
- auto dropTargetUUID = _createCollectionWithUUID(_opCtx.get(), dropTargetNss);
- auto uuid = _createCollectionWithUUID(_opCtx.get(), dropPendingNss);
- auto cmd = BSON("renameCollection" << dropPendingNss.ns() << "to" << _targetNss.ns()
- << "dropTarget" << dropTargetUUID);
-
- repl::UnreplicatedWritesBlock uwb(_opCtx.get());
- repl::OpTime renameOpTime = {Timestamp(Seconds(200), 1U), 1LL};
- ASSERT_OK(renameCollectionForApplyOps(
- _opCtx.get(), dropPendingNss.db().toString(), uuid, cmd, renameOpTime));
-
- // Source collections stays in drop-pending state.
- ASSERT_TRUE(_collectionExists(_opCtx.get(), dropPendingNss));
- ASSERT_FALSE(_collectionExists(_opCtx.get(), dropTargetNss));
- ASSERT_EQUALS(dropTargetNss.makeDropPendingNamespace(renameOpTime),
- _getCollectionNssFromUUID(_opCtx.get(), dropTargetUUID));
- ASSERT_TRUE(_collectionExists(_opCtx.get(), _targetNss));
-}
-
-TEST_F(RenameCollectionTest, RenameCollectionForApplyOpsDropTargetByUUIDEvenIfSourceEqualsTarget) {
- auto dropTargetUUID = _createCollectionWithUUID(_opCtx.get(), _targetNss);
- auto uuid = _createCollectionWithUUID(_opCtx.get(), _sourceNss);
- auto cmd = BSON("renameCollection" << _sourceNss.ns() << "to" << _sourceNss.ns() << "dropTarget"
- << dropTargetUUID);
- repl::UnreplicatedWritesBlock uwb(_opCtx.get());
- repl::OpTime renameOpTime = {Timestamp(Seconds(200), 1U), 1LL};
- auto dpns = _targetNss.makeDropPendingNamespace(renameOpTime);
- ASSERT_OK(renameCollectionForApplyOps(
- _opCtx.get(), _sourceNss.db().toString(), uuid, cmd, renameOpTime));
-
- ASSERT_TRUE(_collectionExists(_opCtx.get(), _sourceNss));
- ASSERT_TRUE(_collectionExists(_opCtx.get(), dpns));
- ASSERT_FALSE(_collectionExists(_opCtx.get(), _targetNss));
-}
-
void _testRenameCollectionStayTemp(OperationContext* opCtx,
const NamespaceString& sourceNss,
const NamespaceString& targetNss,
diff --git a/src/mongo/db/catalog/throttle_cursor_test.cpp b/src/mongo/db/catalog/throttle_cursor_test.cpp
index 2f272e3eeef..2710e627c3f 100644
--- a/src/mongo/db/catalog/throttle_cursor_test.cpp
+++ b/src/mongo/db/catalog/throttle_cursor_test.cpp
@@ -55,6 +55,10 @@ private:
void setUp() override;
void tearDown() override;
+protected:
+ // TODO (SERVER-65221): Use wiredTiger.
+ ThrottleCursorTest() : CatalogTestFixture(Options{}.engine("ephemeralForTest")) {}
+
public:
void setMaxMbPerSec(int maxMbPerSec);
diff --git a/src/mongo/db/catalog/validate_state_test.cpp b/src/mongo/db/catalog/validate_state_test.cpp
index 45868b0ad87..e8e4bfbbbd9 100644
--- a/src/mongo/db/catalog/validate_state_test.cpp
+++ b/src/mongo/db/catalog/validate_state_test.cpp
@@ -52,8 +52,6 @@ const NamespaceString kNss = NamespaceString("fooDB.fooColl");
class ValidateStateTest : public CatalogTestFixture {
public:
- ValidateStateTest() : CatalogTestFixture("wiredTiger") {}
-
/**
* Create collection 'nss'. It will possess a default _id index.
*/
diff --git a/src/mongo/db/commands/mr_test.cpp b/src/mongo/db/commands/mr_test.cpp
index a4c8b4da699..745d883c8e1 100644
--- a/src/mongo/db/commands/mr_test.cpp
+++ b/src/mongo/db/commands/mr_test.cpp
@@ -520,6 +520,7 @@ TEST_F(MapReduceCommandTest, PrimaryStepDownPreventsTemporaryCollectionDrops) {
// Temporary collections should still be present because the server will not accept writes after
// stepping down.
+ _opCtx->recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kLastApplied);
for (const auto& tempNss : _opObserver->tempNamespaces) {
ASSERT_OK(_storage.getCollectionCount(_opCtx.get(), tempNss).getStatus())
<< "missing mapReduce temporary collection: " << tempNss;
diff --git a/src/mongo/db/db_raii_multi_collection_test.cpp b/src/mongo/db/db_raii_multi_collection_test.cpp
index fa47f44c3df..1ad777c076a 100644
--- a/src/mongo/db/db_raii_multi_collection_test.cpp
+++ b/src/mongo/db/db_raii_multi_collection_test.cpp
@@ -45,8 +45,6 @@ namespace {
class AutoGetCollectionMultiTest : public CatalogTestFixture {
public:
- AutoGetCollectionMultiTest() : CatalogTestFixture("wiredTiger") {}
-
typedef std::pair<ServiceContext::UniqueClient, ServiceContext::UniqueOperationContext>
ClientAndCtx;
diff --git a/src/mongo/db/db_raii_test.cpp b/src/mongo/db/db_raii_test.cpp
index 076d8cbbe13..3c578a29370 100644
--- a/src/mongo/db/db_raii_test.cpp
+++ b/src/mongo/db/db_raii_test.cpp
@@ -51,7 +51,6 @@ namespace {
class DBRAIITestFixture : public CatalogTestFixture {
public:
- DBRAIITestFixture() : CatalogTestFixture("wiredTiger") {}
typedef std::pair<ServiceContext::UniqueClient, ServiceContext::UniqueOperationContext>
ClientAndCtx;
diff --git a/src/mongo/db/exec/queued_data_stage_test.cpp b/src/mongo/db/exec/queued_data_stage_test.cpp
index fadb53807b4..37f895ebb6b 100644
--- a/src/mongo/db/exec/queued_data_stage_test.cpp
+++ b/src/mongo/db/exec/queued_data_stage_test.cpp
@@ -53,8 +53,7 @@ const static NamespaceString kNss("db.dummy");
class QueuedDataStageTest : public ServiceContextMongoDTest {
public:
- QueuedDataStageTest() {
- getServiceContext()->setFastClockSource(std::make_unique<ClockSourceMock>());
+ QueuedDataStageTest() : ServiceContextMongoDTest(Options{}.useMockClock(true)) {
_opCtx = makeOperationContext();
}
diff --git a/src/mongo/db/exec/sbe/sbe_plan_stage_test.cpp b/src/mongo/db/exec/sbe/sbe_plan_stage_test.cpp
index 04dbe8bc454..77b1997bdee 100644
--- a/src/mongo/db/exec/sbe/sbe_plan_stage_test.cpp
+++ b/src/mongo/db/exec/sbe/sbe_plan_stage_test.cpp
@@ -66,6 +66,7 @@ PlanStageTestFixture::generateVirtualScanMulti(int32_t numSlots, const BSONArray
}
void PlanStageTestFixture::prepareTree(CompileCtx* ctx, PlanStage* root) {
+ Lock::GlobalLock globalLock{opCtx(), MODE_IS};
root->attachToOperationContext(opCtx());
root->prepare(*ctx);
root->open(false);
diff --git a/src/mongo/db/exec/sort_test.cpp b/src/mongo/db/exec/sort_test.cpp
index 6c9bc2d9379..7266665304a 100644
--- a/src/mongo/db/exec/sort_test.cpp
+++ b/src/mongo/db/exec/sort_test.cpp
@@ -55,8 +55,7 @@ class SortStageDefaultTest : public ServiceContextMongoDTest {
public:
static constexpr uint64_t kMaxMemoryUsageBytes = 1024u * 1024u;
- SortStageDefaultTest() {
- getServiceContext()->setFastClockSource(std::make_unique<ClockSourceMock>());
+ SortStageDefaultTest() : ServiceContextMongoDTest(Options{}.useMockClock(true)) {
_opCtx = makeOperationContext();
CollatorFactoryInterface::set(getServiceContext(), std::make_unique<CollatorFactoryMock>());
}
diff --git a/src/mongo/db/key_generator_update_test.cpp b/src/mongo/db/key_generator_update_test.cpp
index cb1191e5621..70464ca01ff 100644
--- a/src/mongo/db/key_generator_update_test.cpp
+++ b/src/mongo/db/key_generator_update_test.cpp
@@ -49,11 +49,11 @@ namespace {
class KeyGeneratorUpdateTest : public ConfigServerTestFixture {
protected:
+ KeyGeneratorUpdateTest() : ConfigServerTestFixture(Options{}.useMockClock(true)) {}
+
void setUp() override {
ConfigServerTestFixture::setUp();
- auto clockSource = std::make_unique<ClockSourceMock>();
- operationContext()->getServiceContext()->setFastClockSource(std::move(clockSource));
_catalogClient = std::make_unique<KeysCollectionClientSharded>(
Grid::get(operationContext())->catalogClient());
}
diff --git a/src/mongo/db/keys_collection_manager_sharding_test.cpp b/src/mongo/db/keys_collection_manager_sharding_test.cpp
index ba22b2c0481..2e4b175296e 100644
--- a/src/mongo/db/keys_collection_manager_sharding_test.cpp
+++ b/src/mongo/db/keys_collection_manager_sharding_test.cpp
@@ -51,15 +51,11 @@ public:
}
protected:
+ KeysManagerShardedTest() : ConfigServerTestFixture(Options{}.useMockClock(true)) {}
+
void setUp() override {
ConfigServerTestFixture::setUp();
- auto clockSource = std::make_unique<ClockSourceMock>();
- // Timestamps of "0 seconds" are not allowed, so we must advance our clock mock to the first
- // real second.
- clockSource->advance(Seconds(1));
-
- operationContext()->getServiceContext()->setFastClockSource(std::move(clockSource));
auto catalogClient = std::make_unique<KeysCollectionClientSharded>(
Grid::get(operationContext())->catalogClient());
_keyManager =
@@ -77,12 +73,26 @@ private:
};
TEST_F(KeysManagerShardedTest, GetKeyForValidationTimesOutIfRefresherIsNotRunning) {
- operationContext()->setDeadlineAfterNowBy(Microseconds(250 * 1000),
- ErrorCodes::ExceededTimeLimit);
+ Milliseconds maxTime{25};
+ operationContext()->setDeadlineAfterNowBy(maxTime, ErrorCodes::ExceededTimeLimit);
+
+ AtomicWord<bool> done{false};
+ stdx::thread t{[&] {
+ ASSERT_THROWS(keyManager()->getKeysForValidation(
+ operationContext(), 1, LogicalTime(Timestamp(100, 0))),
+ DBException);
+ done.store(true);
+ }};
+
+ int numTimesAdvanced = 0;
+ while (!done.load()) {
+ ClockSourceMock clock;
+ clock.advance(maxTime);
+ ++numTimesAdvanced;
+ }
+ t.join();
- ASSERT_THROWS(
- keyManager()->getKeysForValidation(operationContext(), 1, LogicalTime(Timestamp(100, 0))),
- DBException);
+ ASSERT_GT(numTimesAdvanced, 0);
}
TEST_F(KeysManagerShardedTest, GetKeyForValidationErrorsIfKeyDoesntExist) {
@@ -371,6 +381,8 @@ TEST_F(KeysManagerShardedTest, HasSeenKeysIsFalseUntilKeysAreFound) {
class KeysManagerDirectTest : public ConfigServerTestFixture {
protected:
+ KeysManagerDirectTest() : ConfigServerTestFixture(Options{}.useMockClock(true)) {}
+
const UUID kMigrationId1 = UUID::gen();
const UUID kMigrationId2 = UUID::gen();
@@ -381,12 +393,6 @@ protected:
void setUp() override {
ConfigServerTestFixture::setUp();
- auto clockSource = std::make_unique<ClockSourceMock>();
- // Timestamps of "0 seconds" are not allowed, so we must advance our clock mock to the first
- // real second.
- clockSource->advance(Seconds(1));
-
- operationContext()->getServiceContext()->setFastClockSource(std::move(clockSource));
_keyManager = std::make_unique<KeysCollectionManager>(
"dummy", std::make_unique<KeysCollectionClientDirect>(), Seconds(1));
}
diff --git a/src/mongo/db/logical_time_validator_test.cpp b/src/mongo/db/logical_time_validator_test.cpp
index cad15fb328a..96a942ccda5 100644
--- a/src/mongo/db/logical_time_validator_test.cpp
+++ b/src/mongo/db/logical_time_validator_test.cpp
@@ -54,11 +54,11 @@ public:
}
protected:
+ LogicalTimeValidatorTest() : ConfigServerTestFixture(Options{}.useMockClock(true)) {}
+
void setUp() override {
ConfigServerTestFixture::setUp();
- auto clockSource = std::make_unique<ClockSourceMock>();
- operationContext()->getServiceContext()->setFastClockSource(std::move(clockSource));
auto catalogClient = std::make_unique<KeysCollectionClientSharded>(
Grid::get(operationContext())->catalogClient());
diff --git a/src/mongo/db/op_observer_impl_test.cpp b/src/mongo/db/op_observer_impl_test.cpp
index a4bff71f00b..db67426378f 100644
--- a/src/mongo/db/op_observer_impl_test.cpp
+++ b/src/mongo/db/op_observer_impl_test.cpp
@@ -192,6 +192,8 @@ public:
}
protected:
+ explicit OpObserverTest(Options options = {}) : ServiceContextMongoDTest(std::move(options)) {}
+
// Assert that the oplog has the expected number of entries, and return them
std::vector<BSONObj> getNOplogEntries(OperationContext* opCtx, int numExpected) {
std::vector<BSONObj> allOplogEntries;
@@ -847,6 +849,9 @@ public:
}
protected:
+ // TODO (SERVER-65219): Use wiredTiger.
+ OpObserverTxnParticipantTest() : OpObserverTest(Options{}.engine("ephemeralForTest")) {}
+
Session* session() {
return OperationContextSession::get(opCtx());
}
diff --git a/src/mongo/db/query/classic_stage_builder_test.cpp b/src/mongo/db/query/classic_stage_builder_test.cpp
index 407cd67e426..cb4efe466dc 100644
--- a/src/mongo/db/query/classic_stage_builder_test.cpp
+++ b/src/mongo/db/query/classic_stage_builder_test.cpp
@@ -44,8 +44,9 @@ const static NamespaceString kNss("db.dummy");
class ClassicStageBuilderTest : public ServiceContextMongoDTest {
public:
+ ClassicStageBuilderTest() : ServiceContextMongoDTest(Options{}.useMockClock(true)) {}
+
void setUp() {
- getServiceContext()->setFastClockSource(std::make_unique<ClockSourceMock>());
_opCtx = makeOperationContext();
_workingSet = std::make_unique<WorkingSet>();
}
diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript
index 2f419fcdf60..07b2e725e95 100644
--- a/src/mongo/db/repl/SConscript
+++ b/src/mongo/db/repl/SConscript
@@ -1643,7 +1643,6 @@ if wiredtiger:
'roll_back_local_operations_test.cpp',
'rollback_checker_test.cpp',
'rollback_impl_test.cpp',
- 'rs_rollback_test.cpp',
'scatter_gather_test.cpp',
'speculative_majority_read_info_test.cpp',
'split_horizon_test.cpp',
diff --git a/src/mongo/db/repl/idempotency_test_fixture.h b/src/mongo/db/repl/idempotency_test_fixture.h
index 3c79dc60a0e..93766f8d51e 100644
--- a/src/mongo/db/repl/idempotency_test_fixture.h
+++ b/src/mongo/db/repl/idempotency_test_fixture.h
@@ -89,7 +89,7 @@ StringBuilder& operator<<(StringBuilder& sb, const CollectionState& state);
class IdempotencyTest : public OplogApplierImplTest {
public:
- IdempotencyTest() : OplogApplierImplTest("wiredTiger") {
+ IdempotencyTest() {
globalFailPointRegistry()
.find("doUntimestampedWritesForIdempotencyTests")
->setMode(FailPoint::alwaysOn);
diff --git a/src/mongo/db/repl/mock_repl_coord_server_fixture.cpp b/src/mongo/db/repl/mock_repl_coord_server_fixture.cpp
index bc8704c8622..9a76ffc13b4 100644
--- a/src/mongo/db/repl/mock_repl_coord_server_fixture.cpp
+++ b/src/mongo/db/repl/mock_repl_coord_server_fixture.cpp
@@ -47,6 +47,7 @@
#include "mongo/db/repl/storage_interface_mock.h"
#include "mongo/db/service_context.h"
#include "mongo/db/service_context_d_test_fixture.h"
+#include "mongo/db/storage/snapshot_manager.h"
namespace mongo {
@@ -90,6 +91,14 @@ void MockReplCoordServerFixture::setUp() {
repl::DropPendingCollectionReaper::set(
service,
std::make_unique<repl::DropPendingCollectionReaper>(repl::StorageInterface::get(service)));
+
+ // Set a committed snapshot so that we can perform majority reads.
+ WriteUnitOfWork wuow{_opCtx.get()};
+ if (auto snapshotManager =
+ _opCtx->getServiceContext()->getStorageEngine()->getSnapshotManager()) {
+ snapshotManager->setCommittedSnapshot(repl::getNextOpTime(_opCtx.get()).getTimestamp());
+ }
+ wuow.commit();
}
void MockReplCoordServerFixture::insertOplogEntry(const repl::OplogEntry& entry) {
diff --git a/src/mongo/db/repl/mock_repl_coord_server_fixture.h b/src/mongo/db/repl/mock_repl_coord_server_fixture.h
index 7f52f4a3f21..e0859800f63 100644
--- a/src/mongo/db/repl/mock_repl_coord_server_fixture.h
+++ b/src/mongo/db/repl/mock_repl_coord_server_fixture.h
@@ -57,6 +57,10 @@ public:
OperationContext* opCtx();
+protected:
+ explicit MockReplCoordServerFixture(Options options = {})
+ : ServiceContextMongoDTest(std::move(options)) {}
+
private:
ServiceContext::UniqueOperationContext _opCtx;
repl::StorageInterfaceMock* _storageInterface;
diff --git a/src/mongo/db/repl/oplog_applier_impl_test_fixture.h b/src/mongo/db/repl/oplog_applier_impl_test_fixture.h
index 7013192fba9..e1b188232ae 100644
--- a/src/mongo/db/repl/oplog_applier_impl_test_fixture.h
+++ b/src/mongo/db/repl/oplog_applier_impl_test_fixture.h
@@ -195,12 +195,11 @@ public:
};
class OplogApplierImplTest : public ServiceContextMongoDTest {
-public:
- OplogApplierImplTest(){};
- OplogApplierImplTest(std::string storageEngine)
- : ServiceContextMongoDTest(std::move(storageEngine)){};
-
protected:
+ // TODO (SERVER-65297): Use wiredTiger.
+ explicit OplogApplierImplTest()
+ : ServiceContextMongoDTest(Options{}.engine("ephemeralForTest")) {}
+
void _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::Error expectedError,
const OplogEntry& op,
bool expectedApplyOpCalled);
diff --git a/src/mongo/db/repl/primary_only_service_test_fixture.h b/src/mongo/db/repl/primary_only_service_test_fixture.h
index 906cbd15297..c72a2fe85e1 100644
--- a/src/mongo/db/repl/primary_only_service_test_fixture.h
+++ b/src/mongo/db/repl/primary_only_service_test_fixture.h
@@ -54,6 +54,9 @@ public:
void tearDown() override;
protected:
+ explicit PrimaryOnlyServiceMongoDTest(Options options = {})
+ : ServiceContextMongoDTest(std::move(options)) {}
+
void startup(OperationContext* opCtx);
void shutdown();
diff --git a/src/mongo/db/repl/replication_consistency_markers_impl_test.cpp b/src/mongo/db/repl/replication_consistency_markers_impl_test.cpp
index 465289de440..3d58ef476e4 100644
--- a/src/mongo/db/repl/replication_consistency_markers_impl_test.cpp
+++ b/src/mongo/db/repl/replication_consistency_markers_impl_test.cpp
@@ -203,7 +203,7 @@ TEST_F(ReplicationConsistencyMarkersTest, ReplicationConsistencyMarkers) {
OpTime startOpTime({Seconds(123), 0}, 1LL);
OpTime endOpTime({Seconds(456), 0}, 1LL);
consistencyMarkers.setAppliedThrough(opCtx, startOpTime);
- consistencyMarkers.setMinValid(opCtx, endOpTime);
+ consistencyMarkers.setMinValid(opCtx, endOpTime, true /* alwaysAllowUntimestampedWrite */);
consistencyMarkers.setOplogTruncateAfterPoint(opCtx, endOpTime.getTimestamp());
ASSERT_EQ(consistencyMarkers.getAppliedThrough(opCtx), startOpTime);
diff --git a/src/mongo/db/repl/replication_coordinator_impl_heartbeat_v1_test.cpp b/src/mongo/db/repl/replication_coordinator_impl_heartbeat_v1_test.cpp
index 6cb6e55609c..d403a7d259f 100644
--- a/src/mongo/db/repl/replication_coordinator_impl_heartbeat_v1_test.cpp
+++ b/src/mongo/db/repl/replication_coordinator_impl_heartbeat_v1_test.cpp
@@ -80,6 +80,8 @@ TEST(ReplSetHeartbeatArgs, AcceptsUnknownField) {
class ReplCoordHBV1Test : public ReplCoordTest {
protected:
+ explicit ReplCoordHBV1Test() : ReplCoordTest(Options{}.useMockClock(true)) {}
+
void assertMemberState(MemberState expected, std::string msg = "");
ReplSetHeartbeatResponse receiveHeartbeatFrom(
const ReplSetConfig& rsConfig,
diff --git a/src/mongo/db/repl/replication_coordinator_mock.cpp b/src/mongo/db/repl/replication_coordinator_mock.cpp
index d396c2c429d..22118c874aa 100644
--- a/src/mongo/db/repl/replication_coordinator_mock.cpp
+++ b/src/mongo/db/repl/replication_coordinator_mock.cpp
@@ -39,6 +39,7 @@
#include "mongo/db/repl/read_concern_args.h"
#include "mongo/db/repl/sync_source_resolver.h"
#include "mongo/db/repl/tenant_migration_decoration.h"
+#include "mongo/db/storage/snapshot_manager.h"
#include "mongo/db/write_concern_options.h"
#include "mongo/util/assert_util.h"
@@ -234,12 +235,23 @@ void ReplicationCoordinatorMock::setMyHeartbeatMessage(const std::string& msg) {
// TODO
}
+void ReplicationCoordinatorMock::_setMyLastAppliedOpTimeAndWallTime(
+ const OpTimeAndWallTime& opTimeAndWallTime) {
+ _myLastAppliedOpTime = opTimeAndWallTime.opTime;
+ _myLastAppliedWallTime = opTimeAndWallTime.wallTime;
+
+ if (auto storageEngine = _service->getStorageEngine()) {
+ if (auto snapshotManager = storageEngine->getSnapshotManager()) {
+ snapshotManager->setCommittedSnapshot(opTimeAndWallTime.opTime.getTimestamp());
+ }
+ }
+}
+
void ReplicationCoordinatorMock::setMyLastAppliedOpTimeAndWallTime(
const OpTimeAndWallTime& opTimeAndWallTime) {
stdx::lock_guard<Mutex> lk(_mutex);
- _myLastAppliedOpTime = opTimeAndWallTime.opTime;
- _myLastAppliedWallTime = opTimeAndWallTime.wallTime;
+ _setMyLastAppliedOpTimeAndWallTime(opTimeAndWallTime);
}
void ReplicationCoordinatorMock::setMyLastDurableOpTimeAndWallTime(
@@ -255,8 +267,7 @@ void ReplicationCoordinatorMock::setMyLastAppliedOpTimeAndWallTimeForward(
stdx::lock_guard<Mutex> lk(_mutex);
if (opTimeAndWallTime.opTime > _myLastAppliedOpTime) {
- _myLastAppliedOpTime = opTimeAndWallTime.opTime;
- _myLastAppliedWallTime = opTimeAndWallTime.wallTime;
+ _setMyLastAppliedOpTimeAndWallTime(opTimeAndWallTime);
}
}
diff --git a/src/mongo/db/repl/replication_coordinator_mock.h b/src/mongo/db/repl/replication_coordinator_mock.h
index a77d5ad4982..8e48a9bd8d7 100644
--- a/src/mongo/db/repl/replication_coordinator_mock.h
+++ b/src/mongo/db/repl/replication_coordinator_mock.h
@@ -420,6 +420,8 @@ public:
virtual WriteConcernTagChanges* getWriteConcernTagChanges() override;
private:
+ void _setMyLastAppliedOpTimeAndWallTime(const OpTimeAndWallTime& opTimeAndWallTime);
+
ServiceContext* const _service;
ReplSettings _settings;
StorageInterface* _storage = nullptr;
diff --git a/src/mongo/db/repl/replication_coordinator_test_fixture.cpp b/src/mongo/db/repl/replication_coordinator_test_fixture.cpp
index ced8e4499dc..d1bcdcc92ab 100644
--- a/src/mongo/db/repl/replication_coordinator_test_fixture.cpp
+++ b/src/mongo/db/repl/replication_coordinator_test_fixture.cpp
@@ -81,7 +81,7 @@ BSONObj ReplCoordTest::addProtocolVersion(const BSONObj& configDoc, int protocol
return builder.obj();
}
-ReplCoordTest::ReplCoordTest() {
+ReplCoordTest::ReplCoordTest(Options options) : ServiceContextMongoDTest(std::move(options)) {
_settings.setReplSetString("mySet/node1:12345,node2:54321");
}
@@ -167,8 +167,6 @@ void ReplCoordTest::init() {
replicationProcess,
_storageInterface,
seed);
- service->setFastClockSource(std::make_unique<ClockSourceMock>());
- service->setPreciseClockSource(std::make_unique<ClockSourceMock>());
}
void ReplCoordTest::init(const ReplSettings& settings) {
diff --git a/src/mongo/db/repl/replication_coordinator_test_fixture.h b/src/mongo/db/repl/replication_coordinator_test_fixture.h
index 79845ffcfa1..ad1e52a1af3 100644
--- a/src/mongo/db/repl/replication_coordinator_test_fixture.h
+++ b/src/mongo/db/repl/replication_coordinator_test_fixture.h
@@ -92,7 +92,7 @@ public:
}
protected:
- ReplCoordTest();
+ explicit ReplCoordTest(Options options = Options{}.useMockClock(true));
virtual ~ReplCoordTest();
/**
diff --git a/src/mongo/db/repl/replication_recovery_test.cpp b/src/mongo/db/repl/replication_recovery_test.cpp
index 7b32092e747..2107eaff181 100644
--- a/src/mongo/db/repl/replication_recovery_test.cpp
+++ b/src/mongo/db/repl/replication_recovery_test.cpp
@@ -136,6 +136,9 @@ public:
class ReplicationRecoveryTest : public ServiceContextMongoDTest {
protected:
+ // TODO (SERVER-65304): Use wiredTiger.
+ ReplicationRecoveryTest() : ServiceContextMongoDTest(Options{}.engine("ephemeralForTest")) {}
+
OperationContext* getOperationContext() {
return _opCtx.get();
}
diff --git a/src/mongo/db/repl/rollback_impl_test.cpp b/src/mongo/db/repl/rollback_impl_test.cpp
index afab6b658a7..af9e2d85dad 100644
--- a/src/mongo/db/repl/rollback_impl_test.cpp
+++ b/src/mongo/db/repl/rollback_impl_test.cpp
@@ -152,6 +152,9 @@ private:
friend class RollbackImplTest::Listener;
protected:
+ // TODO (SERVER-65305): Use wiredTiger.
+ RollbackImplTest() : RollbackTest(Options{}.engine("ephemeralForTest")) {}
+
/**
* Creates a new mock collection with name 'nss' via the StorageInterface and associates 'uuid'
* with the new collection in the CollectionCatalog. There must not already exist a collection
diff --git a/src/mongo/db/repl/rollback_test_fixture.cpp b/src/mongo/db/repl/rollback_test_fixture.cpp
index b4a064a7bce..eaf3e1152f4 100644
--- a/src/mongo/db/repl/rollback_test_fixture.cpp
+++ b/src/mongo/db/repl/rollback_test_fixture.cpp
@@ -296,75 +296,5 @@ StatusWith<BSONObj> RollbackSourceMock::getCollectionInfoByUUID(const std::strin
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::getCollectionInfoByUUID(
- const std::string& db, const UUID& uuid) const {
- return BSON("options" << collOptionsObj << "info" << BSON("uuid" << uuid));
-}
-
-void RollbackResyncsCollectionOptionsTest::resyncCollectionOptionsTest(
- CollectionOptions localCollOptions, BSONObj remoteCollOptionsObj) {
- resyncCollectionOptionsTest(localCollOptions,
- remoteCollOptionsObj,
- BSON("collMod"
- << "coll"
- << "validationLevel"
- << "strict"),
- "coll");
-}
-void RollbackResyncsCollectionOptionsTest::resyncCollectionOptionsTest(
- CollectionOptions localCollOptions,
- BSONObj remoteCollOptionsObj,
- BSONObj collModCmd,
- std::string collName) {
- createOplog(_opCtx.get());
-
- auto dbName = "test";
- auto nss = NamespaceString(dbName, collName);
-
- auto coll = _createCollection(_opCtx.get(), nss.toString(), localCollOptions);
-
- auto commonOpUuid = unittest::assertGet(UUID::parse("f005ba11-cafe-bead-f00d-123456789abc"));
- auto commonOpBson = BSON("ts" << Timestamp(1, 1) << "t" << 1LL << "op"
- << "n"
- << "o" << BSONObj() << "ns"
- << "rollback_test.test"
- << "wall" << Date_t() << "ui" << commonOpUuid);
-
- auto commonOperation = std::make_pair(commonOpBson, RecordId(1));
-
- auto collectionModificationOperation =
- makeCommandOp(Timestamp(Seconds(2), 0), coll->uuid(), 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()));
-
- // Make sure the collection options are correct.
- AutoGetCollectionForReadCommand autoColl(_opCtx.get(), NamespaceString(nss.toString()));
- auto collAfterRollbackOptions = autoColl->getCollectionOptions();
-
- 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 bae1e9293b4..9bb4103b656 100644
--- a/src/mongo/db/repl/rollback_test_fixture.h
+++ b/src/mongo/db/repl/rollback_test_fixture.h
@@ -57,7 +57,7 @@ namespace repl {
*/
class RollbackTest : public ServiceContextMongoDTest {
public:
- RollbackTest() = default;
+ explicit RollbackTest(Options options = {}) : ServiceContextMongoDTest(std::move(options)) {}
/**
* Initializes the service context and task executor.
@@ -294,42 +294,5 @@ private:
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.
- *
- * If no command is provided, a collMod operation with a 'validationLevel' 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> getCollectionInfoByUUID(const std::string& db,
- const UUID& uuid) const override;
-
- BSONObj collOptionsObj;
- };
-
-public:
- void resyncCollectionOptionsTest(CollectionOptions localCollOptions,
- BSONObj remoteCollOptionsObj,
- BSONObj collModCmd,
- std::string collName);
- void resyncCollectionOptionsTest(CollectionOptions localCollOptions,
- BSONObj remoteCollOptionsObj);
-};
-
} // namespace repl
} // namespace mongo
diff --git a/src/mongo/db/repl/rs_rollback_test.cpp b/src/mongo/db/repl/rs_rollback_test.cpp
deleted file mode 100644
index cdeff56a1d5..00000000000
--- a/src/mongo/db/repl/rs_rollback_test.cpp
+++ /dev/null
@@ -1,2971 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kTest
-
-#include "mongo/platform/basic.h"
-
-#include <initializer_list>
-#include <memory>
-#include <utility>
-
-#include "mongo/db/catalog/collection_catalog.h"
-#include "mongo/db/catalog/database_holder.h"
-#include "mongo/db/catalog/drop_indexes.h"
-#include "mongo/db/catalog/index_catalog.h"
-#include "mongo/db/client.h"
-#include "mongo/db/concurrency/d_concurrency.h"
-#include "mongo/db/db_raii.h"
-#include "mongo/db/dbhelpers.h"
-#include "mongo/db/index/index_descriptor.h"
-#include "mongo/db/index_builds_coordinator.h"
-#include "mongo/db/jsobj.h"
-#include "mongo/db/namespace_string.h"
-#include "mongo/db/op_observer_noop.h"
-#include "mongo/db/op_observer_registry.h"
-#include "mongo/db/read_write_concern_defaults.h"
-#include "mongo/db/repl/drop_pending_collection_reaper.h"
-#include "mongo/db/repl/oplog.h"
-#include "mongo/db/repl/oplog_interface.h"
-#include "mongo/db/repl/oplog_interface_mock.h"
-#include "mongo/db/repl/rollback_source.h"
-#include "mongo/db/repl/rollback_test_fixture.h"
-#include "mongo/db/repl/rs_rollback.h"
-#include "mongo/db/s/shard_identity_rollback_notifier.h"
-#include "mongo/unittest/death_test.h"
-#include "mongo/unittest/unittest.h"
-#include "mongo/util/net/hostandport.h"
-
-namespace mongo {
-namespace {
-
-using namespace mongo::repl;
-using namespace mongo::repl::rollback_internal;
-
-const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2;
-
-class RSRollbackTest : public RollbackTest {};
-
-
-OplogInterfaceMock::Operation makeNoopOplogEntryAndRecordId(Seconds seconds) {
- OpTime ts(Timestamp(seconds, 0), 0);
- return std::make_pair(BSON("ts" << ts.getTimestamp()), RecordId(1));
-}
-
-OplogInterfaceMock::Operation makeDropIndexOplogEntry(const CollectionPtr& collection,
- BSONObj key,
- std::string indexName,
- int time) {
- auto indexSpec =
- BSON("key" << key << "name" << indexName << "v" << static_cast<int>(kIndexVersion));
-
- return std::make_pair(
- BSON("ts" << Timestamp(Seconds(time), 0) << "op"
- << "c"
- << "ui" << collection->uuid() << "ns"
- << "test.$cmd"
- << "o" << BSON("dropIndexes" << collection->ns().coll() << "index" << indexName)
- << "o2" << indexSpec << "wall" << Date_t()),
- RecordId(time));
-}
-
-OplogInterfaceMock::Operation makeStartIndexBuildOplogEntry(const CollectionPtr& collection,
- UUID buildUUID,
- BSONObj spec,
- int time) {
- auto entry = BSON("startIndexBuild" << collection->ns().coll() << "indexBuildUUID" << buildUUID
- << "indexes" << BSON_ARRAY(spec));
-
- return std::make_pair(BSON("ts" << Timestamp(Seconds(time), 0) << "op"
- << "c"
- << "ns"
- << "test.$cmd"
- << "ui" << collection->uuid() << "o" << entry << "wall"
- << Date_t()),
- RecordId(time));
-}
-
-OplogInterfaceMock::Operation makeCommitIndexBuildOplogEntry(const CollectionPtr& collection,
- UUID buildUUID,
- BSONObj spec,
- int time) {
- auto entry = BSON("commitIndexBuild" << collection->ns().coll() << "indexBuildUUID" << buildUUID
- << "indexes" << BSON_ARRAY(spec));
-
- return std::make_pair(BSON("ts" << Timestamp(Seconds(time), 0) << "op"
- << "c"
- << "ns"
- << "test.$cmd"
- << "ui" << collection->uuid() << "o" << entry << "wall"
- << Date_t()),
- RecordId(time));
-}
-
-OplogInterfaceMock::Operation makeAbortIndexBuildOplogEntry(const CollectionPtr& collection,
- UUID buildUUID,
- BSONObj spec,
- int time) {
- Status cause = {ErrorCodes::IndexBuildAborted, "test"};
-
- BSONObjBuilder causeBuilder;
- causeBuilder.appendBool("ok", 0);
- cause.serializeErrorToBSON(&causeBuilder);
- auto entry =
- BSON("abortIndexBuild" << collection->ns().coll() << "indexBuildUUID" << buildUUID
- << "indexes" << BSON_ARRAY(spec) << "cause" << causeBuilder.done());
-
- return std::make_pair(BSON("ts" << Timestamp(Seconds(time), 0) << "op"
- << "c"
- << "ns"
- << "test.$cmd"
- << "ui" << collection->uuid() << "o" << entry << "wall"
- << Date_t()),
- RecordId(time));
-}
-
-OplogInterfaceMock::Operation makeCreateIndexOplogEntry(const CollectionPtr& collection,
- BSONObj key,
- std::string indexName,
- int time) {
- auto indexSpec =
- BSON("createIndexes" << collection->ns().coll() << "v" << static_cast<int>(kIndexVersion)
- << "key" << key << "name" << indexName);
-
- return std::make_pair(BSON("ts" << Timestamp(Seconds(time), 0) << "op"
- << "c"
- << "ns"
- << "test.$cmd"
- << "ui" << collection->uuid() << "o" << indexSpec << "wall"
- << Date_t()),
- RecordId(time));
-}
-
-OplogInterfaceMock::Operation makeRenameCollectionOplogEntry(
- const NamespaceString& renameFrom,
- const NamespaceString& renameTo,
- const UUID collectionUUID,
- const boost::optional<UUID>& dropTarget,
- const bool stayTemp,
- OpTime opTime) {
- BSONObjBuilder cmd;
- cmd.append("renameCollection", renameFrom.ns());
- cmd.append("to", renameTo.ns());
- cmd.append("stayTemp", stayTemp);
-
- BSONObj obj = cmd.obj();
-
- if (dropTarget) {
- obj = obj.addField(BSON("dropTarget" << *dropTarget).firstElement());
- }
- return std::make_pair(BSON("ts" << opTime.getTimestamp() << "t" << opTime.getTerm() << "op"
- << "c"
- << "ui" << collectionUUID << "ns" << renameFrom.ns() << "o"
- << obj << "wall" << Date_t()),
- RecordId(opTime.getTimestamp().getSecs()));
-}
-
-BSONObj makeOp(long long seconds) {
- auto uuid = unittest::assertGet(UUID::parse("f005ba11-cafe-bead-f00d-123456789abc"));
- return BSON("ts" << Timestamp(seconds, seconds) << "t" << seconds << "op"
- << "n"
- << "o" << BSONObj() << "ns"
- << "rs_rollback.test"
- << "ui" << uuid << "wall" << Date_t());
-}
-
-int recordId = 0;
-OplogInterfaceMock::Operation makeOpAndRecordId(long long seconds) {
- return std::make_pair(makeOp(seconds), RecordId(++recordId));
-}
-
-// Create an index on an empty collection. Returns the number of indexes that exist on the
-// collection after the given index is created.
-int _createIndexOnEmptyCollection(OperationContext* opCtx,
- Collection* coll,
- NamespaceString nss,
- BSONObj indexSpec) {
- Lock::DBLock dbLock(opCtx, nss.db(), MODE_X);
- auto indexCatalog = coll->getIndexCatalog();
- WriteUnitOfWork wunit(opCtx);
- ASSERT_OK(indexCatalog->createIndexOnEmptyCollection(opCtx, coll, indexSpec).getStatus());
- wunit.commit();
- return indexCatalog->numIndexesReady(opCtx);
-}
-
-TEST_F(RSRollbackTest, InconsistentMinValid) {
- _replicationProcess->getConsistencyMarkers()->setAppliedThrough(
- _opCtx.get(), OpTime(Timestamp(Seconds(1), 0), 0));
- _replicationProcess->getConsistencyMarkers()->setMinValid(_opCtx.get(),
- OpTime(Timestamp(Seconds(2), 0), 0));
- auto status = syncRollback(_opCtx.get(),
- OplogInterfaceMock(),
- RollbackSourceMock(std::make_unique<OplogInterfaceMock>()),
- {},
- {},
- _coordinator,
- _replicationProcess.get());
- ASSERT_EQUALS(ErrorCodes::UnrecoverableRollbackError, status.code());
- ASSERT_STRING_CONTAINS(status.reason(), "unable to determine common point");
-}
-
-TEST_F(RSRollbackTest, OplogStartMissing) {
- OpTime ts(Timestamp(Seconds(1), 0), 0);
- auto operation = std::make_pair(BSON("ts" << ts.getTimestamp()), RecordId());
- OplogInterfaceMock::Operations remoteOperations({operation});
- auto remoteOplog = std::make_unique<OplogInterfaceMock>(remoteOperations);
- ASSERT_EQUALS(ErrorCodes::OplogStartMissing,
- syncRollback(_opCtx.get(),
- OplogInterfaceMock(),
- RollbackSourceMock(std::move(remoteOplog)),
- {},
- {},
- _coordinator,
- _replicationProcess.get())
- .code());
-}
-
-TEST_F(RSRollbackTest, NoRemoteOpLog) {
- OpTime ts(Timestamp(Seconds(1), 0), 0);
- auto operation = std::make_pair(BSON("ts" << ts.getTimestamp()), RecordId());
- auto status = syncRollback(_opCtx.get(),
- OplogInterfaceMock({operation}),
- RollbackSourceMock(std::make_unique<OplogInterfaceMock>()),
- {},
- {},
- _coordinator,
- _replicationProcess.get());
- ASSERT_EQUALS(ErrorCodes::UnrecoverableRollbackError, status.code());
- ASSERT_STRING_CONTAINS(status.reason(), "unable to determine common point");
-}
-
-TEST_F(RSRollbackTest, RemoteGetRollbackIdThrows) {
- OpTime ts(Timestamp(Seconds(1), 0), 0);
- auto operation = std::make_pair(BSON("ts" << ts.getTimestamp()), RecordId());
- class RollbackSourceLocal : public RollbackSourceMock {
- public:
- RollbackSourceLocal(std::unique_ptr<OplogInterface> oplog)
- : RollbackSourceMock(std::move(oplog)) {}
- int getRollbackId() const override {
- uassert(ErrorCodes::UnknownError, "getRollbackId() failed", false);
- }
- };
- ASSERT_THROWS_CODE(syncRollback(_opCtx.get(),
- OplogInterfaceMock({operation}),
- RollbackSourceLocal(std::make_unique<OplogInterfaceMock>()),
- {},
- {},
- _coordinator,
- _replicationProcess.get()),
- AssertionException,
- ErrorCodes::UnknownError);
-}
-
-TEST_F(RSRollbackTest, RemoteGetRollbackIdDiffersFromRequiredRBID) {
- OpTime ts(Timestamp(Seconds(1), 0), 0);
- auto operation = std::make_pair(BSON("ts" << ts.getTimestamp()), RecordId());
-
- class RollbackSourceLocal : public RollbackSourceMock {
- public:
- using RollbackSourceMock::RollbackSourceMock;
- int getRollbackId() const override {
- return 2;
- }
- };
-
- ASSERT_THROWS_CODE(syncRollback(_opCtx.get(),
- OplogInterfaceMock({operation}),
- RollbackSourceLocal(std::make_unique<OplogInterfaceMock>()),
- {},
- 1,
- _coordinator,
- _replicationProcess.get()),
- AssertionException,
- ErrorCodes::duplicateCodeForTest(40506));
-}
-
-TEST_F(RSRollbackTest, BothOplogsAtCommonPoint) {
- createOplog(_opCtx.get());
- auto operation = makeOpAndRecordId(1);
- ASSERT_OK(
- syncRollback(_opCtx.get(),
- OplogInterfaceMock({operation}),
- RollbackSourceMock(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- operation,
- }))),
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
-}
-
-/**
- * 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.
- */
-int _testRollbackDelete(OperationContext* opCtx,
- ReplicationCoordinator* coordinator,
- ReplicationProcess* replicationProcess,
- UUID uuid,
- const BSONObj& documentAtSource,
- const bool collectionAtSourceExists = true) {
- auto commonOperation = makeOpAndRecordId(1);
- auto deleteOperation =
- std::make_pair(BSON("ts" << Timestamp(Seconds(2), 0) << "op"
- << "d"
- << "ui" << uuid << "ns"
- << "test.t"
- << "o" << BSON("_id" << 0) << "wall" << Date_t()),
- RecordId(2));
- class RollbackSourceLocal : public RollbackSourceMock {
- public:
- RollbackSourceLocal(const BSONObj& documentAtSource,
- std::unique_ptr<OplogInterface> oplog,
- const bool collectionAtSourceExists)
- : RollbackSourceMock(std::move(oplog)),
- called(false),
- _documentAtSource(documentAtSource),
- _collectionAtSourceExists(collectionAtSourceExists) {}
- std::pair<BSONObj, NamespaceString> findOneByUUID(const std::string& db,
- UUID uuid,
- const BSONObj& filter) const override {
- called = true;
- if (!_collectionAtSourceExists) {
- uassertStatusOKWithContext(
- Status(ErrorCodes::NamespaceNotFound, "MockNamespaceNotFoundMsg"),
- "find command using UUID failed.");
- }
- return {_documentAtSource, NamespaceString()};
- }
- mutable bool called;
-
- private:
- BSONObj _documentAtSource;
- bool _collectionAtSourceExists;
- };
- RollbackSourceLocal rollbackSource(documentAtSource,
- std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })),
- collectionAtSourceExists);
- ASSERT_OK(syncRollback(opCtx,
- OplogInterfaceMock({deleteOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- coordinator,
- replicationProcess));
- ASSERT_TRUE(rollbackSource.called);
-
- Lock::DBLock dbLock(opCtx, "test", MODE_S);
- Lock::CollectionLock collLock(opCtx, NamespaceString("test.t"), MODE_S);
- auto databaseHolder = DatabaseHolder::get(opCtx);
- auto db = databaseHolder->getDb(opCtx, TenantDatabaseName(boost::none, "test"));
- ASSERT_TRUE(db);
- auto collection = CollectionCatalog::get(opCtx)->lookupCollectionByNamespace(
- opCtx, NamespaceString("test.t"));
- if (!collection) {
- return -1;
- }
- return collection->getRecordStore()->numRecords(opCtx);
-}
-
-TEST_F(RSRollbackTest, RollbackDeleteNoDocumentAtSourceCollectionDoesNotExist) {
- createOplog(_opCtx.get());
- ASSERT_EQUALS(
- -1,
- _testRollbackDelete(
- _opCtx.get(), _coordinator, _replicationProcess.get(), UUID::gen(), BSONObj()));
-}
-
-TEST_F(RSRollbackTest, RollbackDeleteDocCmdCollectionAtSourceDropped) {
- const bool collectionAtSourceExists = false;
- const NamespaceString nss("test.t");
- createOplog(_opCtx.get());
- {
- Lock::DBLock dbLock(_opCtx.get(), nss.db(), MODE_X);
- auto databaseHolder = DatabaseHolder::get(_opCtx.get());
- auto db = databaseHolder->openDb(_opCtx.get(), TenantDatabaseName(boost::none, nss.db()));
- ASSERT_TRUE(db);
- }
- ASSERT_EQUALS(-1,
- _testRollbackDelete(_opCtx.get(),
- _coordinator,
- _replicationProcess.get(),
- UUID::gen(),
- BSONObj(),
- collectionAtSourceExists));
-}
-
-TEST_F(RSRollbackTest, RollbackDeleteNoDocumentAtSourceCollectionExistsNonCapped) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- auto coll = _createCollection(_opCtx.get(), "test.t", options);
- _testRollbackDelete(
- _opCtx.get(), _coordinator, _replicationProcess.get(), coll->uuid(), BSONObj());
- ASSERT_EQUALS(
- 0,
- _testRollbackDelete(
- _opCtx.get(), _coordinator, _replicationProcess.get(), coll->uuid(), BSONObj()));
-}
-
-TEST_F(RSRollbackTest, RollbackDeleteNoDocumentAtSourceCollectionExistsCapped) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- options.capped = true;
- auto coll = _createCollection(_opCtx.get(), "test.t", options);
- ASSERT_EQUALS(
- 0,
- _testRollbackDelete(
- _opCtx.get(), _coordinator, _replicationProcess.get(), coll->uuid(), BSONObj()));
-}
-
-TEST_F(RSRollbackTest, RollbackDeleteRestoreDocument) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- auto coll = _createCollection(_opCtx.get(), "test.t", options);
- BSONObj doc = BSON("_id" << 0 << "a" << 1);
- _testRollbackDelete(_opCtx.get(), _coordinator, _replicationProcess.get(), coll->uuid(), doc);
- ASSERT_EQUALS(1,
- _testRollbackDelete(
- _opCtx.get(), _coordinator, _replicationProcess.get(), coll->uuid(), doc));
-}
-
-TEST_F(RSRollbackTest, RollbackInsertDocumentWithNoId) {
- createOplog(_opCtx.get());
- auto commonOperation = makeOpAndRecordId(1);
- auto insertDocumentOperation =
- std::make_pair(BSON("ts" << Timestamp(Seconds(2), 0) << "op"
- << "i"
- << "ui" << UUID::gen() << "ns"
- << "test.t"
- << "wall" << Date_t() << "o" << BSON("a" << 1)),
- RecordId(2));
- class RollbackSourceLocal : public RollbackSourceMock {
- public:
- RollbackSourceLocal(std::unique_ptr<OplogInterface> oplog)
- : RollbackSourceMock(std::move(oplog)), called(false) {}
- BSONObj findOne(const NamespaceString& nss, const BSONObj& filter) const {
- called = true;
- return BSONObj();
- }
- mutable bool called;
-
- private:
- BSONObj _documentAtSource;
- };
- RollbackSourceLocal rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
- startCapturingLogMessages();
- auto status = syncRollback(_opCtx.get(),
- OplogInterfaceMock({insertDocumentOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get());
- stopCapturingLogMessages();
- ASSERT_EQUALS(ErrorCodes::UnrecoverableRollbackError, status.code());
- ASSERT_STRING_CONTAINS(status.reason(), "unable to determine common point");
- ASSERT_EQUALS(1, countTextFormatLogLinesContaining("Cannot roll back op with no _id"));
- ASSERT_FALSE(rollbackSource.called);
-}
-
-TEST_F(RSRollbackTest, RollbackCreateIndexCommand) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- NamespaceString nss("test", "coll");
- auto collection = _createCollection(_opCtx.get(), nss.toString(), options);
- auto indexSpec =
- BSON("v" << static_cast<int>(kIndexVersion) << "key" << BSON("a" << 1) << "name"
- << "a_1");
-
- int numIndexes = _createIndexOnEmptyCollection(_opCtx.get(), collection, nss, indexSpec);
- ASSERT_EQUALS(2, numIndexes);
-
- auto commonOperation = makeOpAndRecordId(1);
- auto createIndexOperation = makeCreateIndexOplogEntry(collection, BSON("a" << 1), "a_1", 2);
-
- // Collection pointer will be stale after rollback
- collection = nullptr;
-
- // Repeat index creation operation and confirm that rollback attempts to drop index just once.
- // This can happen when an index is re-created with different options.
- RollbackSourceMock rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
-
- startCapturingLogMessages();
- ASSERT_OK(syncRollback(
- _opCtx.get(),
- OplogInterfaceMock({createIndexOperation, createIndexOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
- stopCapturingLogMessages();
- ASSERT_EQUALS(1, countTextFormatLogLinesContaining("Dropped index in rollback"));
- {
- Lock::DBLock dbLock(_opCtx.get(), nss.db(), MODE_S);
- auto indexCatalog = CollectionCatalog::get(_opCtx.get())
- ->lookupCollectionByNamespace(_opCtx.get(), nss)
- ->getIndexCatalog();
- ASSERT(indexCatalog);
- ASSERT_EQUALS(1, indexCatalog->numIndexesReady(_opCtx.get()));
- }
-}
-
-TEST_F(RSRollbackTest, RollbackCreateIndexCommandIndexNotInCatalog) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- NamespaceString nss("test.t");
- auto collection = _createCollection(_opCtx.get(), nss, options);
- auto indexSpec = BSON("key" << BSON("a" << 1) << "name"
- << "a_1");
- // Skip index creation to trigger warning during rollback.
- {
- Lock::DBLock dbLock(_opCtx.get(), nss.db(), MODE_S);
- auto indexCatalog = collection->getIndexCatalog();
- ASSERT(indexCatalog);
- ASSERT_EQUALS(1, indexCatalog->numIndexesReady(_opCtx.get()));
- }
-
- auto commonOperation = makeOpAndRecordId(1);
- auto createIndexOperation = makeCreateIndexOplogEntry(collection, BSON("a" << 1), "a_1", 2);
-
- // Collection pointer will be stale after rollback
- collection = nullptr;
-
- RollbackSourceMock rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
- startCapturingLogMessages();
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock({createIndexOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
- stopCapturingLogMessages();
- ASSERT_EQUALS(1, countTextFormatLogLinesContaining("Rollback failed to drop index"));
- {
- Lock::DBLock dbLock(_opCtx.get(), nss.db(), MODE_S);
- auto indexCatalog = CollectionCatalog::get(_opCtx.get())
- ->lookupCollectionByNamespace(_opCtx.get(), nss)
- ->getIndexCatalog();
- ASSERT(indexCatalog);
- ASSERT_EQUALS(1, indexCatalog->numIndexesReady(_opCtx.get()));
- }
-}
-
-TEST_F(RSRollbackTest, RollbackDropIndexCommandWithOneIndex) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- NamespaceString nss("test.t");
- auto collection = _createCollection(_opCtx.get(), nss, options);
- {
- Lock::DBLock dbLock(_opCtx.get(), nss.db(), MODE_S);
- auto indexCatalog = collection->getIndexCatalog();
- ASSERT(indexCatalog);
- ASSERT_EQUALS(1, indexCatalog->numIndexesReady(_opCtx.get()));
- }
-
- auto commonOperation = makeOpAndRecordId(1);
- auto dropIndexOperation = makeDropIndexOplogEntry(collection, BSON("a" << 1), "a_1", 2);
-
- // Collection pointer will be stale after rollback
- collection = nullptr;
-
- RollbackSourceMock rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock({dropIndexOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
- {
- Lock::DBLock dbLock(_opCtx.get(), nss.db(), MODE_S);
- auto indexCatalog = CollectionCatalog::get(_opCtx.get())
- ->lookupCollectionByNamespace(_opCtx.get(), nss)
- ->getIndexCatalog();
- ASSERT(indexCatalog);
- ASSERT_EQUALS(2, indexCatalog->numIndexesReady(_opCtx.get()));
- }
-}
-
-TEST_F(RSRollbackTest, RollbackDropIndexCommandWithMultipleIndexes) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- NamespaceString nss("test.t");
- auto collection = _createCollection(_opCtx.get(), nss, options);
- {
- Lock::DBLock dbLock(_opCtx.get(), nss.db(), MODE_S);
- auto indexCatalog = collection->getIndexCatalog();
- ASSERT(indexCatalog);
- ASSERT_EQUALS(1, indexCatalog->numIndexesReady(_opCtx.get()));
- }
-
- auto commonOperation = makeOpAndRecordId(1);
-
- auto dropIndexOperation1 = makeDropIndexOplogEntry(collection, BSON("a" << 1), "a_1", 2);
- auto dropIndexOperation2 = makeDropIndexOplogEntry(collection, BSON("b" << 1), "b_1", 3);
-
- // Collection pointer will be stale after rollback
- collection = nullptr;
-
- RollbackSourceMock rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
- ASSERT_OK(syncRollback(
- _opCtx.get(),
- OplogInterfaceMock({dropIndexOperation2, dropIndexOperation1, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
- {
- Lock::DBLock dbLock(_opCtx.get(), nss.db(), MODE_S);
- auto indexCatalog = CollectionCatalog::get(_opCtx.get())
- ->lookupCollectionByNamespace(_opCtx.get(), nss)
- ->getIndexCatalog();
- ASSERT(indexCatalog);
- ASSERT_EQUALS(3, indexCatalog->numIndexesReady(_opCtx.get()));
- }
-}
-
-TEST_F(RSRollbackTest, RollingBackCreateAndDropOfSameIndexIgnoresBothCommands) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- NamespaceString nss("test.t");
- auto collection = _createCollection(_opCtx.get(), nss, options);
-
- {
- Lock::DBLock dbLock(_opCtx.get(), nss.db(), MODE_X);
- auto indexCatalog = collection->getIndexCatalog();
- ASSERT(indexCatalog);
- ASSERT_EQUALS(1, indexCatalog->numIndexesReady(_opCtx.get()));
- }
-
- auto commonOperation = makeOpAndRecordId(1);
-
- auto createIndexOperation = makeCreateIndexOplogEntry(collection, BSON("a" << 1), "a_1", 2);
-
- auto dropIndexOperation = makeDropIndexOplogEntry(collection, BSON("a" << 1), "a_1", 3);
-
- // Collection pointer will be stale after rollback
- collection = nullptr;
-
- RollbackSourceMock rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
-
- ASSERT_OK(syncRollback(
- _opCtx.get(),
- OplogInterfaceMock({dropIndexOperation, createIndexOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
- {
- Lock::DBLock dbLock(_opCtx.get(), nss.db(), MODE_S);
- auto indexCatalog = CollectionCatalog::get(_opCtx.get())
- ->lookupCollectionByNamespace(_opCtx.get(), nss)
- ->getIndexCatalog();
- ASSERT(indexCatalog);
- ASSERT_EQUALS(1, indexCatalog->numIndexesReady(_opCtx.get()));
- auto indexDescriptor = indexCatalog->findIndexByName(_opCtx.get(), "a_1", false);
- ASSERT(!indexDescriptor);
- }
-}
-
-TEST_F(RSRollbackTest, RollingBackCreateIndexAndRenameWithLongName) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- NamespaceString nss("test", "coll");
- auto collection = _createCollection(_opCtx.get(), nss.toString(), options);
-
- auto longName = std::string(115, 'a');
- auto indexSpec = BSON("v" << static_cast<int>(kIndexVersion) << "key" << BSON("b" << 1)
- << "name" << longName);
-
- int numIndexes = _createIndexOnEmptyCollection(_opCtx.get(), collection, nss, indexSpec);
- ASSERT_EQUALS(2, numIndexes);
-
- auto commonOperation = makeOpAndRecordId(1);
-
- auto createIndexOperation = makeCreateIndexOplogEntry(collection, BSON("b" << 1), longName, 2);
-
- // A collection rename will fail if it would cause an index name to become more than 128 bytes.
- // The old collection name plus the index name is not too long, but the new collection name
- // plus the index name is too long.
- auto newName = NamespaceString("test", "collcollcollcollcoll");
- auto renameCollectionOperation = makeRenameCollectionOplogEntry(
- newName, nss, collection->uuid(), boost::none, false, OpTime(Timestamp(Seconds(2), 0), 1));
-
- RollbackSourceMock rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
-
- ASSERT_OK(syncRollback(
- _opCtx.get(),
- OplogInterfaceMock({createIndexOperation, renameCollectionOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
-
- {
- AutoGetCollectionForReadCommand coll(_opCtx.get(), newName);
- auto indexCatalog = coll.getCollection()->getIndexCatalog();
- ASSERT(indexCatalog);
- ASSERT_EQUALS(1, indexCatalog->numIndexesReady(_opCtx.get()));
-
- std::vector<const IndexDescriptor*> indexes;
- indexCatalog->findIndexesByKeyPattern(_opCtx.get(), BSON("b" << 1), false, &indexes);
- ASSERT(indexes.size() == 0);
- }
-}
-
-TEST_F(RSRollbackTest, RollingBackDropAndCreateOfSameIndexNameWithDifferentSpecs) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- NamespaceString nss("test", "coll");
- auto collection = _createCollection(_opCtx.get(), nss.toString(), options);
-
- auto indexSpec =
- BSON("v" << static_cast<int>(kIndexVersion) << "key" << BSON("b" << 1) << "name"
- << "a_1");
-
- int numIndexes = _createIndexOnEmptyCollection(_opCtx.get(), collection, nss, indexSpec);
- ASSERT_EQUALS(2, numIndexes);
-
- auto commonOperation = makeOpAndRecordId(1);
-
- auto dropIndexOperation = makeDropIndexOplogEntry(collection, BSON("a" << 1), "a_1", 2);
-
- auto createIndexOperation = makeCreateIndexOplogEntry(collection, BSON("b" << 1), "a_1", 3);
-
- RollbackSourceMock rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
-
- startCapturingLogMessages();
- ASSERT_OK(syncRollback(
- _opCtx.get(),
- OplogInterfaceMock({createIndexOperation, dropIndexOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
- stopCapturingLogMessages();
- {
- Lock::DBLock dbLock(_opCtx.get(), nss.db(), MODE_S);
- auto indexCatalog = CollectionCatalog::get(_opCtx.get())
- ->lookupCollectionByNamespace(_opCtx.get(), nss)
- ->getIndexCatalog();
- ASSERT(indexCatalog);
- ASSERT_EQUALS(2, indexCatalog->numIndexesReady(_opCtx.get()));
- ASSERT_EQUALS(1, countTextFormatLogLinesContaining("Dropped index in rollback"));
- ASSERT_EQUALS(1, countTextFormatLogLinesContaining("Created index in rollback"));
- std::vector<const IndexDescriptor*> indexes;
- indexCatalog->findIndexesByKeyPattern(_opCtx.get(), BSON("a" << 1), false, &indexes);
- ASSERT(indexes.size() == 1);
- ASSERT(indexes[0]->indexName() == "a_1");
-
- std::vector<const IndexDescriptor*> indexes2;
- indexCatalog->findIndexesByKeyPattern(_opCtx.get(), BSON("b" << 1), false, &indexes2);
- ASSERT(indexes2.size() == 0);
- }
-}
-
-TEST_F(RSRollbackTest, RollbackCreateIndexCommandMissingIndexName) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- auto collection = _createCollection(_opCtx.get(), "test.t", options);
- auto commonOperation = makeOpAndRecordId(1);
- BSONObj command = BSON("createIndexes"
- << "t"
- << "ns"
- << "test.t"
- << "wall" << Date_t() << "v" << static_cast<int>(kIndexVersion) << "key"
- << BSON("a" << 1));
-
- auto createIndexOperation = std::make_pair(BSON("ts" << Timestamp(Seconds(2), 0) << "op"
- << "c"
- << "ns"
- << "test.$cmd"
- << "wall" << Date_t() << "ui"
- << collection->uuid() << "o" << command),
- RecordId(2));
- RollbackSourceMock rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
- startCapturingLogMessages();
- auto status = syncRollback(_opCtx.get(),
- OplogInterfaceMock({createIndexOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get());
- stopCapturingLogMessages();
- ASSERT_EQUALS(ErrorCodes::UnrecoverableRollbackError, status.code());
- ASSERT_STRING_CONTAINS(status.reason(), "unable to determine common point");
- ASSERT_EQUALS(1,
- countTextFormatLogLinesContaining(
- "Missing index name in createIndexes operation on rollback"));
-}
-
-// Generators of standard index keys and names given an index 'id'.
-std::string idxKey(std::string id) {
- return "key_" + id;
-};
-std::string idxName(std::string id) {
- return "index_" + id;
-};
-
-// Create an index spec object given the namespace and the index 'id'.
-BSONObj idxSpec(NamespaceString nss, std::string id) {
- return BSON("v" << static_cast<int>(kIndexVersion) << "key" << BSON(idxKey(id) << 1) << "name"
- << idxName(id));
-}
-
-// Returns the number of indexes that exist on the given collection.
-int numIndexesOnColl(OperationContext* opCtx, NamespaceString nss, const CollectionPtr& coll) {
- Lock::DBLock dbLock(opCtx, nss.db(), MODE_X);
- auto indexCatalog = coll->getIndexCatalog();
- ASSERT(indexCatalog);
- return indexCatalog->numIndexesReady(opCtx);
-}
-
-int numIndexesInProgress(OperationContext* opCtx, NamespaceString nss, const CollectionPtr& coll) {
- Lock::DBLock dbLock(opCtx, nss.db(), MODE_X);
- auto indexCatalog = coll->getIndexCatalog();
- ASSERT(indexCatalog);
- return indexCatalog->numIndexesInProgress(opCtx);
-}
-
-TEST_F(RSRollbackTest, RollbackDropIndexOnCollectionWithTwoExistingIndexes) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- NamespaceString nss("test", "coll");
- auto coll = _createCollection(_opCtx.get(), nss.toString(), options);
-
- // Create the necessary indexes. Index 0 is created and dropped in the sequence of ops that will
- // be rolled back, so we only create index 1.
- int numIndexes = _createIndexOnEmptyCollection(_opCtx.get(), coll, nss, idxSpec(nss, "1"));
- ASSERT_EQUALS(2, numIndexes);
-
- auto commonOp = makeOpAndRecordId(1);
-
- // The ops that will be rolled back.
- auto createIndex0Op = makeCreateIndexOplogEntry(coll, BSON(idxKey("0") << 1), idxName("0"), 2);
- auto createIndex1Op = makeCreateIndexOplogEntry(coll, BSON(idxKey("1") << 1), idxName("1"), 3);
- auto dropIndex0Op = makeDropIndexOplogEntry(coll, BSON(idxKey("0") << 1), idxName("0"), 4);
-
- auto remoteOplog = {commonOp};
- auto localOplog = {dropIndex0Op, createIndex1Op, createIndex0Op, commonOp};
-
- // Set up the mock rollback source and then run rollback.
- RollbackSourceMock rollbackSource(std::make_unique<OplogInterfaceMock>(remoteOplog));
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock(localOplog),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
-
- // Make sure the collection indexes are in the proper state post-rollback.
- ASSERT_EQUALS(
- 1,
- numIndexesOnColl(
- _opCtx.get(),
- nss,
- CollectionCatalog::get(_opCtx.get())->lookupCollectionByNamespace(_opCtx.get(), nss)));
-}
-
-TEST_F(RSRollbackTest, RollbackTwoIndexDropsPrecededByTwoIndexCreationsOnSameCollection) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- NamespaceString nss("test", "coll");
- auto coll = _createCollection(_opCtx.get(), nss.toString(), options);
-
- auto commonOp = makeOpAndRecordId(1);
-
- // The ops that will be rolled back.
- auto createIndex0Op = makeCreateIndexOplogEntry(coll, BSON(idxKey("0") << 1), idxName("0"), 2);
- auto createIndex1Op = makeCreateIndexOplogEntry(coll, BSON(idxKey("1") << 1), idxName("1"), 3);
- auto dropIndex0Op = makeDropIndexOplogEntry(coll, BSON(idxKey("0") << 1), idxName("0"), 4);
- auto dropIndex1Op = makeDropIndexOplogEntry(coll, BSON(idxKey("1") << 1), idxName("1"), 5);
-
- auto remoteOplog = {commonOp};
- auto localOplog = {dropIndex1Op, dropIndex0Op, createIndex1Op, createIndex0Op, commonOp};
-
- // Set up the mock rollback source and then run rollback.
- RollbackSourceMock rollbackSource(std::make_unique<OplogInterfaceMock>(remoteOplog));
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock(localOplog),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
-
- // Make sure the collection indexes are in the proper state post-rollback.
- ASSERT_EQUALS(
- 1,
- numIndexesOnColl(
- _opCtx.get(),
- nss,
- CollectionCatalog::get(_opCtx.get())->lookupCollectionByNamespace(_opCtx.get(), nss)));
-}
-
-TEST_F(RSRollbackTest, RollbackMultipleCreateIndexesOnSameCollection) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- NamespaceString nss("test", "coll");
- auto coll = _createCollection(_opCtx.get(), nss.toString(), options);
-
- auto commonOp = makeOpAndRecordId(1);
-
- // Create all of the necessary indexes.
- _createIndexOnEmptyCollection(_opCtx.get(), coll, nss, idxSpec(nss, "0"));
- _createIndexOnEmptyCollection(_opCtx.get(), coll, nss, idxSpec(nss, "1"));
- _createIndexOnEmptyCollection(_opCtx.get(), coll, nss, idxSpec(nss, "2"));
- ASSERT_EQUALS(4, numIndexesOnColl(_opCtx.get(), nss, coll));
-
- // The ops that will be rolled back.
- auto createIndex0Op = makeCreateIndexOplogEntry(coll, BSON(idxKey("0") << 1), idxName("0"), 2);
- auto createIndex1Op = makeCreateIndexOplogEntry(coll, BSON(idxKey("1") << 1), idxName("1"), 3);
- auto createIndex2Op = makeCreateIndexOplogEntry(coll, BSON(idxKey("2") << 1), idxName("2"), 4);
-
- auto remoteOplog = {commonOp};
- auto localOplog = {createIndex2Op, createIndex1Op, createIndex0Op, commonOp};
-
- // Set up the mock rollback source and then run rollback.
- RollbackSourceMock rollbackSource(std::make_unique<OplogInterfaceMock>(remoteOplog));
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock(localOplog),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
-
- // Make sure the collection indexes are in the proper state post-rollback.
- ASSERT_EQUALS(
- 1,
- numIndexesOnColl(
- _opCtx.get(),
- nss,
- CollectionCatalog::get(_opCtx.get())->lookupCollectionByNamespace(_opCtx.get(), nss)));
-}
-
-TEST_F(RSRollbackTest, RollbackCreateDropRecreateIndexOnCollection) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- NamespaceString nss("test", "coll");
- auto coll = _createCollection(_opCtx.get(), nss.toString(), options);
-
- // Create the necessary indexes. Index 0 is created, dropped, and created again in the
- // sequence of ops, so we create that index.
- auto indexSpec = BSON("v" << static_cast<int>(kIndexVersion) << "key" << BSON(idxKey("0") << 1)
- << "name" << idxName("0"));
-
- int numIndexes = _createIndexOnEmptyCollection(_opCtx.get(), coll, nss, indexSpec);
- ASSERT_EQUALS(2, numIndexes);
-
- auto commonOp = makeOpAndRecordId(1);
-
- // The ops that will be rolled back.
- auto createIndex0Op = makeCreateIndexOplogEntry(coll, BSON(idxKey("0") << 1), idxName("0"), 2);
- auto dropIndex0Op = makeDropIndexOplogEntry(coll, BSON(idxKey("0") << 1), idxName("0"), 3);
- auto createIndex0AgainOp =
- makeCreateIndexOplogEntry(coll, BSON(idxKey("0") << 1), idxName("0"), 4);
-
- auto remoteOplog = {commonOp};
- auto localOplog = {createIndex0AgainOp, dropIndex0Op, createIndex0Op, commonOp};
-
- // Set up the mock rollback source and then run rollback.
- RollbackSourceMock rollbackSource(std::make_unique<OplogInterfaceMock>(remoteOplog));
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock(localOplog),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
-
- // Make sure the collection indexes are in the proper state post-rollback.
- ASSERT_EQUALS(
- 1,
- numIndexesOnColl(
- _opCtx.get(),
- nss,
- CollectionCatalog::get(_opCtx.get())->lookupCollectionByNamespace(_opCtx.get(), nss)));
-}
-
-TEST_F(RSRollbackTest, RollbackCommitIndexBuild) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- NamespaceString nss("test", "coll");
- auto coll = _createCollection(_opCtx.get(), nss.toString(), options);
-
- // Create the necessary index.
- auto indexSpec = BSON("v" << static_cast<int>(kIndexVersion) << "key" << BSON(idxKey("0") << 1)
- << "name" << idxName("0") << "collation"
- << BSON("locale"
- << "fr"));
-
- int numIndexes = _createIndexOnEmptyCollection(_opCtx.get(), coll, nss, indexSpec);
- ASSERT_EQUALS(2, numIndexes);
-
- auto buildUUID = UUID::gen();
- // Store the commit quorum value for the index build in config.system.indexBuilds collection.
- _insertDocument(_opCtx.get(),
- NamespaceString::kIndexBuildEntryNamespace,
- BSON("_id" << buildUUID << "collectionUUID" << options.uuid.get()
- << "indexNames" << BSON_ARRAY(idxName("0")) << "commitQuorum" << 0));
-
- auto commonOp = makeOpAndRecordId(1);
-
- auto commitIndexBuild = makeCommitIndexBuildOplogEntry(coll, buildUUID, indexSpec, 2);
-
- // Roll back a commit oplog entry, which will drop and restart the index build.
- auto remoteOplog = {commonOp};
- auto localOplog = {commitIndexBuild, commonOp};
-
- // Collection pointer will be stale after rollback
- coll = nullptr;
-
- // Set up the mock rollback source and then run rollback.
- RollbackSourceMock rollbackSource(std::make_unique<OplogInterfaceMock>(remoteOplog));
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock(localOplog),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
-
- auto collAfterRollback =
- CollectionCatalog::get(_opCtx.get())->lookupCollectionByNamespace(_opCtx.get(), nss);
-
- // Make sure the collection indexes are in the proper state post-rollback.
- ASSERT_EQUALS(1, numIndexesOnColl(_opCtx.get(), nss, collAfterRollback));
- ASSERT_EQUALS(1, numIndexesInProgress(_opCtx.get(), nss, collAfterRollback));
-
- // Kill the index build we just restarted so the fixture can shut down.
- ASSERT_OK(_coordinator->setFollowerMode(MemberState::RS_ROLLBACK));
- ASSERT(IndexBuildsCoordinator::get(_opCtx.get())
- ->abortIndexBuildByBuildUUID(
- _opCtx.get(), buildUUID, IndexBuildAction::kRollbackAbort, ""));
-}
-
-TEST_F(RSRollbackTest, RollbackAbortIndexBuild) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- NamespaceString nss("test", "coll");
- auto coll = _createCollection(_opCtx.get(), nss.toString(), options);
-
- // Create the necessary index.
- auto indexSpec = BSON("v" << static_cast<int>(kIndexVersion) << "key" << BSON(idxKey("0") << 1)
- << "name" << idxName("0") << "collation"
- << BSON("locale"
- << "fr"));
-
- int numIndexes = _createIndexOnEmptyCollection(_opCtx.get(), coll, nss, indexSpec);
- ASSERT_EQUALS(2, numIndexes);
-
- auto buildUUID = UUID::gen();
- // Store the commit quorum value for the index build in config.system.indexBuilds collection.
- _insertDocument(_opCtx.get(),
- NamespaceString::kIndexBuildEntryNamespace,
- BSON("_id" << buildUUID << "collectionUUID" << options.uuid.get()
- << "indexNames" << BSON_ARRAY(idxName("0")) << "commitQuorum" << 0));
-
- auto commonOp = makeOpAndRecordId(1);
-
- auto abortIndexBuild = makeAbortIndexBuildOplogEntry(coll, buildUUID, indexSpec, 2);
-
- // Roll back an abort oplog entry, which will drop and restart the index build.
- auto remoteOplog = {commonOp};
- auto localOplog = {abortIndexBuild, commonOp};
-
- // Collection pointer will be stale after rollback
- coll = nullptr;
-
- // Set up the mock rollback source and then run rollback.
- RollbackSourceMock rollbackSource(std::make_unique<OplogInterfaceMock>(remoteOplog));
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock(localOplog),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
-
- auto collAfterRollback =
- CollectionCatalog::get(_opCtx.get())->lookupCollectionByNamespace(_opCtx.get(), nss);
-
- // Make sure the collection indexes are in the proper state post-rollback.
- ASSERT_EQUALS(1, numIndexesOnColl(_opCtx.get(), nss, collAfterRollback));
- ASSERT_EQUALS(1, numIndexesInProgress(_opCtx.get(), nss, collAfterRollback));
-
- // Kill the index build we just restarted so the fixture can shut down.
- ASSERT_OK(_coordinator->setFollowerMode(MemberState::RS_ROLLBACK));
- ASSERT(IndexBuildsCoordinator::get(_opCtx.get())
- ->abortIndexBuildByBuildUUID(
- _opCtx.get(), buildUUID, IndexBuildAction::kRollbackAbort, ""));
-}
-
-TEST_F(RSRollbackTest, AbortedIndexBuildsAreRestarted) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- NamespaceString nss("test", "coll");
- auto coll = _createCollection(_opCtx.get(), nss.toString(), options);
-
- // Create the necessary index.
- auto indexSpec = BSON("v" << static_cast<int>(kIndexVersion) << "key" << BSON(idxKey("0") << 1)
- << "name" << idxName("0") << "collation"
- << BSON("locale"
- << "fr"));
-
- int numIndexes = _createIndexOnEmptyCollection(_opCtx.get(), coll, nss, indexSpec);
- ASSERT_EQUALS(2, numIndexes);
-
- auto buildUUID = UUID::gen();
- // Store the commit quorum value for the index build in config.system.indexBuilds collection.
- _insertDocument(_opCtx.get(),
- NamespaceString::kIndexBuildEntryNamespace,
- BSON("_id" << buildUUID << "collectionUUID" << options.uuid.get()
- << "indexNames" << BSON_ARRAY(idxName("0")) << "commitQuorum" << 0));
-
- auto commonOp = makeOpAndRecordId(1);
-
- // Don't roll-back anything.
- auto remoteOplog = {commonOp};
- auto localOplog = {commonOp};
-
- // Even though the index has already completed, simulate that we aborted the index build before
- // rollback. We expect the index to be dropped and rebuilt.
- IndexBuildDetails build(coll->uuid());
- build.indexSpecs.push_back(indexSpec);
-
- IndexBuilds abortedBuilds{{buildUUID, build}};
-
- // Collection pointer will be stale after rollback
- coll = nullptr;
-
- // Set up the mock rollback source and then run rollback.
- RollbackSourceMock rollbackSource(std::make_unique<OplogInterfaceMock>(remoteOplog));
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock(localOplog),
- rollbackSource,
- abortedBuilds,
- {},
- _coordinator,
- _replicationProcess.get()));
-
- auto collAfterRollback =
- CollectionCatalog::get(_opCtx.get())->lookupCollectionByNamespace(_opCtx.get(), nss);
-
- // Make sure the collection indexes are in the proper state post-rollback.
- ASSERT_EQUALS(1, numIndexesOnColl(_opCtx.get(), nss, collAfterRollback));
- ASSERT_EQUALS(1, numIndexesInProgress(_opCtx.get(), nss, collAfterRollback));
-
- // Kill the index build we just restarted so the fixture can shut down.
- ASSERT_OK(_coordinator->setFollowerMode(MemberState::RS_ROLLBACK));
- ASSERT(IndexBuildsCoordinator::get(_opCtx.get())
- ->abortIndexBuildByBuildUUID(
- _opCtx.get(), buildUUID, IndexBuildAction::kRollbackAbort, ""));
-}
-
-TEST_F(RSRollbackTest, AbortedIndexBuildsAreNotRestartedWhenStartIsRolledBack) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- NamespaceString nss("test", "coll");
- auto coll = _createCollection(_opCtx.get(), nss.toString(), options);
-
- // Create the necessary index.
- auto indexSpec = BSON("v" << static_cast<int>(kIndexVersion) << "key" << BSON(idxKey("0") << 1)
- << "name" << idxName("0") << "collation"
- << BSON("locale"
- << "fr"));
-
- int numIndexes = _createIndexOnEmptyCollection(_opCtx.get(), coll, nss, indexSpec);
- ASSERT_EQUALS(2, numIndexes);
-
- auto commonOp = makeOpAndRecordId(1);
-
- // Roll-back a startIndexBuild oplog entry. This will cancel out with the aborted index build,
- // and the index will be dropped after rollback.
- auto buildUUID = UUID::gen();
- auto startIndexBuildOp = makeStartIndexBuildOplogEntry(coll, buildUUID, indexSpec, 2);
-
- auto remoteOplog = {commonOp};
- auto localOplog = {startIndexBuildOp, commonOp};
-
- // Create an index build to abort.
- IndexBuildDetails build(coll->uuid());
- build.indexSpecs.push_back(indexSpec);
- IndexBuilds abortedBuilds{{buildUUID, build}};
-
- // Collection pointer will be stale after rollback
- coll = nullptr;
-
- // Set up the mock rollback source and then run rollback.
- RollbackSourceMock rollbackSource(std::make_unique<OplogInterfaceMock>(remoteOplog));
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock(localOplog),
- rollbackSource,
- abortedBuilds,
- {},
- _coordinator,
- _replicationProcess.get()));
-
- auto collAfterRollback =
- CollectionCatalog::get(_opCtx.get())->lookupCollectionByNamespace(_opCtx.get(), nss);
-
- // The aborted index build should have been dropped.
- ASSERT_EQUALS(1, numIndexesOnColl(_opCtx.get(), nss, collAfterRollback));
- ASSERT_EQUALS(0, numIndexesInProgress(_opCtx.get(), nss, collAfterRollback));
-}
-
-TEST_F(RSRollbackTest, RollbackUnknownCommand) {
- createOplog(_opCtx.get());
- auto commonOperation = makeOpAndRecordId(1);
- auto unknownCommandOperation = std::make_pair(BSON("ts" << Timestamp(Seconds(2), 0) << "op"
- << "c"
- << "ui" << UUID::gen() << "ns"
- << "test.t"
- << "wall" << Date_t() << "o"
- << BSON("emptycapped"
- << "t")),
- RecordId(2));
-
- auto status =
- syncRollback(_opCtx.get(),
- OplogInterfaceMock({unknownCommandOperation, commonOperation}),
- RollbackSourceMock(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- }))),
- {},
- {},
- _coordinator,
- _replicationProcess.get());
- ASSERT_EQUALS(ErrorCodes::UnrecoverableRollbackError, status.code());
- ASSERT_STRING_CONTAINS(status.reason(), "unable to determine common point");
-}
-
-TEST_F(RSRollbackTest, RollbackRenameCollectionInSameDatabaseCommand) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- auto collection = _createCollection(_opCtx.get(), "test.y", options);
- UUID collectionUUID = collection->uuid();
-
- OpTime renameTime = OpTime(Timestamp(2, 0), 5);
-
- auto commonOperation = makeOpAndRecordId(1);
- auto renameCollectionOperation = makeRenameCollectionOplogEntry(NamespaceString("test.x"),
- NamespaceString("test.y"),
- collectionUUID,
- boost::none,
- false,
- renameTime);
-
- RollbackSourceMock rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
-
- {
- AutoGetCollectionForReadCommand renamedColl(_opCtx.get(), NamespaceString("test.y"));
- ASSERT_TRUE(renamedColl.getCollection());
-
- AutoGetCollectionForReadCommand oldCollName(_opCtx.get(), NamespaceString("test.x"));
- ASSERT_FALSE(oldCollName.getCollection());
- }
-
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock({renameCollectionOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
- {
- AutoGetCollectionForReadCommand renamedColl(_opCtx.get(), NamespaceString("test.y"));
- ASSERT_FALSE(renamedColl.getCollection());
-
- AutoGetCollectionForReadCommand oldCollName(_opCtx.get(), NamespaceString("test.x"));
- ASSERT_TRUE(oldCollName.getCollection());
-
- // Remote collection options should have been empty.
- auto collAfterRollbackOptions = oldCollName->getCollectionOptions();
- ASSERT_BSONOBJ_EQ(BSON("uuid" << *options.uuid), collAfterRollbackOptions.toBSON());
- }
-}
-
-TEST_F(RSRollbackTest,
- RollingBackRenameCollectionFromTempToPermanentCollectionSetsCollectionOptionToTemp) {
- createOplog(_opCtx.get());
-
- auto renameFromNss = NamespaceString("test.renameFrom");
- auto renameToNss = NamespaceString("test.renameTo");
-
- CollectionOptions options;
- options.uuid = UUID::gen();
- ASSERT_FALSE(options.temp);
-
- // Create the collection and save its UUID.
- auto collection = _createCollection(_opCtx.get(), renameToNss, options);
- auto collectionUUID = collection->uuid();
-
- class RollbackSourceLocal : public RollbackSourceMock {
- public:
- RollbackSourceLocal(std::unique_ptr<OplogInterface> oplog)
- : RollbackSourceMock(std::move(oplog)) {}
- StatusWith<BSONObj> getCollectionInfoByUUID(const std::string& db, const UUID& uuid) const {
- getCollectionInfoCalled = true;
- return BSON("info" << BSON("uuid" << uuid) << "options" << BSON("temp" << true));
- }
- mutable bool getCollectionInfoCalled = false;
- };
-
- auto commonOperation = makeOpAndRecordId(1);
-
- bool stayTemp = false;
- auto renameCollectionOperation = makeRenameCollectionOplogEntry(NamespaceString(renameFromNss),
- NamespaceString(renameToNss),
- collectionUUID,
- boost::none,
- stayTemp,
- OpTime(Timestamp(2, 0), 5));
-
- RollbackSourceLocal rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
-
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock({renameCollectionOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
-
- ASSERT_TRUE(rollbackSource.getCollectionInfoCalled);
-
- AutoGetCollectionForReadCommand autoColl(_opCtx.get(), NamespaceString(renameFromNss));
- auto collAfterRollbackOptions = autoColl->getCollectionOptions();
- ASSERT_TRUE(collAfterRollbackOptions.temp);
- ASSERT_BSONOBJ_EQ(BSON("uuid" << *options.uuid << "temp" << true),
- collAfterRollbackOptions.toBSON());
-}
-
-TEST_F(RSRollbackTest, RollbackRenameCollectionInDatabaseWithDropTargetTrueCommand) {
- createOplog(_opCtx.get());
-
- OpTime dropTime = OpTime(Timestamp(2, 0), 5);
- auto dpns = NamespaceString("test.y").makeDropPendingNamespace(dropTime);
- CollectionOptions droppedCollOptions;
- droppedCollOptions.uuid = UUID::gen();
- auto droppedColl = _createCollection(_opCtx.get(), dpns, droppedCollOptions);
- _dropPendingCollectionReaper->addDropPendingNamespace(_opCtx.get(), dropTime, dpns);
- auto droppedCollectionUUID = droppedColl->uuid();
-
- CollectionOptions renamedCollOptions;
- renamedCollOptions.uuid = UUID::gen();
- auto renamedCollection = _createCollection(_opCtx.get(), "test.y", renamedCollOptions);
- auto renamedCollectionUUID = renamedCollection->uuid();
-
- auto commonOperation = makeOpAndRecordId(1);
- auto renameCollectionOperation = makeRenameCollectionOplogEntry(NamespaceString("test.x"),
- NamespaceString("test.y"),
- renamedCollectionUUID,
- droppedCollectionUUID,
- false,
- dropTime);
-
- RollbackSourceMock rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
-
- {
- AutoGetCollectionForReadCommand autoCollDropPending(_opCtx.get(), dpns);
- ASSERT_TRUE(autoCollDropPending.getCollection());
-
- AutoGetCollectionForReadCommand renamedColl(_opCtx.get(), NamespaceString("test.y"));
- ASSERT_TRUE(renamedColl.getCollection());
-
- AutoGetCollectionForReadCommand oldCollName(_opCtx.get(), NamespaceString("test.x"));
- ASSERT_FALSE(oldCollName.getCollection());
- }
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock({renameCollectionOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
- {
- AutoGetCollectionForReadCommand autoCollDropPending(_opCtx.get(), dpns);
- ASSERT_FALSE(autoCollDropPending.getCollection());
-
- AutoGetCollectionForReadCommand renamedColl(_opCtx.get(), NamespaceString("test.x"));
- ASSERT_TRUE(renamedColl.getCollection());
- ASSERT_EQUALS(renamedColl.getCollection()->uuid(), renamedCollectionUUID);
-
- AutoGetCollectionForReadCommand droppedColl(_opCtx.get(), NamespaceString("test.y"));
- ASSERT_TRUE(droppedColl.getCollection());
- ASSERT_EQUALS(droppedColl.getCollection()->uuid(), droppedCollectionUUID);
- }
-}
-
-
-void _testRollbackRenamingCollectionsToEachOther(OperationContext* opCtx,
- ReplicationCoordinator* replicationCoordinator,
- ReplicationProcess* replicationProcess,
- const CollectionOptions& coll1Options,
- const CollectionOptions& coll2Options) {
- createOplog(opCtx);
-
- auto collection1 = RollbackTest::_createCollection(opCtx, "test.y", coll1Options);
- auto collection1UUID = collection1->uuid();
-
- auto collection2 = RollbackTest::_createCollection(opCtx, "test.x", coll2Options);
- auto collection2UUID = collection2->uuid();
-
- ASSERT_NOT_EQUALS(collection1UUID, collection2UUID);
-
- auto commonOperation = makeOpAndRecordId(1);
- auto renameCollectionOperationXtoZ = makeRenameCollectionOplogEntry(NamespaceString("test.x"),
- NamespaceString("test.z"),
- collection1UUID,
- boost::none,
- false,
- OpTime(Timestamp(2, 0), 5));
-
- auto renameCollectionOperationYtoX = makeRenameCollectionOplogEntry(NamespaceString("test.y"),
- NamespaceString("test.x"),
- collection2UUID,
- boost::none,
- false,
- OpTime(Timestamp(3, 0), 5));
-
- auto renameCollectionOperationZtoY = makeRenameCollectionOplogEntry(NamespaceString("test.z"),
- NamespaceString("test.y"),
- collection1UUID,
- boost::none,
- false,
- OpTime(Timestamp(4, 0), 5));
-
- RollbackSourceMock rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
-
- ASSERT_OK(syncRollback(opCtx,
- OplogInterfaceMock({renameCollectionOperationZtoY,
- renameCollectionOperationYtoX,
- renameCollectionOperationXtoZ,
- commonOperation}),
- rollbackSource,
- {},
- {},
- replicationCoordinator,
- replicationProcess));
-
- {
-
- AutoGetCollectionForReadCommand coll1(opCtx, NamespaceString("test.x"));
- ASSERT_TRUE(coll1.getCollection());
- ASSERT_EQUALS(coll1.getCollection()->uuid(), collection1UUID);
-
- AutoGetCollectionForReadCommand coll2(opCtx, NamespaceString("test.y"));
- ASSERT_TRUE(coll2.getCollection());
- ASSERT_EQUALS(coll2.getCollection()->uuid(), collection2UUID);
- }
-}
-
-TEST_F(RSRollbackTest, RollbackRenamingCollectionsToEachOtherWithoutValidationOptions) {
- CollectionOptions coll1Options;
- coll1Options.uuid = UUID::gen();
-
- CollectionOptions coll2Options;
- coll2Options.uuid = UUID::gen();
-
- _testRollbackRenamingCollectionsToEachOther(
- _opCtx.get(), _coordinator, _replicationProcess.get(), coll1Options, coll2Options);
-}
-
-TEST_F(RSRollbackTest, RollbackRenamingCollectionsToEachOtherWithValidationOptions) {
- CollectionOptions coll1Options;
- coll1Options.uuid = UUID::gen();
- coll1Options.validator = BSON("x" << BSON("$exists" << 1));
- coll1Options.validationLevel = ValidationLevelEnum::moderate;
- coll1Options.validationAction = ValidationActionEnum::warn;
-
- CollectionOptions coll2Options;
- coll2Options.uuid = UUID::gen();
- coll2Options.validator = BSON("y" << BSON("$exists" << 1));
- coll2Options.validationLevel = ValidationLevelEnum::strict;
- coll2Options.validationAction = ValidationActionEnum::error;
-
- // renameOutOfTheWay() uses a temporary namespace to rename either of the two collections
- // affected by rollback. The temporary namespace should be able to support collections with
- // validation enabled.
- _testRollbackRenamingCollectionsToEachOther(
- _opCtx.get(), _coordinator, _replicationProcess.get(), coll1Options, coll2Options);
-}
-
-TEST_F(RSRollbackTest, RollbackDropCollectionThenRenameCollectionToDroppedCollectionNS) {
- createOplog(_opCtx.get());
-
- CollectionOptions renamedCollOptions;
- renamedCollOptions.uuid = UUID::gen();
- auto renamedCollection = _createCollection(_opCtx.get(), "test.x", renamedCollOptions);
- auto renamedCollectionUUID = renamedCollection->uuid();
-
- OpTime dropTime = OpTime(Timestamp(2, 0), 5);
- auto dpns = NamespaceString("test.x").makeDropPendingNamespace(dropTime);
- CollectionOptions droppedCollOptions;
- droppedCollOptions.uuid = UUID::gen();
- auto droppedCollection = _createCollection(_opCtx.get(), dpns, droppedCollOptions);
- auto droppedCollectionUUID = droppedCollection->uuid();
- _dropPendingCollectionReaper->addDropPendingNamespace(_opCtx.get(), dropTime, dpns);
-
- auto commonOperation = makeOpAndRecordId(1);
-
- auto dropCollectionOperation =
- std::make_pair(BSON("ts" << dropTime.getTimestamp() << "t" << dropTime.getTerm() << "op"
- << "c"
- << "ui" << droppedCollectionUUID << "ns"
- << "test.x"
- << "wall" << Date_t() << "o"
- << BSON("drop"
- << "x")),
- RecordId(2));
-
- auto renameCollectionOperation = makeRenameCollectionOplogEntry(NamespaceString("test.y"),
- NamespaceString("test.x"),
- renamedCollectionUUID,
- boost::none,
- false,
- OpTime(Timestamp(3, 0), 5));
-
- RollbackSourceMock rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
-
- {
- AutoGetCollectionForReadCommand autoCollDropPending(_opCtx.get(), dpns);
- ASSERT_TRUE(autoCollDropPending.getCollection());
- AutoGetCollectionForReadCommand autoCollX(_opCtx.get(), NamespaceString("test.x"));
- ASSERT_TRUE(autoCollX.getCollection());
- AutoGetCollectionForReadCommand autoCollY(_opCtx.get(), NamespaceString("test.y"));
- ASSERT_FALSE(autoCollY.getCollection());
- }
- ASSERT_OK(syncRollback(
- _opCtx.get(),
- OplogInterfaceMock({renameCollectionOperation, dropCollectionOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
-
- {
- AutoGetCollectionForReadCommand autoCollDropPending(_opCtx.get(), dpns);
- ASSERT_FALSE(autoCollDropPending.getCollection());
-
- AutoGetCollectionForReadCommand autoCollX(_opCtx.get(), NamespaceString("test.x"));
- ASSERT_TRUE(autoCollX.getCollection());
- ASSERT_EQUALS(autoCollX.getCollection()->uuid(), droppedCollectionUUID);
-
- AutoGetCollectionForReadCommand autoCollY(_opCtx.get(), NamespaceString("test.y"));
- ASSERT_TRUE(autoCollY.getCollection());
- ASSERT_EQUALS(autoCollY.getCollection()->uuid(), renamedCollectionUUID);
- }
-}
-
-TEST_F(RSRollbackTest, RollbackRenameCollectionThenCreateNewCollectionWithOldName) {
- createOplog(_opCtx.get());
-
- CollectionOptions renamedCollOptions;
- renamedCollOptions.uuid = UUID::gen();
- auto renamedCollection = _createCollection(_opCtx.get(), "test.y", renamedCollOptions);
- auto renamedCollectionUUID = renamedCollection->uuid();
-
- CollectionOptions createdCollOptions;
- createdCollOptions.uuid = UUID::gen();
- auto createdCollection = _createCollection(_opCtx.get(), "test.x", createdCollOptions);
- auto createdCollectionUUID = createdCollection->uuid();
-
- auto commonOperation = makeOpAndRecordId(1);
-
- auto renameCollectionOperation = makeRenameCollectionOplogEntry(NamespaceString("test.x"),
- NamespaceString("test.y"),
- renamedCollectionUUID,
- boost::none,
- false,
- OpTime(Timestamp(2, 0), 5));
-
- auto createCollectionOperation =
- std::make_pair(BSON("ts" << Timestamp(Seconds(3), 0) << "op"
- << "c"
- << "ui" << createdCollectionUUID << "ns"
- << "test.x"
- << "wall" << Date_t() << "o"
- << BSON("create"
- << "x")),
- RecordId(3));
-
-
- RollbackSourceMock rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
-
- {
- AutoGetCollectionForReadCommand renamedColl(_opCtx.get(), NamespaceString("test.y"));
- ASSERT_TRUE(renamedColl.getCollection());
- AutoGetCollectionForReadCommand createdColl(_opCtx.get(), NamespaceString("test.x"));
- ASSERT_TRUE(createdColl.getCollection());
- }
- ASSERT_OK(syncRollback(
- _opCtx.get(),
- OplogInterfaceMock({createCollectionOperation, renameCollectionOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
-
- {
-
- AutoGetCollectionForReadCommand renamedColl(_opCtx.get(), NamespaceString("test.x"));
- ASSERT_TRUE(renamedColl.getCollection());
- ASSERT_EQUALS(renamedColl.getCollection()->uuid(), renamedCollectionUUID);
-
- AutoGetCollectionForReadCommand createdColl(_opCtx.get(), NamespaceString("test.y"));
- ASSERT_FALSE(createdColl.getCollection());
- }
-}
-
-TEST_F(RSRollbackTest, RollbackCollModCommandFailsIfRBIDChangesWhileSyncingCollectionMetadata) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- auto coll = _createCollection(_opCtx.get(), "test.t", options);
-
- auto commonOperation = makeOpAndRecordId(1);
- auto collModOperation = std::make_pair(BSON("ts" << Timestamp(Seconds(2), 0) << "op"
- << "c"
- << "ui" << coll->uuid() << "ns"
- << "test.t"
- << "wall" << Date_t() << "o"
- << BSON("collMod"
- << "t"
- << "validationLevel"
- << "off")),
- RecordId(2));
- class RollbackSourceLocal : public RollbackSourceMock {
- public:
- using RollbackSourceMock::RollbackSourceMock;
- int getRollbackId() const override {
- return getCollectionInfoCalled ? 1 : 0;
- }
- StatusWith<BSONObj> getCollectionInfoByUUID(const std::string& db,
- const UUID& uuid) const override {
- getCollectionInfoCalled = true;
- return BSONObj();
- }
- mutable bool getCollectionInfoCalled = false;
- };
- RollbackSourceLocal rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
-
- ASSERT_THROWS_CODE(syncRollback(_opCtx.get(),
- OplogInterfaceMock({collModOperation, commonOperation}),
- rollbackSource,
- {},
- 0,
- _coordinator,
- _replicationProcess.get()),
- DBException,
- 40508);
- ASSERT(rollbackSource.getCollectionInfoCalled);
-}
-
-TEST_F(RSRollbackTest, RollbackDropDatabaseCommand) {
- createOplog(_opCtx.get());
- auto commonOperation = makeOpAndRecordId(1);
- // 'dropDatabase' operations are special and do not include a UUID field.
- auto dropDatabaseOperation =
- std::make_pair(BSON("ts" << Timestamp(Seconds(2), 0) << "op"
- << "c"
- << "ns"
- << "test.$cmd"
- << "wall" << Date_t() << "o" << BSON("dropDatabase" << 1)),
- RecordId(2));
- RollbackSourceMock rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock({dropDatabaseOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
-}
-
-BSONObj makeApplyOpsOplogEntry(Timestamp ts, std::initializer_list<BSONObj> ops) {
- // applyOps oplog entries are special and do not include a UUID field.
- BSONObjBuilder entry;
- entry << "ts" << ts << "op"
- << "c"
- << "ns"
- << "admin"
- << "wall" << Date_t();
- {
- BSONObjBuilder cmd(entry.subobjStart("o"));
- BSONArrayBuilder subops(entry.subarrayStart("applyOps"));
- for (const auto& op : ops) {
- subops << op;
- }
- }
- return entry.obj();
-}
-
-OpTime getOpTimeFromOplogEntry(const BSONObj& entry) {
- const BSONElement tsElement = entry["ts"];
- const BSONElement termElement = entry["t"];
- ASSERT_EQUALS(bsonTimestamp, tsElement.type()) << entry;
- ASSERT_TRUE(termElement.eoo() || termElement.isNumber()) << entry;
- long long term = 1LL;
- if (!termElement.eoo()) {
- term = termElement.numberLong();
- }
- return OpTime(tsElement.timestamp(), term);
-}
-
-TEST_F(RSRollbackTest, RollbackApplyOpsCommand) {
- createOplog(_opCtx.get());
- CollectionPtr coll;
- CollectionOptions options;
- options.uuid = UUID::gen();
- {
- AutoGetDb autoDb(_opCtx.get(), "test", MODE_X);
- mongo::WriteUnitOfWork wuow(_opCtx.get());
- coll = CollectionCatalog::get(_opCtx.get())
- ->lookupCollectionByNamespace(_opCtx.get(), NamespaceString("test.t"));
- if (!coll) {
- auto db = autoDb.ensureDbExists(_opCtx.get());
- coll = db->createCollection(_opCtx.get(), NamespaceString("test.t"), options);
- }
- ASSERT(coll);
- OpDebug* const nullOpDebug = nullptr;
- ASSERT_OK(coll->insertDocument(
- _opCtx.get(), InsertStatement(BSON("_id" << 1 << "v" << 2)), nullOpDebug, false));
- ASSERT_OK(coll->insertDocument(
- _opCtx.get(), InsertStatement(BSON("_id" << 2 << "v" << 4)), nullOpDebug, false));
- ASSERT_OK(coll->insertDocument(
- _opCtx.get(), InsertStatement(BSON("_id" << 4)), nullOpDebug, false));
- wuow.commit();
- }
- UUID uuid = coll->uuid();
- const auto commonOperation = makeOpAndRecordId(1);
- const auto applyOpsOperation =
- std::make_pair(makeApplyOpsOplogEntry(
- Timestamp(Seconds(2), 0),
- {BSON("op"
- << "u"
- << "ui" << uuid << "ts" << Timestamp(1, 1) << "t" << 1LL << "ns"
- << "test.t"
- << "o2" << BSON("_id" << 1) << "wall" << Date_t() << "o"
- << BSON("_id" << 1 << "v" << 2)),
- BSON("op"
- << "u"
- << "ui" << uuid << "ts" << Timestamp(2, 1) << "t" << 1LL << "ns"
- << "test.t"
- << "o2" << BSON("_id" << 2) << "wall" << Date_t() << "o"
- << BSON("_id" << 2 << "v" << 4)),
- BSON("op"
- << "d"
- << "ui" << uuid << "ts" << Timestamp(3, 1) << "t" << 1LL << "ns"
- << "test.t"
- << "wall" << Date_t() << "o" << BSON("_id" << 3)),
- BSON("op"
- << "i"
- << "ui" << uuid << "ts" << Timestamp(4, 1) << "t" << 1LL << "ns"
- << "test.t"
- << "wall" << Date_t() << "o" << BSON("_id" << 4)),
- // applyOps internal oplog entries are not required
- // to have a timestamp.
- BSON("op"
- << "i"
- << "ui" << uuid << "ts" << Timestamp(4, 1) << "t" << 1LL << "ns"
- << "test.t"
- << "wall" << Date_t() << "o" << BSON("_id" << 4)),
- BSON("op"
- << "i"
- << "ui" << uuid << "t" << 1LL << "ns"
- << "test.t"
- << "wall" << Date_t() << "o" << BSON("_id" << 4)),
- BSON("op"
- << "i"
- << "ui" << uuid << "t" << 1LL << "ns"
- << "test.t"
- << "wall" << Date_t() << "o" << BSON("_id" << 4))}),
- RecordId(2));
-
- class RollbackSourceLocal : public RollbackSourceMock {
- public:
- RollbackSourceLocal(std::unique_ptr<OplogInterface> oplog)
- : RollbackSourceMock(std::move(oplog)) {}
-
- std::pair<BSONObj, NamespaceString> findOneByUUID(const std::string& db,
- UUID uuid,
- const BSONObj& filter) const override {
- int numFields = 0;
- for (const auto& element : filter) {
- ++numFields;
- ASSERT_EQUALS("_id", element.fieldNameStringData()) << filter;
- }
- ASSERT_EQUALS(1, numFields) << filter;
- searchedIds.insert(filter.firstElement().numberInt());
- switch (filter.firstElement().numberInt()) {
- case 1:
- return {BSON("_id" << 1 << "v" << 1), NamespaceString()};
- case 2:
- return {BSON("_id" << 2 << "v" << 3), NamespaceString()};
- case 3:
- return {BSON("_id" << 3 << "v" << 5), NamespaceString()};
- case 4:
- return {};
- }
- FAIL("Unexpected findOne request") << filter;
- return {}; // Unreachable; why doesn't compiler know?
- }
-
- mutable std::multiset<int> searchedIds;
- } rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({commonOperation})));
-
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock({applyOpsOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
- ASSERT_EQUALS(4U, rollbackSource.searchedIds.size());
- ASSERT_EQUALS(1U, rollbackSource.searchedIds.count(1));
- ASSERT_EQUALS(1U, rollbackSource.searchedIds.count(2));
- ASSERT_EQUALS(1U, rollbackSource.searchedIds.count(3));
- ASSERT_EQUALS(1U, rollbackSource.searchedIds.count(4));
-
- AutoGetCollectionForReadCommand acr(_opCtx.get(), NamespaceString("test.t"));
- BSONObj result;
- ASSERT(Helpers::findOne(_opCtx.get(), acr.getCollection(), BSON("_id" << 1), result));
- ASSERT_EQUALS(1, result["v"].numberInt()) << result;
- ASSERT(Helpers::findOne(_opCtx.get(), acr.getCollection(), BSON("_id" << 2), result));
- ASSERT_EQUALS(3, result["v"].numberInt()) << result;
- ASSERT(Helpers::findOne(_opCtx.get(), acr.getCollection(), BSON("_id" << 3), result));
- ASSERT_EQUALS(5, result["v"].numberInt()) << result;
- ASSERT_FALSE(Helpers::findOne(_opCtx.get(), acr.getCollection(), BSON("_id" << 4), result))
- << result;
-}
-
-TEST_F(RSRollbackTest, RollbackCreateCollectionCommand) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- auto coll = _createCollection(_opCtx.get(), "test.t", options);
-
- auto commonOperation = makeOpAndRecordId(1);
- auto createCollectionOperation = std::make_pair(BSON("ts" << Timestamp(Seconds(2), 0) << "op"
- << "c"
- << "ui" << coll->uuid() << "ns"
- << "test.t"
- << "wall" << Date_t() << "o"
- << BSON("create"
- << "t")),
- RecordId(2));
- RollbackSourceMock rollbackSource(
- std::unique_ptr<OplogInterface>(new OplogInterfaceMock({commonOperation})));
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock({createCollectionOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
- {
- Lock::DBLock dbLock(_opCtx.get(), "test", MODE_S);
- auto databaseHolder = DatabaseHolder::get(_opCtx.get());
- auto db = databaseHolder->getDb(_opCtx.get(), TenantDatabaseName(boost::none, "test"));
- ASSERT_TRUE(db);
- ASSERT_FALSE(CollectionCatalog::get(_opCtx.get())
- ->lookupCollectionByNamespace(_opCtx.get(), NamespaceString("test.t")));
- }
-}
-
-TEST_F(RSRollbackTest, RollbackCollectionModificationCommand) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- auto coll = _createCollection(_opCtx.get(), "test.t", options);
-
- auto commonOperation = makeOpAndRecordId(1);
-
- BSONObj collModCmd = BSON("collMod"
- << "t"
- << "validationLevel"
- << "strict");
- auto collectionModificationOperation =
- makeCommandOp(Timestamp(Seconds(2), 0), coll->uuid(), "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> getCollectionInfoByUUID(const std::string& db, const UUID& uuid) const {
- called = true;
- return BSON("options" << BSONObj() << "info" << BSON("uuid" << uuid));
- }
- mutable bool called;
- };
- RollbackSourceLocal rollbackSource(
- std::unique_ptr<OplogInterface>(new OplogInterfaceMock({commonOperation})));
-
- startCapturingLogMessages();
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock({collectionModificationOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
- stopCapturingLogMessages();
-
- ASSERT_TRUE(rollbackSource.called);
- for (const auto& message : getCapturedTextFormatLogMessages()) {
- 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->getCollectionOptions();
- ASSERT_BSONOBJ_EQ(BSON("uuid" << *options.uuid), collAfterRollbackOptions.toBSON());
-}
-
-TEST_F(RollbackResyncsCollectionOptionsTest,
- FullRemoteCollectionValidationOptionsAndEmptyLocalValidationOptions) {
- // Empty local collection options.
- CollectionOptions localCollOptions;
- localCollOptions.uuid = UUID::gen();
-
- // 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;
- localCollOptions.uuid = UUID::gen();
-
- BSONObj remoteCollOptionsObj = BSON("validationLevel"
- << "moderate"
- << "validationAction"
- << "warn");
-
- resyncCollectionOptionsTest(localCollOptions, remoteCollOptionsObj);
-}
-
-TEST_F(RollbackResyncsCollectionOptionsTest,
- PartialRemoteCollectionValidationOptionsAndFullLocalValidationOptions) {
- CollectionOptions localCollOptions;
- localCollOptions.uuid = UUID::gen();
- localCollOptions.validator = BSON("x" << BSON("$exists" << 1));
- localCollOptions.validationLevel = ValidationLevelEnum::moderate;
- localCollOptions.validationAction = ValidationActionEnum::warn;
-
- BSONObj remoteCollOptionsObj = BSON("validationLevel"
- << "strict"
- << "validationAction"
- << "error");
-
-
- resyncCollectionOptionsTest(localCollOptions, remoteCollOptionsObj);
-}
-
-TEST_F(RollbackResyncsCollectionOptionsTest,
- EmptyRemoteCollectionValidationOptionsAndEmptyLocalValidationOptions) {
- CollectionOptions localCollOptions;
- localCollOptions.uuid = UUID::gen();
-
- BSONObj remoteCollOptionsObj = BSONObj();
-
- resyncCollectionOptionsTest(localCollOptions, remoteCollOptionsObj);
-}
-
-TEST_F(RollbackResyncsCollectionOptionsTest,
- EmptyRemoteCollectionValidationOptionsAndFullLocalValidationOptions) {
- CollectionOptions localCollOptions;
- localCollOptions.uuid = UUID::gen();
- localCollOptions.validator = BSON("x" << BSON("$exists" << 1));
- localCollOptions.validationLevel = ValidationLevelEnum::moderate;
- localCollOptions.validationAction = ValidationActionEnum::warn;
-
- BSONObj remoteCollOptionsObj = BSONObj();
-
- resyncCollectionOptionsTest(localCollOptions, remoteCollOptionsObj);
-}
-
-TEST_F(RollbackResyncsCollectionOptionsTest, LocalTempCollectionRemotePermanentCollection) {
- CollectionOptions localCollOptions;
- localCollOptions.uuid = UUID::gen();
- localCollOptions.temp = true;
-
- BSONObj remoteCollOptionsObj = BSONObj();
-
- resyncCollectionOptionsTest(localCollOptions, remoteCollOptionsObj);
-}
-
-TEST_F(RollbackResyncsCollectionOptionsTest, LocalPermanentCollectionRemoteTempCollection) {
- CollectionOptions localCollOptions;
- localCollOptions.uuid = UUID::gen();
-
- BSONObj remoteCollOptionsObj = BSON("temp" << true);
-
- resyncCollectionOptionsTest(localCollOptions, remoteCollOptionsObj);
-}
-
-TEST_F(RollbackResyncsCollectionOptionsTest, BothCollectionsTemp) {
- CollectionOptions localCollOptions;
- localCollOptions.uuid = UUID::gen();
- localCollOptions.temp = true;
-
- BSONObj remoteCollOptionsObj = BSON("temp" << true);
-
- resyncCollectionOptionsTest(localCollOptions, remoteCollOptionsObj);
-}
-
-TEST_F(RollbackResyncsCollectionOptionsTest, ChangingTempStatusAlsoChangesOtherCollectionOptions) {
- CollectionOptions localCollOptions;
- localCollOptions.uuid = UUID::gen();
- localCollOptions.temp = true;
-
- BSONObj remoteCollOptionsObj = BSON("validationLevel"
- << "strict"
- << "validationAction"
- << "error");
-
- resyncCollectionOptionsTest(localCollOptions, remoteCollOptionsObj);
-}
-
-TEST_F(RSRollbackTest, RollbackCollectionModificationCommandInvalidCollectionOptions) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- auto coll = _createCollection(_opCtx.get(), "test.t", options);
-
- auto commonOperation = makeOpAndRecordId(1);
-
- BSONObj collModCmd = BSON("collMod"
- << "t"
- << "validationLevel"
- << "strict");
- auto collectionModificationOperation =
- makeCommandOp(Timestamp(Seconds(2), 0), coll->uuid(), "test.t", collModCmd, 2);
-
-
- class RollbackSourceLocal : public RollbackSourceMock {
- public:
- RollbackSourceLocal(std::unique_ptr<OplogInterface> oplog)
- : RollbackSourceMock(std::move(oplog)) {}
- StatusWith<BSONObj> getCollectionInfoByUUID(const std::string& db, const UUID& uuid) const {
- return BSON("options" << 12345);
- }
- };
- RollbackSourceLocal rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({
- commonOperation,
- })));
- auto status =
- syncRollback(_opCtx.get(),
- OplogInterfaceMock({collectionModificationOperation, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get());
- ASSERT_EQUALS(ErrorCodes::UnrecoverableRollbackError, status.code());
- ASSERT_STRING_CONTAINS(status.reason(), "Failed to parse options");
-}
-
-TEST(RSRollbackTest, LocalEntryWithoutNsIsFatal) {
- const auto validOplogEntry = BSON("op"
- << "i"
- << "ui" << UUID::gen() << "ts" << Timestamp(1, 1) << "t"
- << 1LL << "ns"
- << "test.t"
- << "wall" << Date_t() << "o" << BSON("_id" << 1 << "a" << 1));
- FixUpInfo fui;
- ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */, OplogInterfaceMock(), fui, validOplogEntry, false));
- const auto invalidOplogEntry = BSON("op"
- << "i"
- << "ui" << UUID::gen() << "ts" << Timestamp(1, 1) << "t"
- << 1LL << "ns"
- << ""
- << "wall" << Date_t() << "o"
- << BSON("_id" << 1 << "a" << 1));
- ASSERT_THROWS(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */, OplogInterfaceMock(), fui, invalidOplogEntry, false),
- RSFatalException);
-}
-
-TEST(RSRollbackTest, LocalEntryWithoutOIsFatal) {
- const auto validOplogEntry = BSON("op"
- << "i"
- << "ui" << UUID::gen() << "ts" << Timestamp(1, 1) << "t"
- << 1LL << "ns"
- << "test.t"
- << "wall" << Date_t() << "o" << BSON("_id" << 1 << "a" << 1));
- FixUpInfo fui;
- ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */, OplogInterfaceMock(), fui, validOplogEntry, false));
- const auto invalidOplogEntry = BSON("op"
- << "i"
- << "ui" << UUID::gen() << "ts" << Timestamp(1, 1) << "t"
- << 1LL << "ns"
- << "test.t"
- << "wall" << Date_t() << "o" << BSONObj());
- ASSERT_THROWS(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */, OplogInterfaceMock(), fui, invalidOplogEntry, false),
- RSFatalException);
-}
-
-DEATH_TEST_F(RSRollbackTest, LocalUpdateEntryWithoutO2IsFatal, "Fatal assertion") {
- const auto invalidOplogEntry = BSON("op"
- << "u"
- << "ui" << UUID::gen() << "ts" << Timestamp(1, 1) << "t"
- << 1LL << "ns"
- << "test.t"
- << "wall" << Date_t() << "o"
- << BSON("_id" << 1 << "a" << 1));
- FixUpInfo fui;
- updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */, OplogInterfaceMock(), fui, invalidOplogEntry, false)
- .ignore();
-}
-
-TEST(RSRollbackTest, LocalUpdateEntryWithEmptyO2IsFatal) {
- const auto validOplogEntry = BSON("op"
- << "u"
- << "ui" << UUID::gen() << "ts" << Timestamp(1, 1) << "t"
- << 1LL << "ns"
- << "test.t"
- << "wall" << Date_t() << "o" << BSON("_id" << 1 << "a" << 1)
- << "o2" << BSON("_id" << 1));
- FixUpInfo fui;
- ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */, OplogInterfaceMock(), fui, validOplogEntry, false));
- const auto invalidOplogEntry = BSON("op"
- << "u"
- << "ui" << UUID::gen() << "ts" << Timestamp(1, 1) << "t"
- << 1LL << "ns"
- << "test.t"
- << "wall" << Date_t() << "o" << BSON("_id" << 1 << "a" << 1)
- << "o2" << BSONObj());
- ASSERT_THROWS(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */, OplogInterfaceMock(), fui, invalidOplogEntry, false),
- RSFatalException);
-}
-
-DEATH_TEST_F(RSRollbackTest, LocalEntryWithTxnNumberWithoutSessionIdIsFatal, "invariant") {
- auto validOplogEntry = BSON("ts" << Timestamp(Seconds(1), 0) << "t" << 1LL << "op"
- << "i"
- << "ui" << UUID::gen() << "ns"
- << "test.t"
- << "wall" << Date_t() << "o" << BSON("_id" << 1 << "a" << 1));
- FixUpInfo fui;
- ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */, OplogInterfaceMock(), fui, validOplogEntry, false));
-
- const auto txnNumber = BSON("txnNumber" << 1LL);
- const auto noSessionIdOrStmtId = validOplogEntry.addField(txnNumber.firstElement());
-
- const auto stmtId = BSON("stmtId" << 1);
- const auto noSessionId = noSessionIdOrStmtId.addField(stmtId.firstElement());
- ASSERT_THROWS(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */, OplogInterfaceMock(), fui, noSessionId, false),
- RSFatalException);
-}
-
-TEST_F(RSRollbackTest, LocalEntryWithTxnNumberWithoutTxnTableUUIDIsFatal) {
- // If txnNumber is present, but the transaction collection has no UUID, rollback fails.
- UUID uuid = UUID::gen();
- auto lsid = makeLogicalSessionIdForTest();
- auto entryWithTxnNumber =
- BSON("ts" << Timestamp(Seconds(1), 0) << "t" << 1LL << "op"
- << "i"
- << "ui" << uuid << "ns"
- << "test.t"
- << "wall" << Date_t() << "o" << BSON("_id" << 1 << "a" << 1) << "txnNumber" << 1LL
- << "stmtId" << 1 << "lsid" << lsid.toBSON());
-
- FixUpInfo fui;
- ASSERT_THROWS(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */, OplogInterfaceMock(), fui, entryWithTxnNumber, false),
- RSFatalException);
-}
-
-TEST_F(RSRollbackTest, LocalEntryWithTxnNumberAddsTransactionTableDocToBeRefetched) {
- FixUpInfo fui;
-
- // With no txnNumber present, no extra documents need to be refetched.
- auto entryWithoutTxnNumber =
- BSON("ts" << Timestamp(Seconds(1), 0) << "t" << 1LL << "op"
- << "i"
- << "ui" << UUID::gen() << "ns"
- << "test.t2"
- << "wall" << Date_t() << "o" << BSON("_id" << 2 << "a" << 2));
-
- ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */, OplogInterfaceMock(), fui, entryWithoutTxnNumber, false));
- ASSERT_EQ(fui.docsToRefetch.size(), 1U);
-
- // If txnNumber is present, and the transaction table exists and has a UUID, the session
- // transactions table document corresponding to the oplog entry's sessionId also needs to be
- // refetched.
- UUID uuid = UUID::gen();
- auto lsid = makeLogicalSessionIdForTest();
- auto entryWithTxnNumber =
- BSON("ts" << Timestamp(Seconds(1), 0) << "t" << 1LL << "op"
- << "i"
- << "ui" << uuid << "ns"
- << "test.t"
- << "wall" << Date_t() << "o" << BSON("_id" << 1 << "a" << 1) << "txnNumber" << 1LL
- << "stmtId" << 1 << "lsid" << lsid.toBSON());
- UUID transactionTableUUID = UUID::gen();
- fui.transactionTableUUID = transactionTableUUID;
-
- ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */, OplogInterfaceMock(), fui, entryWithTxnNumber, false));
- ASSERT_EQ(fui.docsToRefetch.size(), 3U);
-
- auto expectedObj = BSON("_id" << lsid.toBSON());
- DocID expectedTxnDoc(expectedObj, expectedObj.firstElement(), transactionTableUUID);
- ASSERT_TRUE(fui.docsToRefetch.find(expectedTxnDoc) != fui.docsToRefetch.end());
-}
-
-TEST_F(RSRollbackTest, LocalEntryWithPartialTxnAddsTransactionTableDocToBeRefetched) {
- FixUpInfo fui;
-
- // If txnNumber is present, and the transaction table exists and has a UUID, the session
- // transactions table document corresponding to the oplog entry's sessionId also needs to be
- // refetched. This is true even if "partialTxn" is set indicating this is part of a transaction
- // that may not have been committed.
- UUID uuid = UUID::gen();
- auto lsid = makeLogicalSessionIdForTest();
- auto entryWithTxnNumber =
- BSON("ts" << Timestamp(Seconds(1), 0) << "t" << 1LL << "op"
- << "c"
- << "ns"
- << "admin.$cmd"
- << "wall" << Date_t() << "o"
- << BSON("applyOps" << BSON_ARRAY(BSON("op"
- << "i"
- << "ui" << uuid << "ns"
- << "test.t"
- << "o" << BSON("_id" << 1 << "a" << 1)))
- << "partialTxn" << true)
- << "txnNumber" << 1LL << "stmtId" << 1 << "lsid" << lsid.toBSON());
- UUID transactionTableUUID = UUID::gen();
- fui.transactionTableUUID = transactionTableUUID;
-
- ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */, OplogInterfaceMock(), fui, entryWithTxnNumber, false));
- ASSERT_EQ(fui.docsToRefetch.size(), 1U);
-
- auto expectedObj = BSON("_id" << lsid.toBSON());
- DocID expectedTxnDoc(expectedObj, expectedObj.firstElement(), transactionTableUUID);
- ASSERT_TRUE(fui.docsToRefetch.find(expectedTxnDoc) != fui.docsToRefetch.end());
-}
-
-TEST_F(RSRollbackTest, LocalAbortTxnRefetchesTransactionTableEntry) {
- // A rolled back abort, even if we rolled back no transaction operations, should refetch the
- // transaction table entry.
- FixUpInfo fui;
-
- auto lsid = makeLogicalSessionIdForTest();
- auto abortTxnEntry =
- BSON("ts" << Timestamp(Seconds(1), 1) << "t" << 1LL << "op"
- << "c"
- << "ns"
- << "admin.$cmd"
- << "wall" << Date_t() << "o" << BSON("abortTransaction" << 1) << "txnNumber"
- << 1LL << "stmtId" << 1 << "lsid" << lsid.toBSON() << "prevOpTime"
- << BSON("ts" << Timestamp(Seconds(1), 0) << "t" << 1LL));
-
- UUID transactionTableUUID = UUID::gen();
- fui.transactionTableUUID = transactionTableUUID;
-
- ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */, OplogInterfaceMock(), fui, abortTxnEntry, false));
- ASSERT_EQ(fui.docsToRefetch.size(), 1U);
-
- auto expectedObj = BSON("_id" << lsid.toBSON());
- DocID expectedTxnDoc(expectedObj, expectedObj.firstElement(), transactionTableUUID);
- ASSERT_TRUE(fui.docsToRefetch.find(expectedTxnDoc) != fui.docsToRefetch.end());
-}
-
-TEST_F(RSRollbackTest, LocalEntryWithAbortedPartialTxnRefetchesOnlyTransactionTableEntry) {
- FixUpInfo fui;
-
- // If txnNumber is present, and the transaction table exists and has a UUID, the session
- // transactions table document corresponding to the oplog entry's sessionId also needs to be
- // refetched. This is true even if "partialTxn" is set indicating this is part of a transaction
- // that may not have been committed, and even if it is known that the transaction aborted.
- UUID uuid = UUID::gen();
- auto lsid = makeLogicalSessionIdForTest();
- auto abortTxnEntry =
- BSON("ts" << Timestamp(Seconds(1), 2) << "t" << 1LL << "op"
- << "c"
- << "ns"
- << "admin.$cmd"
- << "wall" << Date_t() << "o" << BSON("abortTransaction" << 1) << "txnNumber"
- << 1LL << "stmtId" << 1 << "lsid" << lsid.toBSON() << "prevOpTime"
- << BSON("ts" << Timestamp(Seconds(1), 1) << "t" << 1LL));
-
- auto entryWithTxnNumber =
- BSON("ts" << Timestamp(Seconds(1), 1) << "t" << 1LL << "op"
- << "c"
- << "ns"
- << "admin.$cmd"
- << "wall" << Date_t() << "o"
- << BSON("applyOps" << BSON_ARRAY(BSON("op"
- << "i"
- << "ui" << uuid << "ns"
- << "test.t"
- << "o" << BSON("_id" << 1 << "a" << 1)))
- << "partialTxn" << true)
- << "txnNumber" << 1LL << "stmtId" << 1 << "lsid" << lsid.toBSON());
- UUID transactionTableUUID = UUID::gen();
- fui.transactionTableUUID = transactionTableUUID;
-
- ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */, OplogInterfaceMock(), fui, abortTxnEntry, false));
- ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */, OplogInterfaceMock(), fui, entryWithTxnNumber, false));
- ASSERT_EQ(fui.docsToRefetch.size(), 1U);
-
- auto expectedObj = BSON("_id" << lsid.toBSON());
- DocID expectedTxnDoc(expectedObj, expectedObj.firstElement(), transactionTableUUID);
- ASSERT_TRUE(fui.docsToRefetch.find(expectedTxnDoc) != fui.docsToRefetch.end());
-}
-
-TEST_F(RSRollbackTest, LocalEntryWithCommittedTxnRefetchesDocsAndTransactionTableEntry) {
- FixUpInfo fui;
- UUID uuid = UUID::gen();
- auto lsid = makeLogicalSessionIdForTest();
- auto commitTxnEntry =
- BSON("ts" << Timestamp(Seconds(1), 2) << "t" << 1LL << "op"
- << "c"
- << "ns"
- << "admin.$cmd"
- << "wall" << Date_t() << "o"
- << BSON("applyOps" << BSON_ARRAY(BSON("op"
- << "i"
- << "ui" << uuid << "ns"
- << "test.t"
- << "o" << BSON("_id" << 2 << "a" << 2)))
- << "count" << 2)
- << "txnNumber" << 1LL << "stmtId" << 2 << "lsid" << lsid.toBSON() << "prevOpTime"
- << BSON("ts" << Timestamp(Seconds(1), 1) << "t" << 1LL));
- auto commitTxnOperation = std::make_pair(commitTxnEntry, RecordId(2));
-
- auto partialTxnEntry =
- BSON("ts" << Timestamp(Seconds(1), 1) << "t" << 1LL << "op"
- << "c"
- << "ns"
- << "admin.$cmd"
- << "wall" << Date_t() << "o"
- << BSON("applyOps" << BSON_ARRAY(BSON("op"
- << "i"
- << "ui" << uuid << "ns"
- << "test.t"
- << "o" << BSON("_id" << 1 << "a" << 1)))
- << "partialTxn" << true)
- << "txnNumber" << 1LL << "stmtId" << 1 << "lsid" << lsid.toBSON() << "prevOpTime"
- << BSON("ts" << Timestamp(0, 0) << "t" << -1LL));
-
- auto partialTxnOperation = std::make_pair(partialTxnEntry, RecordId(1));
- UUID transactionTableUUID = UUID::gen();
- fui.transactionTableUUID = transactionTableUUID;
-
- ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */,
- OplogInterfaceMock({commitTxnOperation, partialTxnOperation}),
- fui,
- commitTxnEntry,
- false));
- ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */,
- OplogInterfaceMock({commitTxnOperation, partialTxnOperation}),
- fui,
- partialTxnEntry,
- false));
- ASSERT_EQ(fui.docsToRefetch.size(), 3U);
-
- auto expectedObj = BSON("_id" << lsid.toBSON());
- DocID expectedTxnDoc(expectedObj, expectedObj.firstElement(), transactionTableUUID);
- ASSERT_TRUE(fui.docsToRefetch.find(expectedTxnDoc) != fui.docsToRefetch.end());
-
- auto expectedCrudObj = BSON("_id" << 2);
- auto expectedCrudDoc = DocID(expectedObj, expectedObj.firstElement(), transactionTableUUID);
- ASSERT_TRUE(fui.docsToRefetch.find(expectedCrudDoc) != fui.docsToRefetch.end());
-
- expectedCrudObj = BSON("_id" << 1);
- expectedCrudDoc = DocID(expectedObj, expectedObj.firstElement(), transactionTableUUID);
- ASSERT_TRUE(fui.docsToRefetch.find(expectedCrudDoc) != fui.docsToRefetch.end());
-}
-
-TEST_F(RSRollbackTest, RollbackFetchesTransactionOperationBeforeCommonPoint) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- auto coll = _createCollection(_opCtx.get(), "test.t", options);
- options.uuid = UUID::gen();
- auto txnTable = _createCollection(_opCtx.get(), "config.transactions", options);
-
- auto commonOperation = makeOpAndRecordId(10);
- UUID uuid = coll->uuid();
- auto lsid = makeLogicalSessionIdForTest();
- auto commitTxnEntry =
- BSON("ts" << Timestamp(Seconds(10), 12) << "t" << 10LL << "op"
- << "c"
- << "ns"
- << "admin.$cmd"
- << "wall" << Date_t() << "o"
- << BSON("applyOps" << BSON_ARRAY(BSON("op"
- << "i"
- << "ui" << uuid << "ns"
- << "test.t"
- << "o" << BSON("_id" << 0 << "a" << 0)))
- << "count" << 3)
- << "txnNumber" << 1LL << "stmtId" << 3 << "lsid" << lsid.toBSON() << "prevOpTime"
- << BSON("ts" << Timestamp(Seconds(10), 11) << "t" << 10LL));
- auto commitTxnOperation = std::make_pair(commitTxnEntry, RecordId(12));
-
- auto entryAfterCommonPoint =
- BSON("ts" << Timestamp(Seconds(10), 11) << "t" << 10LL << "op"
- << "c"
- << "ns"
- << "admin.$cmd"
- << "wall" << Date_t() << "o"
- << BSON("applyOps" << BSON_ARRAY(BSON("op"
- << "i"
- << "ui" << uuid << "ns"
- << "test.t"
- << "o" << BSON("_id" << 1 << "a" << 1)))
- << "partialTxn" << true)
- << "txnNumber" << 1LL << "stmtId" << 2 << "lsid" << lsid.toBSON() << "prevOpTime"
- << BSON("ts" << Timestamp(Seconds(10), 9) << "t" << 10LL));
- auto operationAfterCommonPoint = std::make_pair(entryAfterCommonPoint, RecordId(11));
-
- auto entryBeforeCommonPoint =
- BSON("ts" << Timestamp(Seconds(10), 9) << "t" << 10LL << "op"
- << "c"
- << "ns"
- << "admin.$cmd"
- << "wall" << Date_t() << "o"
- << BSON("applyOps" << BSON_ARRAY(BSON("op"
- << "i"
- << "ui" << uuid << "ns"
- << "test.t"
- << "o" << BSON("_id" << 2 << "a" << 2)))
- << "partialTxn" << true)
- << "txnNumber" << 1LL << "stmtId" << 1 << "lsid" << lsid.toBSON() << "prevOpTime"
- << BSON("ts" << Timestamp(0, 0) << "t" << -1LL));
- auto operationBeforeCommonPoint = std::make_pair(entryBeforeCommonPoint, RecordId(9));
-
- class RollbackSourceLocal : public RollbackSourceMock {
- public:
- RollbackSourceLocal(std::unique_ptr<OplogInterface> oplog, const UUID& txnTableUuid)
- : RollbackSourceMock(std::move(oplog)), _txnTableUuid(txnTableUuid) {}
-
- std::pair<BSONObj, NamespaceString> findOneByUUID(const std::string& db,
- UUID uuid,
- const BSONObj& filter) const override {
- int numFields = 0;
- if (uuid == _txnTableUuid) {
- // This unit test does not test transaction table fetches.
- return {BSONObj(), NamespaceString::kSessionTransactionsTableNamespace};
- }
- for (const auto& element : filter) {
- ++numFields;
- ASSERT_EQUALS("_id", element.fieldNameStringData()) << filter;
- }
- ASSERT_EQUALS(1, numFields) << filter;
- searchedIds.insert(filter.firstElement().numberInt());
- switch (filter.firstElement().numberInt()) {
- case 0:
- return {BSON("_id" << 0 << "v" << 0), NamespaceString()};
- case 1:
- return {BSON("_id" << 1 << "v" << 1), NamespaceString()};
- case 2:
- return {BSON("_id" << 2 << "v" << 3), NamespaceString()};
- }
- FAIL("Unexpected findOne request") << filter;
- return {}; // Unreachable; why doesn't compiler know?
- }
-
- mutable std::multiset<int> searchedIds;
-
- private:
- UUID _txnTableUuid;
-
- } rollbackSource(std::unique_ptr<OplogInterface>(
- new OplogInterfaceMock({commonOperation, operationBeforeCommonPoint})),
- txnTable->uuid());
-
- ASSERT_OK(syncRollback(_opCtx.get(),
- OplogInterfaceMock({commitTxnOperation,
- operationAfterCommonPoint,
- commonOperation,
- operationBeforeCommonPoint}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get()));
- ASSERT_EQUALS(3U, rollbackSource.searchedIds.size());
- ASSERT_EQUALS(1U, rollbackSource.searchedIds.count(0));
- ASSERT_EQUALS(1U, rollbackSource.searchedIds.count(1));
- ASSERT_EQUALS(1U, rollbackSource.searchedIds.count(2));
-}
-
-TEST_F(RSRollbackTest, RollbackIncompleteTransactionReturnsUnrecoverableRollbackError) {
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- auto coll = _createCollection(_opCtx.get(), "test.t", options);
- options.uuid = UUID::gen();
- auto txnTable = _createCollection(_opCtx.get(), "config.transactions", options);
-
- auto commonOperation = makeOpAndRecordId(10);
- UUID uuid = coll->uuid();
- auto lsid = makeLogicalSessionIdForTest();
- auto commitTxnEntry =
- BSON("ts" << Timestamp(Seconds(10), 12) << "t" << 10LL << "op"
- << "c"
- << "ns"
- << "admin.$cmd"
- << "wall" << Date_t() << "o"
- << BSON("applyOps" << BSON_ARRAY(BSON("op"
- << "i"
- << "ui" << uuid << "ns"
- << "test.t"
- << "o" << BSON("_id" << 0 << "a" << 0)))
- << "count" << 3)
- << "stmtId" << 3 << "lsid" << lsid.toBSON() << "prevOpTime"
- << BSON("ts" << Timestamp(Seconds(10), 11) << "t" << 10LL));
- auto commitTxnOperation = std::make_pair(commitTxnEntry, RecordId(12));
-
- auto entryAfterCommonPoint =
- BSON("ts" << Timestamp(Seconds(10), 11) << "t" << 10LL << "op"
- << "c"
- << "ns"
- << "admin.$cmd"
- << "wall" << Date_t() << "o"
- << BSON("applyOps" << BSON_ARRAY(BSON("op"
- << "i"
- << "ui" << uuid << "ns"
- << "test.t"
- << "o" << BSON("_id" << 1 << "a" << 1)))
- << "partialTxn" << true)
- << "txnNumber" << 1LL << "stmtId" << 2 << "lsid" << lsid.toBSON() << "prevOpTime"
- << BSON("ts" << Timestamp(Seconds(10), 9) << "t" << 10LL));
- auto operationAfterCommonPoint = std::make_pair(entryAfterCommonPoint, RecordId(11));
-
- class RollbackSourceLocal : public RollbackSourceMock {
- public:
- RollbackSourceLocal(std::unique_ptr<OplogInterface> oplog, const UUID& txnTableUuid)
- : RollbackSourceMock(std::move(oplog)), _txnTableUuid(txnTableUuid) {}
-
- std::pair<BSONObj, NamespaceString> findOneByUUID(const std::string& db,
- UUID uuid,
- const BSONObj& filter) const override {
- if (uuid == _txnTableUuid) {
- // This unit test does not test transaction table fetches.
- return {BSONObj(), NamespaceString::kSessionTransactionsTableNamespace};
- } else {
- return {BSONObj(), NamespaceString()};
- }
- }
-
- private:
- UUID _txnTableUuid;
- } rollbackSource(std::unique_ptr<OplogInterface>(new OplogInterfaceMock({commonOperation})),
- txnTable->uuid());
-
-
- auto status = syncRollback(
- _opCtx.get(),
- OplogInterfaceMock({commitTxnOperation, operationAfterCommonPoint, commonOperation}),
- rollbackSource,
- {},
- {},
- _coordinator,
- _replicationProcess.get());
- ASSERT_EQUALS(ErrorCodes::UnrecoverableRollbackError, status.code());
-}
-
-TEST_F(RSRollbackTest, RollbackFailsIfTransactionDocumentRefetchReturnsDifferentNamespace) {
- createOplog(_opCtx.get());
-
- // Create a valid FixUpInfo struct for rolling back a single CRUD operation that has a
- // transaction number and session id.
- FixUpInfo fui;
-
- auto entryWithTxnNumber =
- BSON("ts" << Timestamp(Seconds(2), 1) << "t" << 1LL << "op"
- << "i"
- << "ui" << UUID::gen() << "ns"
- << "test.t"
- << "wall" << Date_t() << "o" << BSON("_id" << 1 << "a" << 1) << "txnNumber" << 1LL
- << "stmtId" << 1 << "lsid" << makeLogicalSessionIdForTest().toBSON());
-
- UUID transactionTableUUID = UUID::gen();
- fui.transactionTableUUID = transactionTableUUID;
-
- auto commonOperation = makeOpAndRecordId(1);
- fui.commonPoint = OpTime(Timestamp(Seconds(1), 1), 1LL);
- fui.commonPointOurDiskloc = RecordId(1);
-
- fui.rbid = 1;
-
- // The FixUpInfo will have an extra doc to refetch: the corresponding transaction table entry.
- ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(
- nullptr /* opCtx */, OplogInterfaceMock(), fui, entryWithTxnNumber, false));
- ASSERT_EQ(fui.docsToRefetch.size(), 2U);
-
- {
- class RollbackSourceLocal : public RollbackSourceMock {
- public:
- RollbackSourceLocal(std::unique_ptr<OplogInterface> oplog)
- : RollbackSourceMock(std::move(oplog)) {}
- std::pair<BSONObj, NamespaceString> findOneByUUID(
- const std::string& db, UUID uuid, const BSONObj& filter) const override {
- return {BSONObj(), NamespaceString::kSessionTransactionsTableNamespace};
- }
- int getRollbackId() const override {
- return 1;
- }
- };
-
- // Should not throw, since findOneByUUID will return the expected namespace.
- syncFixUp(_opCtx.get(),
- fui,
- RollbackSourceLocal(
- std::unique_ptr<OplogInterface>(new OplogInterfaceMock({commonOperation}))),
- _coordinator,
- _replicationProcess.get());
- }
-
- {
- class RollbackSourceLocal : public RollbackSourceMock {
- public:
- RollbackSourceLocal(std::unique_ptr<OplogInterface> oplog)
- : RollbackSourceMock(std::move(oplog)) {}
- std::pair<BSONObj, NamespaceString> findOneByUUID(
- const std::string& db, UUID uuid, const BSONObj& filter) const override {
- return {BSONObj(), NamespaceString("foo.bar")};
- }
- int getRollbackId() const override {
- return 1;
- }
- };
-
- // The returned namespace will not be the expected one, implying a rename/drop of the
- // transactions collection across this node and the sync source, so rollback should fail.
- ASSERT_THROWS(syncFixUp(_opCtx.get(),
- fui,
- RollbackSourceLocal(std::unique_ptr<OplogInterface>(
- new OplogInterfaceMock({commonOperation}))),
- _coordinator,
- _replicationProcess.get()),
- RSFatalException);
- }
-}
-
-TEST_F(RSRollbackTest, RollbackReturnsImmediatelyOnFailureToTransitionToRollback) {
- // On failing to transition to ROLLBACK, rollback() should return immediately and not call
- // syncRollback(). We provide an empty oplog so that if syncRollback() is called erroneously,
- // we would go fatal.
- OplogInterfaceMock localOplogWithSingleOplogEntry({makeNoopOplogEntryAndRecordId(Seconds(1))});
- RollbackSourceMock rollbackSourceWithInvalidOplog(std::make_unique<OplogInterfaceMock>());
-
- // Inject ReplicationCoordinator::setFollowerMode() error. We set the current member state
- // because it will be logged by rollback() on failing to transition to ROLLBACK.
- ASSERT_OK(_coordinator->setFollowerMode(MemberState::RS_SECONDARY));
- _coordinator->failSettingFollowerMode(MemberState::RS_ROLLBACK, ErrorCodes::NotSecondary);
-
- startCapturingLogMessages();
- rollback(_opCtx.get(),
- localOplogWithSingleOplogEntry,
- rollbackSourceWithInvalidOplog,
- {},
- _coordinator,
- _replicationProcess.get());
- stopCapturingLogMessages();
-
- ASSERT_EQUALS(1,
- countTextFormatLogLinesContaining("Cannot perform replica set state transition"));
- ASSERT_EQUALS(MemberState(MemberState::RS_SECONDARY), _coordinator->getMemberState());
-}
-
-DEATH_TEST_REGEX_F(RSRollbackTest,
- RollbackUnrecoverableRollbackErrorTriggersFatalAssertion,
- "Unable to complete rollback. A full resync may be needed") {
- // rollback() should abort on getting UnrecoverableRollbackError from syncRollback(). An empty
- // local oplog will make syncRollback() return the intended error.
- OplogInterfaceMock localOplogWithSingleOplogEntry({makeNoopOplogEntryAndRecordId(Seconds(1))});
- RollbackSourceMock rollbackSourceWithInvalidOplog(std::make_unique<OplogInterfaceMock>());
-
- rollback(_opCtx.get(),
- localOplogWithSingleOplogEntry,
- rollbackSourceWithInvalidOplog,
- {},
- _coordinator,
- _replicationProcess.get());
-}
-
-TEST_F(RSRollbackTest, RollbackLogsRetryMessageAndReturnsOnNonUnrecoverableRollbackError) {
- // If local oplog is empty, syncRollback() returns OplogStartMissing (instead of
- // UnrecoverableRollbackError when the remote oplog is missing). rollback() should log a message
- // about retrying rollback later before returning.
- OplogInterfaceMock localOplogWithNoEntries;
- OplogInterfaceMock::Operations remoteOperations({makeNoopOplogEntryAndRecordId(Seconds(1))});
- auto remoteOplog = std::make_unique<OplogInterfaceMock>(remoteOperations);
- RollbackSourceMock rollbackSourceWithValidOplog(std::move(remoteOplog));
- auto noopSleepSecsFn = [](int) {};
-
- startCapturingLogMessages();
- rollback(_opCtx.get(),
- localOplogWithNoEntries,
- rollbackSourceWithValidOplog,
- {},
- _coordinator,
- _replicationProcess.get(),
- noopSleepSecsFn);
- stopCapturingLogMessages();
-
- ASSERT_EQUALS(1,
- countTextFormatLogLinesContaining(
- "Rollback cannot complete at this time (retrying later)"));
- ASSERT_EQUALS(MemberState(MemberState::RS_RECOVERING), _coordinator->getMemberState());
-}
-
-DEATH_TEST_F(RSRollbackTest,
- RollbackTriggersFatalAssertionOnDetectingShardIdentityDocumentRollback,
- "shardIdentity document rollback detected. Shutting down to clear in-memory sharding "
- "state. Restarting this process should safely return it to a healthy state") {
- auto commonOperation = makeNoopOplogEntryAndRecordId(Seconds(1));
- OplogInterfaceMock localOplog({commonOperation});
- RollbackSourceMock rollbackSource(
- std::unique_ptr<OplogInterface>(new OplogInterfaceMock({commonOperation})));
-
- ASSERT_FALSE(ShardIdentityRollbackNotifier::get(_opCtx.get())->didRollbackHappen());
- ShardIdentityRollbackNotifier::get(_opCtx.get())->recordThatRollbackHappened();
- ASSERT_TRUE(ShardIdentityRollbackNotifier::get(_opCtx.get())->didRollbackHappen());
-
- createOplog(_opCtx.get());
- rollback(_opCtx.get(), localOplog, rollbackSource, {}, _coordinator, _replicationProcess.get());
-}
-
-DEATH_TEST_REGEX_F(
- RSRollbackTest,
- RollbackTriggersFatalAssertionOnFailingToTransitionToRecoveringAfterSyncRollbackReturns,
- "Failed to perform replica set state transition") {
- auto commonOperation = makeNoopOplogEntryAndRecordId(Seconds(1));
- OplogInterfaceMock localOplog({commonOperation});
- RollbackSourceMock rollbackSource(
- std::unique_ptr<OplogInterface>(new OplogInterfaceMock({commonOperation})));
-
- _coordinator->failSettingFollowerMode(MemberState::RS_RECOVERING, ErrorCodes::IllegalOperation);
-
- createOplog(_opCtx.get());
- rollback(_opCtx.get(), localOplog, rollbackSource, {}, _coordinator, _replicationProcess.get());
-}
-
-// The testcases used here are trying to detect off-by-one errors in
-// FixUpInfo::removeAllDocsToRefectchFor.
-TEST(FixUpInfoTest, RemoveAllDocsToRefetchForWorks) {
- const auto normalHolder = BSON("" << OID::gen());
- const auto normalKey = normalHolder.firstElement();
-
- UUID uuid1 = UUID::gen();
- UUID uuid2 = UUID::gen();
- UUID uuid3 = UUID::gen();
-
- // Can't use ASSERT_EQ with this since it isn't ostream-able. Failures will at least give you
- // the size. If that isn't enough, use GDB.
- using DocSet = std::set<DocID>;
-
- FixUpInfo fui;
- fui.docsToRefetch = {
- DocID::minFor(uuid1),
- DocID{{}, normalKey, uuid1},
- DocID::maxFor(uuid1),
-
- DocID::minFor(uuid2),
- DocID{{}, normalKey, uuid2},
- DocID::maxFor(uuid2),
-
- DocID::minFor(uuid3),
- DocID{{}, normalKey, uuid3},
- DocID::maxFor(uuid3),
- };
-
- // Remove from the middle.
- fui.removeAllDocsToRefetchFor(uuid2);
- ASSERT((fui.docsToRefetch ==
- DocSet{
- DocID::minFor(uuid1),
- DocID{{}, normalKey, uuid1},
- DocID::maxFor(uuid1),
-
- DocID::minFor(uuid3),
- DocID{{}, normalKey, uuid3},
- DocID::maxFor(uuid3),
- }))
- << "remaining docs: " << fui.docsToRefetch.size();
-
- // Remove from the end.
- fui.removeAllDocsToRefetchFor(uuid3);
- ASSERT((fui.docsToRefetch ==
- DocSet{
- DocID::minFor(uuid1), // This comment helps clang-format.
- DocID{{}, normalKey, uuid1},
- DocID::maxFor(uuid1),
- }))
- << "remaining docs: " << fui.docsToRefetch.size();
-
- // Everything else.
- fui.removeAllDocsToRefetchFor(uuid1);
- ASSERT((fui.docsToRefetch == DocSet{})) << "remaining docs: " << fui.docsToRefetch.size();
-}
-
-TEST_F(RSRollbackTest, RollbackInvalidatesDefaultRWConcernCache) {
- auto& rwcDefaults = ReadWriteConcernDefaults::get(getServiceContext());
-
- // Put initial defaults in the cache.
- {
- RWConcernDefault origDefaults;
- origDefaults.setUpdateOpTime(Timestamp(10, 20));
- origDefaults.setUpdateWallClockTime(Date_t::fromMillisSinceEpoch(1234));
- _lookupMock.setLookupCallReturnValue(std::move(origDefaults));
- }
- auto origCachedDefaults = rwcDefaults.getDefault(_opCtx.get());
- ASSERT_EQ(Timestamp(10, 20), *origCachedDefaults.getUpdateOpTime());
- ASSERT_EQ(Date_t::fromMillisSinceEpoch(1234), *origCachedDefaults.getUpdateWallClockTime());
-
- // Change the mock's defaults, but don't invalidate the cache yet. The cache should still return
- // the original defaults.
- {
- RWConcernDefault newDefaults;
- newDefaults.setUpdateOpTime(Timestamp(50, 20));
- newDefaults.setUpdateWallClockTime(Date_t::fromMillisSinceEpoch(5678));
- _lookupMock.setLookupCallReturnValue(std::move(newDefaults));
-
- auto cachedDefaults = rwcDefaults.getDefault(_opCtx.get());
- ASSERT_EQ(Timestamp(10, 20), *cachedDefaults.getUpdateOpTime());
- ASSERT_EQ(Date_t::fromMillisSinceEpoch(1234), *cachedDefaults.getUpdateWallClockTime());
- }
-
- // Rollback via refetch should invalidate the cache and getting the defaults should now return
- // the latest value.
- createOplog(_opCtx.get());
- CollectionOptions options;
- options.uuid = UUID::gen();
- auto coll = _createCollection(_opCtx.get(), "test.t", options);
- BSONObj doc = BSON("_id" << 0 << "a" << 1);
- _testRollbackDelete(_opCtx.get(), _coordinator, _replicationProcess.get(), coll->uuid(), doc);
-
- auto newCachedDefaults = rwcDefaults.getDefault(_opCtx.get());
- ASSERT_EQ(Timestamp(50, 20), *newCachedDefaults.getUpdateOpTime());
- ASSERT_EQ(Date_t::fromMillisSinceEpoch(5678), *newCachedDefaults.getUpdateWallClockTime());
-}
-
-} // namespace
-} // namespace mongo
diff --git a/src/mongo/db/repl/storage_interface_impl_test.cpp b/src/mongo/db/repl/storage_interface_impl_test.cpp
index 060e18a0361..6912206db8c 100644
--- a/src/mongo/db/repl/storage_interface_impl_test.cpp
+++ b/src/mongo/db/repl/storage_interface_impl_test.cpp
@@ -52,6 +52,7 @@
#include "mongo/db/repl/replication_coordinator_mock.h"
#include "mongo/db/repl/storage_interface_impl.h"
#include "mongo/db/service_context_d_test_fixture.h"
+#include "mongo/db/storage/snapshot_manager.h"
#include "mongo/stdx/thread.h"
#include "mongo/transport/transport_layer_mock.h"
#include "mongo/unittest/unittest.h"
@@ -385,12 +386,6 @@ TEST_F(StorageInterfaceImplTest, GetRollbackIDReturnsBadStatusIfRollbackIDIsNotI
ASSERT_EQUALS(ErrorCodes::TypeMismatch, storage.getRollbackID(opCtx).getStatus());
}
-TEST_F(StorageInterfaceImplTest, SnapshotSupported) {
- auto opCtx = getOperationContext();
- Status status = opCtx->recoveryUnit()->majorityCommittedSnapshotAvailable();
- ASSERT(status.isOK());
-}
-
TEST_F(StorageInterfaceImplTest, InsertDocumentsReturnsOKWhenNoOperationsAreGiven) {
auto opCtx = getOperationContext();
auto nss = makeNamespace(_agent);
diff --git a/src/mongo/db/repl/storage_timestamp_test.cpp b/src/mongo/db/repl/storage_timestamp_test.cpp
index f03c8306fa3..fead4dab5ee 100644
--- a/src/mongo/db/repl/storage_timestamp_test.cpp
+++ b/src/mongo/db/repl/storage_timestamp_test.cpp
@@ -251,12 +251,7 @@ public:
repl::ReplicationConsistencyMarkers* _consistencyMarkers;
StorageTimestampTest()
- : ServiceContextMongoDTest("wiredTiger",
- ServiceContextMongoDTest::RepairAction::kNoRepair,
- kDefaultStorageEngineInitFlags,
- true, // useReplSettings
- true // useMockClock
- ) {
+ : ServiceContextMongoDTest(Options{}.useReplSettings(true).useMockClock(true)) {
// Set up mongod.
ServiceContextMongoDTest::setUp();
diff --git a/src/mongo/db/repl/tenant_migration_donor_service_test.cpp b/src/mongo/db/repl/tenant_migration_donor_service_test.cpp
index 765c8de625f..e76097432b6 100644
--- a/src/mongo/db/repl/tenant_migration_donor_service_test.cpp
+++ b/src/mongo/db/repl/tenant_migration_donor_service_test.cpp
@@ -60,11 +60,6 @@ class TenantMigrationDonorServiceTest : public ServiceContextMongoDTest {
ServiceContextMongoDTest::setUp();
auto serviceContext = getServiceContext();
- // Set up clocks.
- serviceContext->setFastClockSource(std::make_unique<SharedClockSourceAdapter>(_clkSource));
- serviceContext->setPreciseClockSource(
- std::make_unique<SharedClockSourceAdapter>(_clkSource));
-
WaitForMajorityService::get(getServiceContext()).startup(getServiceContext());
{
@@ -130,9 +125,11 @@ class TenantMigrationDonorServiceTest : public ServiceContextMongoDTest {
}
protected:
+ TenantMigrationDonorServiceTest() : ServiceContextMongoDTest(Options{}.useMockClock(true)) {}
+
PrimaryOnlyServiceRegistry* _registry;
PrimaryOnlyService* _service;
- std::shared_ptr<ClockSourceMock> _clkSource = std::make_shared<ClockSourceMock>();
+ ClockSourceMock _clkSource;
long long _term = 0;
const TenantMigrationPEMPayload kDonorPEMPayload = [&] {
@@ -170,7 +167,7 @@ protected:
TEST_F(TenantMigrationDonorServiceTest, CheckSettingMigrationStartDate) {
// Advance the clock by some arbitrary amount of time so we are not starting at 0 seconds.
- _clkSource->advance(Milliseconds(10000));
+ _clkSource.advance(Milliseconds(10000));
auto taskFp =
globalFailPointRegistry().find("pauseTenantMigrationAfterPersistingInitialDonorStateDoc");
diff --git a/src/mongo/db/repl/tenant_migration_recipient_service_test.cpp b/src/mongo/db/repl/tenant_migration_recipient_service_test.cpp
index 2763fe2bfd6..589b3e63cd0 100644
--- a/src/mongo/db/repl/tenant_migration_recipient_service_test.cpp
+++ b/src/mongo/db/repl/tenant_migration_recipient_service_test.cpp
@@ -181,11 +181,6 @@ public:
ConnectionString::setConnectionHook(mongo::MockConnRegistry::get()->getConnStrHook());
- // Set up clocks.
- serviceContext->setFastClockSource(std::make_unique<SharedClockSourceAdapter>(_clkSource));
- serviceContext->setPreciseClockSource(
- std::make_unique<SharedClockSourceAdapter>(_clkSource));
-
WaitForMajorityService::get(serviceContext).startup(serviceContext);
// Automatically mark the state doc garbage collectable after data sync completion.
@@ -256,10 +251,6 @@ public:
auto fetchCommittedTransactionsFp =
globalFailPointRegistry().find("skipFetchingCommittedTransactions");
fetchCommittedTransactionsFp->setMode(FailPoint::alwaysOn);
-
- // Timestamps of "0 seconds" are not allowed, so we must advance our clock mock to the first
- // real second.
- _clkSource->advance(Milliseconds(1000));
}
void tearDown() override {
@@ -305,6 +296,9 @@ public:
}
protected:
+ TenantMigrationRecipientServiceTest()
+ : ServiceContextMongoDTest(Options{}.useMockClock(true)) {}
+
PrimaryOnlyServiceRegistry* _registry;
PrimaryOnlyService* _service;
long long _term = 0;
@@ -416,14 +410,14 @@ protected:
* Advance the time by millis on both clock source mocks.
*/
void advanceTime(Milliseconds millis) {
- _clkSource->advance(millis);
+ _clkSource.advance(millis);
}
/**
* Assumes that the times on both clock source mocks is the same.
*/
Date_t now() {
- return _clkSource->now();
+ return _clkSource.now();
};
/*
@@ -456,11 +450,11 @@ protected:
}
ClockSource* clock() {
- return _clkSource.get();
+ return &_clkSource;
}
private:
- std::shared_ptr<ClockSourceMock> _clkSource = std::make_shared<ClockSourceMock>();
+ ClockSourceMock _clkSource;
unittest::MinimumLoggedSeverityGuard _replicationSeverityGuard{
logv2::LogComponent::kReplication, logv2::LogSeverity::Debug(1)};
diff --git a/src/mongo/db/s/balancer/migration_test_fixture.h b/src/mongo/db/s/balancer/migration_test_fixture.h
index 669133e0f36..76d13c587d7 100644
--- a/src/mongo/db/s/balancer/migration_test_fixture.h
+++ b/src/mongo/db/s/balancer/migration_test_fixture.h
@@ -46,6 +46,9 @@ namespace mongo {
class MigrationTestFixture : public ConfigServerTestFixture {
protected:
+ explicit MigrationTestFixture(Options options = {})
+ : ConfigServerTestFixture(std::move(options)) {}
+
void setUp() override;
/**
diff --git a/src/mongo/db/s/config/config_server_test_fixture.cpp b/src/mongo/db/s/config/config_server_test_fixture.cpp
index 6d378adf68d..6efbdd6d15c 100644
--- a/src/mongo/db/s/config/config_server_test_fixture.cpp
+++ b/src/mongo/db/s/config/config_server_test_fixture.cpp
@@ -92,7 +92,8 @@ namespace {
ReadPreferenceSetting kReadPref(ReadPreference::PrimaryOnly);
} // namespace
-ConfigServerTestFixture::ConfigServerTestFixture() = default;
+ConfigServerTestFixture::ConfigServerTestFixture(Options options, bool setUpMajorityReads)
+ : ShardingMongodTestFixture(std::move(options), setUpMajorityReads) {}
ConfigServerTestFixture::~ConfigServerTestFixture() = default;
diff --git a/src/mongo/db/s/config/config_server_test_fixture.h b/src/mongo/db/s/config/config_server_test_fixture.h
index f2d2d0a1ef0..2a990b778d7 100644
--- a/src/mongo/db/s/config/config_server_test_fixture.h
+++ b/src/mongo/db/s/config/config_server_test_fixture.h
@@ -48,7 +48,7 @@ class Shard;
*/
class ConfigServerTestFixture : public ShardingMongodTestFixture {
protected:
- ConfigServerTestFixture();
+ explicit ConfigServerTestFixture(Options options = {}, bool setUpMajorityReads = true);
~ConfigServerTestFixture();
void setUp() override;
diff --git a/src/mongo/db/s/config/sharding_catalog_manager_config_initialization_test.cpp b/src/mongo/db/s/config/sharding_catalog_manager_config_initialization_test.cpp
index 943be85f854..6c95002292b 100644
--- a/src/mongo/db/s/config/sharding_catalog_manager_config_initialization_test.cpp
+++ b/src/mongo/db/s/config/sharding_catalog_manager_config_initialization_test.cpp
@@ -81,6 +81,9 @@ void assertBSONObjsSame(const std::vector<BSONObj>& expectedBSON,
class ConfigInitializationTest : public ConfigServerTestFixture {
protected:
+ // TODO (SERVER-65308): Use wiredTiger.
+ ConfigInitializationTest() : ConfigServerTestFixture(Options{}.engine("ephemeralForTest")) {}
+
/*
* Initializes the sharding state and locks both the config db and rstl.
*/
diff --git a/src/mongo/db/s/migration_chunk_cloner_source_legacy_test.cpp b/src/mongo/db/s/migration_chunk_cloner_source_legacy_test.cpp
index 3f01fe4d3a7..0ec28d4b862 100644
--- a/src/mongo/db/s/migration_chunk_cloner_source_legacy_test.cpp
+++ b/src/mongo/db/s/migration_chunk_cloner_source_legacy_test.cpp
@@ -67,6 +67,8 @@ const ConnectionString kRecipientConnStr =
class MigrationChunkClonerSourceLegacyTest : public ShardServerTestFixture {
protected:
+ MigrationChunkClonerSourceLegacyTest() : ShardServerTestFixture(Options{}.useMockClock(true)) {}
+
void setUp() override {
ShardServerTestFixture::setUp();
@@ -98,14 +100,6 @@ protected:
->setFindHostReturnValue(kRecipientConnStr.getServers()[0]);
}
- auto clockSource = std::make_unique<ClockSourceMock>();
-
- // Timestamps of "0 seconds" are not allowed, so we must advance our clock mock to the first
- // real second.
- clockSource->advance(Seconds(1));
-
- operationContext()->getServiceContext()->setFastClockSource(std::move(clockSource));
-
_lsid = makeLogicalSessionId(operationContext());
}
diff --git a/src/mongo/db/s/resharding/resharding_coordinator_service_test.cpp b/src/mongo/db/s/resharding/resharding_coordinator_service_test.cpp
index 716a7278a36..e3b59a8068f 100644
--- a/src/mongo/db/s/resharding/resharding_coordinator_service_test.cpp
+++ b/src/mongo/db/s/resharding/resharding_coordinator_service_test.cpp
@@ -127,6 +127,10 @@ class ReshardingCoordinatorServiceTest : public ConfigServerTestFixture {
public:
using ReshardingCoordinator = ReshardingCoordinatorService::ReshardingCoordinator;
+ // TODO (SERVER-65302): Use wiredTiger.
+ ReshardingCoordinatorServiceTest()
+ : ConfigServerTestFixture(Options{}.engine("ephemeralForTest")) {}
+
std::unique_ptr<repl::PrimaryOnlyService> makeService(ServiceContext* serviceContext) {
return std::make_unique<ReshardingCoordinatorServiceForTest>(serviceContext);
}
diff --git a/src/mongo/db/s/resharding/resharding_donor_recipient_common_test.cpp b/src/mongo/db/s/resharding/resharding_donor_recipient_common_test.cpp
index f4437351785..3fccff9812c 100644
--- a/src/mongo/db/s/resharding/resharding_donor_recipient_common_test.cpp
+++ b/src/mongo/db/s/resharding/resharding_donor_recipient_common_test.cpp
@@ -32,6 +32,7 @@
#include "mongo/db/db_raii.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/persistent_task_store.h"
+#include "mongo/db/repl/oplog.h"
#include "mongo/db/repl/wait_for_majority_service.h"
#include "mongo/db/s/collection_sharding_runtime.h"
#include "mongo/db/s/operation_sharding_state.h"
@@ -315,8 +316,11 @@ public:
ASSERT_OK(replCoord->setFollowerMode(repl::MemberState::RS_PRIMARY));
ASSERT_OK(replCoord->updateTerm(operationContext(), _term));
- replCoord->setMyLastAppliedOpTimeAndWallTime(
- repl::OpTimeAndWallTime(repl::OpTime(Timestamp(1, 1), _term), Date_t()));
+
+ WriteUnitOfWork wuow{operationContext()};
+ replCoord->setMyLastAppliedOpTimeAndWallTime(repl::OpTimeAndWallTime(
+ repl::OpTime(repl::getNextOpTime(operationContext()).getTimestamp(), _term), Date_t()));
+ wuow.commit();
_primaryOnlyServiceRegistry->onStepUpComplete(operationContext(), _term);
}
diff --git a/src/mongo/db/s/resharding/resharding_oplog_batch_applier_test.cpp b/src/mongo/db/s/resharding/resharding_oplog_batch_applier_test.cpp
index f1361bfb165..c9d188252a8 100644
--- a/src/mongo/db/s/resharding/resharding_oplog_batch_applier_test.cpp
+++ b/src/mongo/db/s/resharding/resharding_oplog_batch_applier_test.cpp
@@ -298,6 +298,11 @@ public:
<< sessionTxnRecord.toBSON() << ", " << foundOp;
}
+protected:
+ // TODO (SERVER-65307): Use wiredTiger.
+ ReshardingOplogBatchApplierTest()
+ : ServiceContextMongoDTest(Options{}.engine("ephemeralForTest")) {}
+
private:
ChunkManager makeChunkManagerForSourceCollection() {
const OID epoch = OID::gen();
diff --git a/src/mongo/db/s/resharding/resharding_oplog_session_application_test.cpp b/src/mongo/db/s/resharding/resharding_oplog_session_application_test.cpp
index dfaa498e4f6..00d3f6af370 100644
--- a/src/mongo/db/s/resharding/resharding_oplog_session_application_test.cpp
+++ b/src/mongo/db/s/resharding/resharding_oplog_session_application_test.cpp
@@ -310,6 +310,11 @@ public:
return _oplogBufferNss;
}
+protected:
+ // TODO (SERVER-65306): Use wiredTiger.
+ ReshardingOplogSessionApplicationTest()
+ : ServiceContextMongoDTest(Options{}.engine("ephemeralForTest")) {}
+
private:
// Used for pre/post image oplog entry lookup.
const ShardId _donorShardId{"donor-0"};
diff --git a/src/mongo/db/s/resharding/resharding_txn_cloner_test.cpp b/src/mongo/db/s/resharding/resharding_txn_cloner_test.cpp
index c41f4ce7db3..290a8837e9f 100644
--- a/src/mongo/db/s/resharding/resharding_txn_cloner_test.cpp
+++ b/src/mongo/db/s/resharding/resharding_txn_cloner_test.cpp
@@ -150,6 +150,9 @@ class ReshardingTxnClonerTest : public ShardServerTestFixture {
}
protected:
+ // TODO (SERVER-65303): Use wiredTiger.
+ ReshardingTxnClonerTest() : ShardServerTestFixture(Options{}.engine("ephemeralForTest")) {}
+
const UUID kDefaultReshardingId = UUID::gen();
const std::vector<ShardId> kTwoShardIdList{_myShardName, {"otherShardName"}};
const std::vector<ReshardingSourceId> kTwoSourceIdList = {
diff --git a/src/mongo/db/s/shard_local_test.cpp b/src/mongo/db/s/shard_local_test.cpp
index 9cbed53e039..427c624b0e8 100644
--- a/src/mongo/db/s/shard_local_test.cpp
+++ b/src/mongo/db/s/shard_local_test.cpp
@@ -39,6 +39,7 @@
#include "mongo/db/repl/replication_coordinator_mock.h"
#include "mongo/db/s/shard_local.h"
#include "mongo/db/service_context_d_test_fixture.h"
+#include "mongo/db/storage/snapshot_manager.h"
#include "mongo/db/write_concern_options.h"
#include "mongo/s/client/shard_registry.h"
@@ -90,6 +91,14 @@ void ShardLocalTest::setUp() {
new repl::ReplicationCoordinatorMock(_opCtx->getServiceContext(), replSettings)));
ASSERT_OK(repl::ReplicationCoordinator::get(getGlobalServiceContext())
->setFollowerMode(repl::MemberState::RS_PRIMARY));
+
+ repl::createOplog(_opCtx.get());
+
+ // Set a committed snapshot so that we can perform majority reads.
+ WriteUnitOfWork wuow{_opCtx.get()};
+ _opCtx->getServiceContext()->getStorageEngine()->getSnapshotManager()->setCommittedSnapshot(
+ repl::getNextOpTime(_opCtx.get()).getTimestamp());
+ wuow.commit();
}
void ShardLocalTest::tearDown() {
diff --git a/src/mongo/db/s/shard_server_test_fixture.cpp b/src/mongo/db/s/shard_server_test_fixture.cpp
index 2c65e268b1b..fe4de75a820 100644
--- a/src/mongo/db/s/shard_server_test_fixture.cpp
+++ b/src/mongo/db/s/shard_server_test_fixture.cpp
@@ -44,7 +44,8 @@ namespace mongo {
const HostAndPort ShardServerTestFixture::kConfigHostAndPort("dummy", 123);
-ShardServerTestFixture::ShardServerTestFixture() = default;
+ShardServerTestFixture::ShardServerTestFixture(Options options, bool setUpMajorityReads)
+ : ShardingMongodTestFixture(std::move(options), setUpMajorityReads) {}
ShardServerTestFixture::~ShardServerTestFixture() = default;
diff --git a/src/mongo/db/s/shard_server_test_fixture.h b/src/mongo/db/s/shard_server_test_fixture.h
index 57adbc030ba..a92316ed1f9 100644
--- a/src/mongo/db/s/shard_server_test_fixture.h
+++ b/src/mongo/db/s/shard_server_test_fixture.h
@@ -40,7 +40,7 @@ namespace mongo {
*/
class ShardServerTestFixture : public ShardingMongodTestFixture {
protected:
- ShardServerTestFixture();
+ ShardServerTestFixture(Options options = {}, bool setUpMajorityReads = true);
~ShardServerTestFixture();
void setUp() override;
diff --git a/src/mongo/db/s/sharding_mongod_test_fixture.cpp b/src/mongo/db/s/sharding_mongod_test_fixture.cpp
index abf6df3ff4f..a05fddaa213 100644
--- a/src/mongo/db/s/sharding_mongod_test_fixture.cpp
+++ b/src/mongo/db/s/sharding_mongod_test_fixture.cpp
@@ -56,6 +56,7 @@
#include "mongo/db/s/op_observer_sharding_impl.h"
#include "mongo/db/s/shard_local.h"
#include "mongo/db/s/shard_server_op_observer.h"
+#include "mongo/db/storage/snapshot_manager.h"
#include "mongo/executor/task_executor_pool.h"
#include "mongo/executor/thread_pool_task_executor_test_fixture.h"
#include "mongo/rpc/metadata/repl_set_metadata.h"
@@ -85,7 +86,8 @@ using repl::ReplicationCoordinatorMock;
using repl::ReplSettings;
using unittest::assertGet;
-ShardingMongodTestFixture::ShardingMongodTestFixture() {}
+ShardingMongodTestFixture::ShardingMongodTestFixture(Options options, bool setUpMajorityReads)
+ : ServiceContextMongoDTest(std::move(options)), _setUpMajorityReads(setUpMajorityReads) {}
ShardingMongodTestFixture::~ShardingMongodTestFixture() = default;
@@ -281,6 +283,13 @@ void ShardingMongodTestFixture::setUp() {
// testing this release's code, not backwards compatibility code.
// (Generic FCV reference): This FCV reference should exist across LTS binary versions.
serverGlobalParams.mutableFeatureCompatibility.setVersion(multiversion::GenericFCV::kLatest);
+
+ if (_setUpMajorityReads && service->getStorageEngine()->getSnapshotManager()) {
+ WriteUnitOfWork wuow{operationContext()};
+ service->getStorageEngine()->getSnapshotManager()->setCommittedSnapshot(
+ repl::getNextOpTime(operationContext()).getTimestamp());
+ wuow.commit();
+ }
}
void ShardingMongodTestFixture::tearDown() {
diff --git a/src/mongo/db/s/sharding_mongod_test_fixture.h b/src/mongo/db/s/sharding_mongod_test_fixture.h
index b80d234a9ac..1c3a64e5a70 100644
--- a/src/mongo/db/s/sharding_mongod_test_fixture.h
+++ b/src/mongo/db/s/sharding_mongod_test_fixture.h
@@ -52,7 +52,7 @@ namespace mongo {
class ShardingMongodTestFixture : public ShardingTestFixtureCommon,
public ServiceContextMongoDTest {
protected:
- ShardingMongodTestFixture();
+ ShardingMongodTestFixture(Options options = {}, bool allowMajorityReads = true);
~ShardingMongodTestFixture();
void setUp() override;
@@ -143,6 +143,10 @@ private:
// Records if a component has been shut down, so that it is only shut down once.
bool _executorPoolShutDown = false;
+
+ // Whether the test fixture should set a committed snapshot during setup so that tests can
+ // perform majority reads without doing any writes.
+ bool _setUpMajorityReads;
};
} // namespace mongo
diff --git a/src/mongo/db/s/vector_clock_config_server_test.cpp b/src/mongo/db/s/vector_clock_config_server_test.cpp
index 14694f697d0..f304b321323 100644
--- a/src/mongo/db/s/vector_clock_config_server_test.cpp
+++ b/src/mongo/db/s/vector_clock_config_server_test.cpp
@@ -42,12 +42,12 @@ namespace {
class VectorClockConfigServerTest : public ConfigServerTestFixture {
protected:
+ VectorClockConfigServerTest()
+ : ConfigServerTestFixture(Options{}.useMockClock(true), false /* setUpMajorityReads */) {}
+
void setUp() override {
ConfigServerTestFixture::setUp();
- auto clockSource = std::make_unique<ClockSourceMock>();
- getServiceContext()->setFastClockSource(std::move(clockSource));
-
auto keysCollectionClient = std::make_unique<KeysCollectionClientSharded>(
Grid::get(operationContext())->catalogClient());
diff --git a/src/mongo/db/s/vector_clock_shard_server_test.cpp b/src/mongo/db/s/vector_clock_shard_server_test.cpp
index 0674419fc34..de575294c3c 100644
--- a/src/mongo/db/s/vector_clock_shard_server_test.cpp
+++ b/src/mongo/db/s/vector_clock_shard_server_test.cpp
@@ -44,12 +44,12 @@ namespace {
class VectorClockShardServerTest : public ShardServerTestFixture {
protected:
+ VectorClockShardServerTest()
+ : ShardServerTestFixture(Options{}.useMockClock(true), false /* setUpMajorityReads */) {}
+
void setUp() override {
ShardServerTestFixture::setUp();
- auto clockSource = std::make_unique<ClockSourceMock>();
- getServiceContext()->setFastClockSource(std::move(clockSource));
-
auto keysCollectionClient = std::make_unique<KeysCollectionClientDirect>();
VectorClockMutable::get(getServiceContext())
diff --git a/src/mongo/db/serverless/shard_split_donor_service_test.cpp b/src/mongo/db/serverless/shard_split_donor_service_test.cpp
index 2e0e3822c64..ad51e94e358 100644
--- a/src/mongo/db/serverless/shard_split_donor_service_test.cpp
+++ b/src/mongo/db/serverless/shard_split_donor_service_test.cpp
@@ -228,6 +228,10 @@ public:
}
protected:
+ // TODO (SERVER-65218): Use wiredTiger.
+ ShardSplitDonorServiceTest()
+ : repl::PrimaryOnlyServiceMongoDTest(Options{}.engine("ephemeralForTest")) {}
+
std::unique_ptr<repl::PrimaryOnlyService> makeService(ServiceContext* serviceContext) override {
return std::make_unique<ShardSplitDonorService>(serviceContext);
}
diff --git a/src/mongo/db/service_context_d_test_fixture.cpp b/src/mongo/db/service_context_d_test_fixture.cpp
index c5aaed6c870..96b521111f8 100644
--- a/src/mongo/db/service_context_d_test_fixture.cpp
+++ b/src/mongo/db/service_context_d_test_fixture.cpp
@@ -46,6 +46,7 @@
#include "mongo/db/index_builds_coordinator_mongod.h"
#include "mongo/db/op_observer_registry.h"
#include "mongo/db/repl/repl_settings.h"
+#include "mongo/db/repl/replication_coordinator_mock.h"
#include "mongo/db/s/collection_sharding_state_factory_shard.h"
#include "mongo/db/service_entry_point_mongod.h"
#include "mongo/db/storage/control/storage_control.h"
@@ -58,31 +59,22 @@
namespace mongo {
-ServiceContextMongoDTest::ServiceContextMongoDTest()
- : ServiceContextMongoDTest("ephemeralForTest") {}
-
-ServiceContextMongoDTest::ServiceContextMongoDTest(std::string engine)
- : ServiceContextMongoDTest(engine, RepairAction::kNoRepair) {}
-
-ServiceContextMongoDTest::ServiceContextMongoDTest(std::string engine,
- RepairAction repair,
- StorageEngineInitFlags initFlags,
- bool useReplSettings,
- bool useMockClock)
+ServiceContextMongoDTest::ServiceContextMongoDTest(Options options)
: _tempDir("service_context_d_test_fixture") {
- if (useReplSettings) {
+ if (options._useReplSettings) {
repl::ReplSettings replSettings;
replSettings.setOplogSizeBytes(10 * 1024 * 1024);
replSettings.setReplSetString("rs0");
setGlobalReplSettings(replSettings);
}
- _stashedStorageParams.engine = std::exchange(storageGlobalParams.engine, std::move(engine));
+ _stashedStorageParams.engine =
+ std::exchange(storageGlobalParams.engine, std::move(options._engine));
_stashedStorageParams.engineSetByUser =
std::exchange(storageGlobalParams.engineSetByUser, true);
_stashedStorageParams.repair =
- std::exchange(storageGlobalParams.repair, (repair == RepairAction::kRepair));
+ std::exchange(storageGlobalParams.repair, (options._repair == RepairAction::kRepair));
_stashedServerParams.enableMajorityReadConcern = serverGlobalParams.enableMajorityReadConcern;
if (storageGlobalParams.engine == "ephemeralForTest" ||
@@ -95,7 +87,7 @@ ServiceContextMongoDTest::ServiceContextMongoDTest(std::string engine,
}
auto const serviceContext = getServiceContext();
- if (useMockClock) {
+ if (options._useMockClock) {
// Copied from dbtests.cpp. DBTests sets up a controlled mock clock while
// ServiceContextMongoDTest uses the system clock. Tests moved from dbtests to unittests may
// depend on a deterministic clock.
@@ -125,7 +117,7 @@ ServiceContextMongoDTest::ServiceContextMongoDTest(std::string engine,
// Since unit tests start in their own directories, by default skip lock file and metadata file
// for faster startup.
auto opCtx = serviceContext->makeOperationContext(getClient());
- initializeStorageEngine(opCtx.get(), initFlags);
+ initializeStorageEngine(opCtx.get(), options._initFlags);
StorageControl::startStorageControls(serviceContext, true /*forTestOnly*/);
DatabaseHolder::set(serviceContext, std::make_unique<DatabaseHolderImpl>());
@@ -142,10 +134,16 @@ ServiceContextMongoDTest::~ServiceContextMongoDTest() {
CollectionShardingStateFactory::clear(getServiceContext());
{
- auto opCtx = getClient()->makeOperationContext();
- Lock::GlobalLock glk(opCtx.get(), MODE_X);
- auto databaseHolder = DatabaseHolder::get(opCtx.get());
- databaseHolder->closeAll(opCtx.get());
+ ServiceContext::UniqueOperationContext uniqueOpCtx;
+ auto opCtx = getClient()->getOperationContext();
+ if (!opCtx) {
+ uniqueOpCtx = getClient()->makeOperationContext();
+ opCtx = uniqueOpCtx.get();
+ }
+
+ Lock::GlobalLock glk(opCtx, MODE_X);
+ auto databaseHolder = DatabaseHolder::get(opCtx);
+ databaseHolder->closeAll(opCtx);
}
shutdownGlobalStorageEngineCleanly(getServiceContext());
diff --git a/src/mongo/db/service_context_d_test_fixture.h b/src/mongo/db/service_context_d_test_fixture.h
index 539bf087634..f615ffe31d8 100644
--- a/src/mongo/db/service_context_d_test_fixture.h
+++ b/src/mongo/db/service_context_d_test_fixture.h
@@ -46,17 +46,43 @@ public:
protected:
enum class RepairAction { kNoRepair, kRepair };
- ServiceContextMongoDTest();
-
- /**
- * Build a ServiceContextMongoDTest, using the named storage engine.
- */
- explicit ServiceContextMongoDTest(std::string engine);
- ServiceContextMongoDTest(std::string engine,
- RepairAction repair,
- StorageEngineInitFlags initFlags = kDefaultStorageEngineInitFlags,
- bool useReplSettings = false,
- bool useMockClock = false);
+ class Options {
+ public:
+ Options(){};
+
+ Options& engine(std::string engine) {
+ _engine = std::move(engine);
+ return *this;
+ }
+ Options& repair(RepairAction repair) {
+ _repair = repair;
+ return *this;
+ }
+ Options& initFlags(StorageEngineInitFlags initFlags) {
+ _initFlags = initFlags;
+ return *this;
+ }
+ Options& useReplSettings(bool useReplSettings) {
+ _useReplSettings = useReplSettings;
+ return *this;
+ }
+ Options& useMockClock(bool useMockClock) {
+ _useMockClock = useMockClock;
+ return *this;
+ }
+
+ private:
+ std::string _engine = "wiredTiger";
+ RepairAction _repair = RepairAction::kNoRepair;
+ StorageEngineInitFlags _initFlags = kDefaultStorageEngineInitFlags;
+ bool _useReplSettings = false;
+ bool _useMockClock = false;
+
+ friend class ServiceContextMongoDTest;
+ };
+
+ explicit ServiceContextMongoDTest(Options options = {});
+
virtual ~ServiceContextMongoDTest();
void tearDown() override;
diff --git a/src/mongo/db/service_context_devnull_test_fixture.cpp b/src/mongo/db/service_context_devnull_test_fixture.cpp
index d1f69034f5e..c420b7eaa2c 100644
--- a/src/mongo/db/service_context_devnull_test_fixture.cpp
+++ b/src/mongo/db/service_context_devnull_test_fixture.cpp
@@ -34,6 +34,6 @@
namespace mongo {
ServiceContextDevnullTestFixture::ServiceContextDevnullTestFixture()
- : ServiceContextMongoDTest("devnull") {}
+ : ServiceContextMongoDTest(Options{}.engine("devnull")) {}
} // namespace mongo
diff --git a/src/mongo/db/session_catalog_mongod_test.cpp b/src/mongo/db/session_catalog_mongod_test.cpp
index e7519fc6f9c..1b4ea856605 100644
--- a/src/mongo/db/session_catalog_mongod_test.cpp
+++ b/src/mongo/db/session_catalog_mongod_test.cpp
@@ -42,6 +42,8 @@ namespace {
class MongoDSessionCatalogTest : public ServiceContextMongoDTest {
protected:
+ MongoDSessionCatalogTest() : ServiceContextMongoDTest(Options{}.useMockClock(true)) {}
+
void setUp() override {
ServiceContextMongoDTest::setUp();
const auto service = getServiceContext();
@@ -50,8 +52,6 @@ protected:
repl::ReplicationCoordinator::set(service, std::move(replCoord));
repl::createOplog(_opCtx);
-
- service->setFastClockSource(std::make_unique<ClockSourceMock>());
}
ClockSourceMock* clock() {
diff --git a/src/mongo/db/storage/kv/durable_catalog_test.cpp b/src/mongo/db/storage/kv/durable_catalog_test.cpp
index 787a6c3b353..14994f957e8 100644
--- a/src/mongo/db/storage/kv/durable_catalog_test.cpp
+++ b/src/mongo/db/storage/kv/durable_catalog_test.cpp
@@ -62,6 +62,9 @@ static const long kExpectedVersion = 1;
class DurableCatalogTest : public CatalogTestFixture {
public:
+ // TODO (SERVER-65189): Use wiredTiger.
+ DurableCatalogTest() : CatalogTestFixture(Options{}.engine("ephemeralForTest")) {}
+
void setUp() final {
CatalogTestFixture::setUp();
@@ -224,6 +227,7 @@ TEST_F(DurableCatalogTest, CanSetIndividualPathComponentOfBtreeIndexAsMultikey)
auto collection = getCollection();
{
+ Lock::GlobalLock globalLock{operationContext(), MODE_IX};
WriteUnitOfWork wuow(operationContext());
ASSERT(collection->setIndexIsMultikey(operationContext(),
indexEntry->descriptor()->indexName(),
@@ -244,6 +248,7 @@ TEST_F(DurableCatalogTest, MultikeyPathsAccumulateOnDifferentFields) {
auto collection = getCollection();
{
+ Lock::GlobalLock globalLock{operationContext(), MODE_IX};
WriteUnitOfWork wuow(operationContext());
ASSERT(collection->setIndexIsMultikey(operationContext(),
indexEntry->descriptor()->indexName(),
@@ -259,6 +264,7 @@ TEST_F(DurableCatalogTest, MultikeyPathsAccumulateOnDifferentFields) {
}
{
+ Lock::GlobalLock globalLock{operationContext(), MODE_IX};
WriteUnitOfWork wuow(operationContext());
ASSERT(collection->setIndexIsMultikey(operationContext(),
indexEntry->descriptor()->indexName(),
@@ -279,6 +285,7 @@ TEST_F(DurableCatalogTest, MultikeyPathsAccumulateOnDifferentComponentsOfTheSame
auto collection = getCollection();
{
+ Lock::GlobalLock globalLock{operationContext(), MODE_IX};
WriteUnitOfWork wuow(operationContext());
ASSERT(collection->setIndexIsMultikey(
operationContext(), indexEntry->descriptor()->indexName(), {{0U}}));
@@ -293,6 +300,7 @@ TEST_F(DurableCatalogTest, MultikeyPathsAccumulateOnDifferentComponentsOfTheSame
}
{
+ Lock::GlobalLock globalLock{operationContext(), MODE_IX};
WriteUnitOfWork wuow(operationContext());
ASSERT(collection->setIndexIsMultikey(
operationContext(), indexEntry->descriptor()->indexName(), {{1U}}));
@@ -312,6 +320,7 @@ TEST_F(DurableCatalogTest, NoOpWhenSpecifiedPathComponentsAlreadySetAsMultikey)
auto collection = getCollection();
{
+ Lock::GlobalLock globalLock{operationContext(), MODE_IX};
WriteUnitOfWork wuow(operationContext());
ASSERT(collection->setIndexIsMultikey(
operationContext(), indexEntry->descriptor()->indexName(), {{0U}}));
@@ -326,6 +335,7 @@ TEST_F(DurableCatalogTest, NoOpWhenSpecifiedPathComponentsAlreadySetAsMultikey)
}
{
+ Lock::GlobalLock globalLock{operationContext(), MODE_IX};
WriteUnitOfWork wuow(operationContext());
ASSERT(!collection->setIndexIsMultikey(
operationContext(), indexEntry->descriptor()->indexName(), {{0U}}));
@@ -344,6 +354,7 @@ TEST_F(DurableCatalogTest, CanSetMultipleFieldsAndComponentsAsMultikey) {
auto indexEntry = createIndex(BSON("a.b.c" << 1 << "a.b.d" << 1));
auto collection = getCollection();
{
+ Lock::GlobalLock globalLock{operationContext(), MODE_IX};
WriteUnitOfWork wuow(operationContext());
ASSERT(collection->setIndexIsMultikey(
operationContext(), indexEntry->descriptor()->indexName(), {{0U, 1U}, {0U, 1U}}));
@@ -364,6 +375,7 @@ DEATH_TEST_REGEX_F(DurableCatalogTest,
auto indexEntry = createIndex(BSON("a" << 1 << "b" << 1));
auto collection = getCollection();
+ Lock::GlobalLock globalLock{operationContext(), MODE_IX};
WriteUnitOfWork wuow(operationContext());
collection->setIndexIsMultikey(
operationContext(), indexEntry->descriptor()->indexName(), MultikeyPaths{});
@@ -375,6 +387,7 @@ DEATH_TEST_REGEX_F(DurableCatalogTest,
auto indexEntry = createIndex(BSON("a" << 1 << "b" << 1));
auto collection = getCollection();
+ Lock::GlobalLock globalLock{operationContext(), MODE_IX};
WriteUnitOfWork wuow(operationContext());
collection->setIndexIsMultikey(operationContext(),
@@ -415,6 +428,7 @@ TEST_F(DurableCatalogTest, CanSetEntireTextIndexAsMultikey) {
auto collection = getCollection();
{
+ Lock::GlobalLock globalLock{operationContext(), MODE_IX};
WriteUnitOfWork wuow(operationContext());
ASSERT(collection->setIndexIsMultikey(
operationContext(), indexEntry->descriptor()->indexName(), MultikeyPaths{}));
@@ -435,6 +449,7 @@ TEST_F(DurableCatalogTest, NoOpWhenEntireIndexAlreadySetAsMultikey) {
auto collection = getCollection();
{
+ Lock::GlobalLock globalLock{operationContext(), MODE_IX};
WriteUnitOfWork wuow(operationContext());
ASSERT(collection->setIndexIsMultikey(
operationContext(), indexEntry->descriptor()->indexName(), MultikeyPaths{}));
@@ -449,6 +464,7 @@ TEST_F(DurableCatalogTest, NoOpWhenEntireIndexAlreadySetAsMultikey) {
}
{
+ Lock::GlobalLock globalLock{operationContext(), MODE_IX};
WriteUnitOfWork wuow(operationContext());
ASSERT(!collection->setIndexIsMultikey(
operationContext(), indexEntry->descriptor()->indexName(), MultikeyPaths{}));
@@ -515,6 +531,7 @@ DEATH_TEST_REGEX_F(DurableCatalogTest,
auto indexEntry = createIndex(BSON("a" << indexType << "b" << 1), indexType);
auto collection = getCollection();
+ Lock::GlobalLock globalLock{operationContext(), MODE_IX};
WriteUnitOfWork wuow(operationContext());
collection->setIndexIsMultikey(
operationContext(), indexEntry->descriptor()->indexName(), {{0U}, {0U}});
@@ -656,6 +673,7 @@ TEST_F(DurableCatalogTest, CheckTimeseriesBucketsMayHaveMixedSchemaDataFlagFCVLa
const NamespaceString regularNss = NamespaceString("test.regular");
createCollection(regularNss, CollectionOptions());
+ Lock::GlobalLock globalLock{operationContext(), MODE_IS};
auto collection = CollectionCatalog::get(operationContext())
->lookupCollectionByNamespace(operationContext(), regularNss);
RecordId catalogId = collection->getCatalogId();
@@ -670,6 +688,7 @@ TEST_F(DurableCatalogTest, CheckTimeseriesBucketsMayHaveMixedSchemaDataFlagFCVLa
options.timeseries = TimeseriesOptions(/*timeField=*/"t");
createCollection(bucketsNss, options);
+ Lock::GlobalLock globalLock{operationContext(), MODE_IS};
auto collection = CollectionCatalog::get(operationContext())
->lookupCollectionByNamespace(operationContext(), bucketsNss);
RecordId catalogId = collection->getCatalogId();
diff --git a/src/mongo/db/storage/kv/storage_engine_test.cpp b/src/mongo/db/storage/kv/storage_engine_test.cpp
index 46f5ffe64d7..1fbdc65188d 100644
--- a/src/mongo/db/storage/kv/storage_engine_test.cpp
+++ b/src/mongo/db/storage/kv/storage_engine_test.cpp
@@ -130,7 +130,6 @@ TEST_F(StorageEngineTest, TemporaryRecordStoreClustered) {
WriteUnitOfWork wuow(opCtx.get());
StatusWith<RecordId> s = rs->insertRecord(opCtx.get(), rid, data, strlen(data), Timestamp());
ASSERT_TRUE(s.isOK());
- ASSERT_EQUALS(1, rs->numRecords(opCtx.get()));
wuow.commit();
// Read the record back.
@@ -175,13 +174,7 @@ TEST_F(StorageEngineTest, ReconcileKeepsTemporary) {
ASSERT_EQUALS(0UL, reconcileResult.indexesToRebuild.size());
ASSERT_EQUALS(0UL, reconcileResult.indexBuildsToRestart.size());
- if (_storageEngine->supportsResumableIndexBuilds()) {
- // The storage engine does not drop its temporary idents outside of starting up after an
- // unclean shutdown.
- ASSERT(identExists(opCtx.get(), ident));
- } else {
- ASSERT_FALSE(identExists(opCtx.get(), ident));
- }
+ ASSERT_FALSE(identExists(opCtx.get(), ident));
}
class StorageEngineTimestampMonitorTest : public StorageEngineTest {
@@ -685,7 +678,7 @@ TEST_F(TimestampKVEngineTest, TimestampAdvancesOnNotification) {
_storageEngine->getTimestampMonitor()->clearListeners();
}
-TEST_F(StorageEngineDurableTest, UseAlternateStorageLocation) {
+TEST_F(StorageEngineTest, UseAlternateStorageLocation) {
auto opCtx = cc().makeOperationContext();
const NamespaceString coll1Ns("db.coll1");
diff --git a/src/mongo/db/storage/storage_engine_test_fixture.h b/src/mongo/db/storage/storage_engine_test_fixture.h
index 266052614a7..db8f499f42b 100644
--- a/src/mongo/db/storage/storage_engine_test_fixture.h
+++ b/src/mongo/db/storage/storage_engine_test_fixture.h
@@ -48,23 +48,14 @@ namespace mongo {
class StorageEngineTest : public ServiceContextMongoDTest {
public:
- StorageEngineTest(RepairAction repair,
- const std::string& storageEngine,
- StorageEngineInitFlags initFlags)
- : ServiceContextMongoDTest(storageEngine, repair, initFlags),
- _storageEngine(getServiceContext()->getStorageEngine()) {}
-
- StorageEngineTest(const std::string& storageEngine, StorageEngineInitFlags initFlags)
- : StorageEngineTest(RepairAction::kNoRepair, storageEngine, initFlags) {
- auto serviceCtx = getServiceContext();
+ explicit StorageEngineTest(Options options = {})
+ : ServiceContextMongoDTest(std::move(options)),
+ _storageEngine(getServiceContext()->getStorageEngine()) {
repl::ReplicationCoordinator::set(
- serviceCtx, std::make_unique<repl::ReplicationCoordinatorMock>(serviceCtx));
+ getServiceContext(),
+ std::make_unique<repl::ReplicationCoordinatorMock>(getServiceContext()));
}
- StorageEngineTest()
- : StorageEngineTest("ephemeralForTest",
- ServiceContextMongoDTest::kDefaultStorageEngineInitFlags) {}
-
StatusWith<DurableCatalog::Entry> createCollection(OperationContext* opCtx,
NamespaceString ns) {
AutoGetDb db(opCtx, ns.db(), LockMode::MODE_X);
@@ -121,6 +112,7 @@ public:
}
StatusWith<StorageEngine::ReconcileResult> reconcile(OperationContext* opCtx) {
+ Lock::GlobalLock globalLock{opCtx, MODE_IX};
return _storageEngine->reconcileCatalogAndIdents(opCtx,
StorageEngine::LastShutdownState::kClean);
}
@@ -207,10 +199,9 @@ public:
class StorageEngineRepairTest : public StorageEngineTest {
public:
+ // TODO (SERVER-65191): Use wiredTiger.
StorageEngineRepairTest()
- : StorageEngineTest(RepairAction::kRepair,
- "ephemeralForTest",
- ServiceContextMongoDTest::kDefaultStorageEngineInitFlags) {}
+ : StorageEngineTest(Options{}.engine("ephemeralForTest").repair(RepairAction::kRepair)) {}
void tearDown() {
auto repairObserver = StorageRepairObserver::get(getGlobalServiceContext());
@@ -228,9 +219,4 @@ public:
}
};
-class StorageEngineDurableTest : public StorageEngineTest {
-public:
- StorageEngineDurableTest() : StorageEngineTest("wiredTiger", StorageEngineInitFlags()) {}
-};
-
} // namespace mongo
diff --git a/src/mongo/db/storage/storage_repair_observer_test.cpp b/src/mongo/db/storage/storage_repair_observer_test.cpp
index 2fe3cc786d0..204ba7fc7de 100644
--- a/src/mongo/db/storage/storage_repair_observer_test.cpp
+++ b/src/mongo/db/storage/storage_repair_observer_test.cpp
@@ -53,8 +53,7 @@ using boost::filesystem::path;
class StorageRepairObserverTest : public ServiceContextMongoDTest {
public:
- StorageRepairObserverTest() : ServiceContextMongoDTest("ephemeralForTest") {
-
+ StorageRepairObserverTest() {
repl::ReplicationCoordinator::set(
getServiceContext(),
std::make_unique<repl::ReplicationCoordinatorMock>(getServiceContext()));
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp
index 3cb2aca26a3..b13db8fd9d4 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp
@@ -150,8 +150,7 @@ bool WiredTigerFileVersion::shouldDowngrade(bool readOnly, bool hasRecoveryTimes
}
const auto replCoord = repl::ReplicationCoordinator::get(getGlobalServiceContext());
- const auto memberState = replCoord->getMemberState();
- if (memberState.arbiter()) {
+ if (replCoord && replCoord->getMemberState().arbiter()) {
// SERVER-35361: Arbiters will no longer downgrade their data files. To downgrade
// binaries, the user must delete the dbpath. It's not particularly expensive for a
// replica set to re-initialize an arbiter that comes online.
diff --git a/src/mongo/db/transaction_participant_test.cpp b/src/mongo/db/transaction_participant_test.cpp
index f53255e9ce4..25fd8403f2c 100644
--- a/src/mongo/db/transaction_participant_test.cpp
+++ b/src/mongo/db/transaction_participant_test.cpp
@@ -3360,8 +3360,14 @@ std::string buildTransactionInfoString(OperationContext* opCtx,
<< singleTransactionStatsInfo.str()
<< " terminationCause:" << terminationCause
<< timeActiveAndInactiveInfo.str() << " numYields:" << 0
- << " locks:" << locks.done().toString()
- << " wasPrepared:" << wasPrepared;
+ << " locks:" << locks.done().toString();
+
+ if (auto& storageStats = CurOp::get(opCtx)->debug().storageStats) {
+ expectedTransactionInfo << " storage:" << storageStats->toBSON();
+ }
+
+ expectedTransactionInfo << " wasPrepared:" << wasPrepared;
+
if (wasPrepared) {
StringBuilder totalPreparedDuration;
buildPreparedDurationString(
diff --git a/src/mongo/db/vector_clock_mongod_test.cpp b/src/mongo/db/vector_clock_mongod_test.cpp
index 51166840c89..9351b6438ff 100644
--- a/src/mongo/db/vector_clock_mongod_test.cpp
+++ b/src/mongo/db/vector_clock_mongod_test.cpp
@@ -50,12 +50,12 @@ namespace {
*/
class VectorClockMongoDTest : public ShardingMongodTestFixture {
protected:
+ VectorClockMongoDTest()
+ : ShardingMongodTestFixture(Options{}.useMockClock(true), false /* setUpMajorityReads */) {}
+
void setUp() override {
ShardingMongodTestFixture::setUp();
- auto clockSource = std::make_unique<ClockSourceMock>();
- getServiceContext()->setFastClockSource(std::move(clockSource));
-
auto keysCollectionClient = std::make_unique<KeysCollectionClientDirect>();
VectorClockMutable::get(getServiceContext())
diff --git a/src/mongo/db/vector_clock_test.cpp b/src/mongo/db/vector_clock_test.cpp
index 9d462b85c10..77e194e8478 100644
--- a/src/mongo/db/vector_clock_test.cpp
+++ b/src/mongo/db/vector_clock_test.cpp
@@ -65,7 +65,7 @@ TEST_F(VectorClockTest, roundtrip) {
VectorClockMutable::get(getServiceContext())->tickClusterTimeTo(time);
auto storedTime(getClusterTime());
- ASSERT_TRUE(storedTime == time);
+ ASSERT_EQ(storedTime, time);
}
// Verify the reserve ticks functionality.
@@ -75,28 +75,28 @@ TEST_F(VectorClockTest, reserveTicks) {
auto t1 = VectorClockMutable::get(getServiceContext())->tickClusterTime(1);
auto t2(getClusterTime());
- ASSERT_TRUE(t1 == t2);
+ ASSERT_EQ(t1, t2);
// Make sure we synchronized with the wall clock.
- ASSERT_TRUE(t2.asTimestamp().getSecs() == 10);
+ ASSERT_EQ(t2.asTimestamp().getSecs(), 10);
auto t3 = VectorClockMutable::get(getServiceContext())->tickClusterTime(1);
t1.addTicks(1);
- ASSERT_TRUE(t3 == t1);
+ ASSERT_EQ(t3, t1);
t3 = VectorClockMutable::get(getServiceContext())->tickClusterTime(100);
t1.addTicks(1);
- ASSERT_TRUE(t3 == t1);
+ ASSERT_EQ(t3, t1);
t3 = VectorClockMutable::get(getServiceContext())->tickClusterTime(1);
t1.addTicks(100);
- ASSERT_TRUE(t3 == t1);
+ ASSERT_EQ(t3, t1);
// Ensure overflow to a new second.
auto initTimeSecs = getClusterTime().asTimestamp().getSecs();
VectorClockMutable::get(getServiceContext())->tickClusterTime((1U << 31) - 1);
auto newTimeSecs = getClusterTime().asTimestamp().getSecs();
- ASSERT_TRUE(newTimeSecs == initTimeSecs + 1);
+ ASSERT_EQ(newTimeSecs, initTimeSecs + 1);
}
// Verify the advanceClusterTime functionality.
@@ -104,7 +104,7 @@ TEST_F(VectorClockTest, advanceClusterTime) {
auto t1 = VectorClockMutable::get(getServiceContext())->tickClusterTime(1);
t1.addTicks(100);
advanceClusterTime(t1);
- ASSERT_TRUE(t1 == getClusterTime());
+ ASSERT_EQ(t1, getClusterTime());
}
// Verify rate limiter rejects cluster times whose seconds values are too far ahead.
@@ -124,8 +124,8 @@ TEST_F(VectorClockTest, RateLimiterRejectsLogicalTimesTooFarAhead) {
// Verify cluster time can be initialized to a very old time.
TEST_F(VectorClockTest, InitFromTrustedSourceCanAcceptVeryOldLogicalTime) {
- setMockClockSourceTime(Date_t::fromMillisSinceEpoch(
- durationCount<Seconds>(Seconds(kMaxAcceptableLogicalClockDriftSecsDefault)) * 10 * 1000));
+ setMockClockSourceTime(Date_t::fromDurationSinceEpoch(
+ Seconds(kMaxAcceptableLogicalClockDriftSecsDefault) * 10 * 1000));
Timestamp veryOldTimestamp(
durationCount<Seconds>(getMockClockSourceTime().toDurationSinceEpoch()) -
@@ -133,7 +133,7 @@ TEST_F(VectorClockTest, InitFromTrustedSourceCanAcceptVeryOldLogicalTime) {
auto veryOldTime = LogicalTime(veryOldTimestamp);
VectorClockMutable::get(getServiceContext())->tickClusterTimeTo(veryOldTime);
- ASSERT_TRUE(getClusterTime() == veryOldTime);
+ ASSERT_EQ(getClusterTime(), veryOldTime);
}
// Verify writes to the oplog advance cluster time.
@@ -142,10 +142,10 @@ TEST_F(VectorClockTest, WritesToOplogAdvanceClusterTime) {
auto initialTime = LogicalTime(tX);
VectorClockMutable::get(getServiceContext())->tickClusterTimeTo(initialTime);
- ASSERT_TRUE(getClusterTime() == initialTime);
+ ASSERT_EQ(getClusterTime(), initialTime);
getDBClient()->insert(kDummyNamespaceString.ns(), BSON("x" << 1));
- ASSERT_TRUE(getClusterTime() > initialTime);
+ ASSERT_GT(getClusterTime(), initialTime);
ASSERT_EQ(getClusterTime().asTimestamp(),
replicationCoordinator()->getMyLastAppliedOpTime().getTimestamp());
}
@@ -170,9 +170,9 @@ TEST_F(VectorClockTest, WallClockSetTooFarInPast) {
// If cluster time is either uninitialized or even farther in the past, a write would set
// cluster time more than maxAcceptableLogicalClockDriftSecs in the past.
getDBClient()->insert(kDummyNamespaceString.ns(), BSON("x" << 1));
- ASSERT_TRUE(getClusterTime() <
- LogicalTime(Timestamp(
- currentSecs - Seconds(kMaxAcceptableLogicalClockDriftSecsDefault), 0)));
+ ASSERT_LT(getClusterTime(),
+ LogicalTime(
+ Timestamp(currentSecs - Seconds(kMaxAcceptableLogicalClockDriftSecsDefault), 0)));
// Set wall clock to the current time on the affected node.
setMockClockSourceTime(Date_t::fromDurationSinceEpoch(currentSecs));
@@ -180,7 +180,7 @@ TEST_F(VectorClockTest, WallClockSetTooFarInPast) {
// Verify that maxAcceptableLogicalClockDriftSecs parameter does not need to be increased to
// advance cluster time through metadata back to the current time.
advanceClusterTime(currentTime);
- ASSERT_TRUE(getClusterTime() == currentTime);
+ ASSERT_EQ(getClusterTime(), currentTime);
}
// Tests the scenario where an admin incorrectly sets the wall clock more than
@@ -201,9 +201,9 @@ TEST_F(VectorClockTest, WallClockSetTooFarInFuture) {
// A write gets through and advances cluster time more than maxAcceptableLogicalClockDriftSecs
// in the future.
getDBClient()->insert(kDummyNamespaceString.ns(), BSON("x" << 1));
- ASSERT_TRUE(getClusterTime() >
- LogicalTime(Timestamp(
- currentSecs + Seconds(kMaxAcceptableLogicalClockDriftSecsDefault), 0)));
+ ASSERT_GT(getClusterTime(),
+ LogicalTime(
+ Timestamp(currentSecs + Seconds(kMaxAcceptableLogicalClockDriftSecsDefault), 0)));
// Set wall clock to the current time on the affected node.
setMockClockSourceTime(Date_t::fromDurationSinceEpoch(currentSecs));
@@ -222,11 +222,14 @@ TEST_F(VectorClockTest, WallClockSetTooFarInFuture) {
setMockClockSourceTime(Date_t::fromDurationSinceEpoch(currentSecs + oneDay));
advanceClusterTime(nextTime);
- ASSERT_TRUE(getClusterTime() == nextTime);
+ ASSERT_EQ(getClusterTime(), nextTime);
}
// Verify the behavior of advancing cluster time around the max allowed values.
TEST_F(VectorClockTest, ReserveTicksBehaviorAroundMaxTime) {
+ // Ensure the clock starts at 0.
+ setMockClockSourceTime(Date_t{});
+
// Verify clock can be advanced near the max values.
// Can always advance to the max value for the inc field.
@@ -320,7 +323,7 @@ TEST_F(VectorClockTest, RejectsLogicalTimesGreaterThanMaxTime) {
resetClock();
ASSERT_THROWS(VectorClockMutable::get(getServiceContext())->tickClusterTimeTo(beyondMaxTime),
DBException);
- ASSERT_TRUE(getClusterTime() == VectorClock::kInitialComponentTime);
+ ASSERT_EQ(getClusterTime(), VectorClock::kInitialComponentTime);
// The time can't be advanced through metadata to a time greater than the max possible.
// Advance the wall clock close enough to the new value so the rate check is passed.
@@ -328,7 +331,7 @@ TEST_F(VectorClockTest, RejectsLogicalTimesGreaterThanMaxTime) {
Seconds(maxVal) - Seconds(kMaxAcceptableLogicalClockDriftSecsDefault) + Seconds(10);
setMockClockSourceTime(Date_t::fromDurationSinceEpoch(almostMaxSecs));
ASSERT_THROWS(advanceClusterTime(beyondMaxTime), DBException);
- ASSERT_TRUE(getClusterTime() == VectorClock::kInitialComponentTime);
+ ASSERT_EQ(getClusterTime(), VectorClock::kInitialComponentTime);
}
} // unnamed namespace
diff --git a/src/mongo/db/vector_clock_test_fixture.cpp b/src/mongo/db/vector_clock_test_fixture.cpp
index c25324339db..13814076081 100644
--- a/src/mongo/db/vector_clock_test_fixture.cpp
+++ b/src/mongo/db/vector_clock_test_fixture.cpp
@@ -47,7 +47,8 @@
namespace mongo {
-VectorClockTestFixture::VectorClockTestFixture() = default;
+VectorClockTestFixture::VectorClockTestFixture()
+ : ShardingMongodTestFixture(Options{}.useMockClock(true), false /* setUpMajorityReads */) {}
VectorClockTestFixture::~VectorClockTestFixture() = default;
@@ -58,9 +59,6 @@ void VectorClockTestFixture::setUp() {
_clock = VectorClock::get(service);
- service->setFastClockSource(std::make_unique<SharedClockSourceAdapter>(_mockClockSource));
- service->setPreciseClockSource(std::make_unique<SharedClockSourceAdapter>(_mockClockSource));
-
_dbDirectClient = std::make_unique<DBDirectClient>(operationContext());
ASSERT_OK(replicationCoordinator()->setFollowerMode(repl::MemberState::RS_PRIMARY));
@@ -90,16 +88,16 @@ LogicalTime VectorClockTestFixture::getClusterTime() const {
return now.clusterTime();
}
-ClockSourceMock* VectorClockTestFixture::getMockClockSource() const {
- return _mockClockSource.get();
+ClockSourceMock* VectorClockTestFixture::getMockClockSource() {
+ return &_mockClockSource;
}
-void VectorClockTestFixture::setMockClockSourceTime(Date_t time) const {
- _mockClockSource->reset(time);
+void VectorClockTestFixture::setMockClockSourceTime(Date_t time) {
+ _mockClockSource.reset(time);
}
-Date_t VectorClockTestFixture::getMockClockSourceTime() const {
- return _mockClockSource->now();
+Date_t VectorClockTestFixture::getMockClockSourceTime() {
+ return _mockClockSource.now();
}
DBDirectClient* VectorClockTestFixture::getDBClient() const {
diff --git a/src/mongo/db/vector_clock_test_fixture.h b/src/mongo/db/vector_clock_test_fixture.h
index 3fc5b043744..4ae782cbb7a 100644
--- a/src/mongo/db/vector_clock_test_fixture.h
+++ b/src/mongo/db/vector_clock_test_fixture.h
@@ -45,11 +45,10 @@ class VectorClockMutable;
* ShardingMongodTestFixture.
*/
class VectorClockTestFixture : public ShardingMongodTestFixture {
-public:
+protected:
VectorClockTestFixture();
~VectorClockTestFixture();
-protected:
/**
* Sets up this fixture as the primary node in a shard server replica set with a VectorClock
* (with a TimeProofService), storage engine, DBClient, OpObserver, and a mocked clock source.
@@ -66,20 +65,19 @@ protected:
LogicalTime getClusterTime() const;
- ClockSourceMock* getMockClockSource() const;
+ ClockSourceMock* getMockClockSource();
- void setMockClockSourceTime(Date_t time) const;
+ void setMockClockSourceTime(Date_t time);
- Date_t getMockClockSourceTime() const;
+ Date_t getMockClockSourceTime();
DBDirectClient* getDBClient() const;
-protected:
void setupOpObservers() override;
private:
VectorClock* _clock;
- std::shared_ptr<ClockSourceMock> _mockClockSource = std::make_shared<ClockSourceMock>();
+ ClockSourceMock _mockClockSource;
std::unique_ptr<DBDirectClient> _dbDirectClient;
};