From 18c39bc1e395412f1aa69d98a1ac1e39bfa48d9b Mon Sep 17 00:00:00 2001 From: Hugh Tong Date: Fri, 9 Sep 2022 20:46:33 +0000 Subject: SERVER-62393 Apply CRUD ops using correct tenant namespace during oplog application --- src/mongo/db/dbhelpers.h | 1 + src/mongo/db/repl/oplog.cpp | 8 +- src/mongo/db/repl/oplog_applier_impl_test.cpp | 195 +++++++++++++++++++-- .../db/repl/oplog_applier_impl_test_fixture.cpp | 22 +-- .../db/repl/oplog_applier_impl_test_fixture.h | 1 + src/mongo/db/repl/oplog_applier_utils.cpp | 5 +- 6 files changed, 205 insertions(+), 27 deletions(-) diff --git a/src/mongo/db/dbhelpers.h b/src/mongo/db/dbhelpers.h index 047aa9f8534..c4741ffba17 100644 --- a/src/mongo/db/dbhelpers.h +++ b/src/mongo/db/dbhelpers.h @@ -87,6 +87,7 @@ struct Helpers { * * Returns true if a matching document was found. */ + // TODO SERVER-69541 pass in NamespaceString object instead static bool findById(OperationContext* opCtx, StringData ns, BSONObj query, diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index be4cc5863b4..03365f0db74 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -1599,8 +1599,12 @@ Status applyOperation_inlock(OperationContext* opCtx, // document. invariant(op.getObject2()); auto&& documentId = *op.getObject2(); - auto documentFound = Helpers::findById( - opCtx, collection->ns().ns(), documentId, changeStreamPreImage); + + // TODO SERVER-69541 pass in NamespaceString object instead + auto documentFound = Helpers::findById(opCtx, + collection->ns().toStringWithTenantId(), + documentId, + changeStreamPreImage); invariant(documentFound); } diff --git a/src/mongo/db/repl/oplog_applier_impl_test.cpp b/src/mongo/db/repl/oplog_applier_impl_test.cpp index a695eb26a2d..ff4441515d4 100644 --- a/src/mongo/db/repl/oplog_applier_impl_test.cpp +++ b/src/mongo/db/repl/oplog_applier_impl_test.cpp @@ -129,10 +129,12 @@ TEST_F(OplogApplierImplTest, applyOplogEntryOrGroupedInsertsInsertDocumentDataba TEST_F(OplogApplierImplTestDisableSteadyStateConstraints, applyOplogEntryOrGroupedInsertsDeleteDocumentDatabaseMissing) { + + const NamespaceString nss(boost::none, "test.t"); NamespaceString otherNss("test.othername"); auto op = makeOplogEntry(OpTypeEnum::kDelete, otherNss, {}); int prevDeleteFromMissing = replOpCounters.getDeleteFromMissingNamespace()->load(); - _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, false); + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, nss, false); auto postDeleteFromMissing = replOpCounters.getDeleteFromMissingNamespace()->load(); ASSERT_EQ(1, postDeleteFromMissing - prevDeleteFromMissing); @@ -170,7 +172,7 @@ TEST_F(OplogApplierImplTestDisableSteadyStateConstraints, NamespaceString otherNss(nss.getSisterNS("othername")); auto op = makeOplogEntry(OpTypeEnum::kDelete, otherNss, kUuid); int prevDeleteFromMissing = replOpCounters.getDeleteFromMissingNamespace()->load(); - _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, false); + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, nss, false); auto postDeleteFromMissing = replOpCounters.getDeleteFromMissingNamespace()->load(); ASSERT_EQ(1, postDeleteFromMissing - prevDeleteFromMissing); @@ -214,7 +216,7 @@ TEST_F(OplogApplierImplTestDisableSteadyStateConstraints, // implicitly create the collection. auto op = makeOplogEntry(OpTypeEnum::kDelete, nss, {}); int prevDeleteFromMissing = replOpCounters.getDeleteFromMissingNamespace()->load(); - _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, false); + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, nss, false); ASSERT_FALSE(collectionExists(_opCtx.get(), nss)); auto postDeleteFromMissing = replOpCounters.getDeleteFromMissingNamespace()->load(); ASSERT_EQ(1, postDeleteFromMissing - prevDeleteFromMissing); @@ -242,7 +244,7 @@ TEST_F(OplogApplierImplTest, applyOplogEntryOrGroupedInsertsInsertDocumentCollec const NamespaceString nss("test.t"); repl::createCollection(_opCtx.get(), nss, {}); auto op = makeOplogEntry(OpTypeEnum::kInsert, nss, {}); - _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, true); + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, nss, true); } TEST_F(OplogApplierImplTestDisableSteadyStateConstraints, @@ -251,7 +253,7 @@ TEST_F(OplogApplierImplTestDisableSteadyStateConstraints, repl::createCollection(_opCtx.get(), nss, {}); auto op = makeOplogEntry(OpTypeEnum::kDelete, nss, {}); int prevDeleteWasEmpty = replOpCounters.getDeleteWasEmpty()->load(); - _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, false); + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, nss, false); auto postDeleteWasEmpty = replOpCounters.getDeleteWasEmpty()->load(); ASSERT_EQ(1, postDeleteWasEmpty - prevDeleteWasEmpty); @@ -277,7 +279,7 @@ TEST_F(OplogApplierImplTest, applyOplogEntryOrGroupedInsertsDeleteDocumentCollec createCollection(_opCtx.get(), nss, createRecordPreImageCollectionOptions()); ASSERT_OK(getStorageInterface()->insertDocument(_opCtx.get(), nss, {BSON("_id" << 0)}, 0)); auto op = makeOplogEntry(OpTypeEnum::kDelete, nss, {}); - _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, true); + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, nss, true); } TEST_F(OplogApplierImplTestDisableSteadyStateConstraints, @@ -287,7 +289,7 @@ TEST_F(OplogApplierImplTestDisableSteadyStateConstraints, ASSERT_OK(getStorageInterface()->insertDocument(_opCtx.get(), nss, {BSON("_id" << 0)}, 0)); auto op = makeOplogEntry(OpTypeEnum::kInsert, nss, uuid); int prevInsertOnExistingDoc = replOpCounters.getInsertOnExistingDoc()->load(); - _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, false); + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, nss, false); auto postInsertOnExistingDoc = replOpCounters.getInsertOnExistingDoc()->load(); ASSERT_EQ(1, postInsertOnExistingDoc - prevInsertOnExistingDoc); @@ -304,7 +306,7 @@ TEST_F(OplogApplierImplTestEnableSteadyStateConstraints, auto uuid = createCollectionWithUuid(_opCtx.get(), nss); ASSERT_OK(getStorageInterface()->insertDocument(_opCtx.get(), nss, {BSON("_id" << 0)}, 0)); auto op = makeOplogEntry(OpTypeEnum::kInsert, nss, uuid); - _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::DuplicateKey, op, false); + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::DuplicateKey, op, nss, false); } TEST_F(OplogApplierImplTestDisableSteadyStateConstraints, @@ -318,7 +320,7 @@ TEST_F(OplogApplierImplTestDisableSteadyStateConstraints, BSON(doc_diff::kUpdateSectionFieldName << fromjson("{a: 1}"))), BSON("_id" << 0)); int prevUpdateOnMissingDoc = replOpCounters.getUpdateOnMissingDoc()->load(); - _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, true); + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, nss, true); auto postUpdateOnMissingDoc = replOpCounters.getUpdateOnMissingDoc()->load(); ASSERT_EQ(1, postUpdateOnMissingDoc - prevUpdateOnMissingDoc); @@ -339,7 +341,8 @@ TEST_F(OplogApplierImplTestEnableSteadyStateConstraints, update_oplog_entry::makeDeltaOplogEntry( BSON(doc_diff::kUpdateSectionFieldName << fromjson("{a: 1}"))), BSON("_id" << 0)); - _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::UpdateOperationFailed, op, false); + _testApplyOplogEntryOrGroupedInsertsCrudOperation( + ErrorCodes::UpdateOperationFailed, op, nss, false); } TEST_F(OplogApplierImplTest, applyOplogEntryOrGroupedInsertsInsertDocumentCollectionLockedByUUID) { @@ -348,7 +351,7 @@ TEST_F(OplogApplierImplTest, applyOplogEntryOrGroupedInsertsInsertDocumentCollec // Test that the collection to lock is determined by the UUID and not the 'ns' field. NamespaceString otherNss(nss.getSisterNS("othername")); auto op = makeOplogEntry(OpTypeEnum::kInsert, otherNss, uuid); - _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, true); + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, nss, true); } TEST_F(OplogApplierImplTestDisableSteadyStateConstraints, @@ -362,7 +365,7 @@ TEST_F(OplogApplierImplTestDisableSteadyStateConstraints, NamespaceString otherNss(nss.getSisterNS("othername")); auto op = makeOplogEntry(OpTypeEnum::kDelete, otherNss, options.uuid); int prevDeleteWasEmpty = replOpCounters.getDeleteWasEmpty()->load(); - _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, false); + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, nss, false); auto postDeleteWasEmpty = replOpCounters.getDeleteWasEmpty()->load(); ASSERT_EQ(1, postDeleteWasEmpty - prevDeleteWasEmpty); @@ -399,7 +402,7 @@ TEST_F(OplogApplierImplTest, applyOplogEntryOrGroupedInsertsDeleteDocumentCollec // Test that the collection to lock is determined by the UUID and not the 'ns' field. NamespaceString otherNss(nss.getSisterNS("othername")); auto op = makeOplogEntry(OpTypeEnum::kDelete, otherNss, options.uuid); - _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, true); + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, nss, true); } TEST_F(OplogApplierImplTest, applyOplogEntryToRecordChangeStreamPreImages) { @@ -700,6 +703,172 @@ TEST_F(OplogApplierImplTest, secondDerivedOp.getObject()["lastWriteOpTime"]["ts"].timestamp()); } +TEST_F(OplogApplierImplTest, applyOplogEntryOrGroupedInsertsInsertDocumentIncludesTenantId) { + RAIIServerParameterControllerForTest multitenancyController("multitenancySupport", true); + RAIIServerParameterControllerForTest featureFlagController("featureFlagRequireTenantID", true); + const TenantId tid(OID::gen()); + const NamespaceString nss(tid, "test.t"); + BSONObj doc = BSON("_id" << 0); + + repl::createCollection(_opCtx.get(), nss, {}); + + auto op = makeOplogEntry(OpTypeEnum::kInsert, nss, boost::none, doc, boost::none); + + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, nss, true); + + // TODO SERVER-67423: use docExists to check that the doc actually got inserted +} + +TEST_F(OplogApplierImplTest, applyOplogEntryOrGroupedInsertsInsertDocumentIncorrectTenantId) { + RAIIServerParameterControllerForTest multitenancyController("multitenancySupport", true); + RAIIServerParameterControllerForTest featureFlagController("featureFlagRequireTenantID", true); + const auto commonNss("test.t"_sd); + const TenantId tid1(OID::gen()); + const TenantId tid2(OID::gen()); + const NamespaceString nssTenant1(tid1, commonNss); + const NamespaceString nssTenant2(tid2, commonNss); + BSONObj doc = BSON("_id" << 0); + + repl::createCollection(_opCtx.get(), nssTenant1, {}); + + auto op = makeOplogEntry(OpTypeEnum::kInsert, nssTenant2, boost::none, doc, boost::none); + + ASSERT_THROWS( + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, nssTenant2, false), + ExceptionFor); + + // TODO SERVER-67423: use docExists to check that the doc still exists on nssTenant1, and does + // not exist on nssTenant2 +} + +TEST_F(OplogApplierImplTest, applyOplogEntryOrGroupedInsertsDeleteDocumentIncludesTenantId) { + RAIIServerParameterControllerForTest multitenancyController("multitenancySupport", true); + RAIIServerParameterControllerForTest featureFlagController("featureFlagRequireTenantID", true); + const TenantId tid(OID::gen()); + const NamespaceString nss(tid, "test.t"); + BSONObj doc = BSON("_id" << 0); + + // this allows us to set deleteArgs.deletedDoc needed by the onDeleteFn validation function in + // _testApplyOplogEntryOrGroupedInsertsCrudOperation below + CollectionOptions options = createRecordPreImageCollectionOptions(); + + repl::createCollection(_opCtx.get(), nss, options); + ASSERT_OK(getStorageInterface()->insertDocument(_opCtx.get(), nss, {doc}, 0)); + + auto op = makeOplogEntry(OpTypeEnum::kDelete, nss, boost::none); + + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, nss, true); + + // TODO SERVER-67423: use docExists to check that the doc actually got deleted +} + +TEST_F(OplogApplierImplTestEnableSteadyStateConstraints, // see TODO SERVER-67423 below + applyOplogEntryOrGroupedInsertsDeleteDocumentIncorrectTenantId) { + RAIIServerParameterControllerForTest multitenancyController("multitenancySupport", true); + RAIIServerParameterControllerForTest featureFlagController("featureFlagRequireTenantID", true); + const auto commonNss("test.t"_sd); + const TenantId tid1(OID::gen()); + const TenantId tid2(OID::gen()); + const NamespaceString nssTenant1(tid1, commonNss); + const NamespaceString nssTenant2(tid2, commonNss); + BSONObj doc = BSON("_id" << 0); + + repl::createCollection(_opCtx.get(), nssTenant1, {}); + ASSERT_OK(getStorageInterface()->insertDocument(_opCtx.get(), nssTenant1, {doc}, 0)); + + auto op = makeOplogEntry(OpTypeEnum::kDelete, nssTenant2, boost::none); + + ASSERT_THROWS( + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, nssTenant2, false), + ExceptionFor); + + // TODO SERVER-67423: use docExists to check that the doc still exists on nssTenant1, and does + // not exist on nssTenant2. Also, we are using OplogApplierImplTestEnableSteadyStateConstraints + // because according to OplogApplierUtils::applyOplogEntryOrGroupedInsertsCommon not enabling + // steady state constraints allows the delete to fail silently. While updating SERVER-67423, we + // can instead use docExists to check the results of the deletion rather than rely on the + // exception +} + +// Steady state constraints are required for secondaries in order to avoid turning an insert into an +// upsert and masking duplicateKey errors. +TEST_F(OplogApplierImplTestEnableSteadyStateConstraints, + applyOplogEntryOrGroupedInsertsUuidIncludesTenantId) { + RAIIServerParameterControllerForTest multitenancyController("multitenancySupport", true); + RAIIServerParameterControllerForTest featureFlagController("featureFlagRequireTenantID", true); + const auto commonNss("test.t"_sd); + const TenantId tid1(OID::gen()); + const TenantId tid2(OID::gen()); + const NamespaceString nssTenant1(tid1, commonNss); + const NamespaceString nssTenant2(tid2, commonNss); + BSONObj doc = BSON("_id" << 0); + + auto uuid1 = createCollectionWithUuid(_opCtx.get(), nssTenant1); + auto uuid2 = createCollectionWithUuid(_opCtx.get(), nssTenant2); + + // Only insert on tenant1, such that we will cause a duplicate key error on one tenant but not + // the other. + ASSERT_OK(getStorageInterface()->insertDocument(_opCtx.get(), nssTenant1, {doc}, 0)); + + auto duplicateInsertOp = makeOplogEntry(OpTypeEnum::kInsert, nssTenant1, uuid1); + auto successfulInsertOp = makeOplogEntry(OpTypeEnum::kInsert, nssTenant2, uuid2); + + _testApplyOplogEntryOrGroupedInsertsCrudOperation( + ErrorCodes::DuplicateKey, duplicateInsertOp, nssTenant1, false); + _testApplyOplogEntryOrGroupedInsertsCrudOperation( + ErrorCodes::OK, successfulInsertOp, nssTenant2, true); +} + +TEST_F(OplogApplierImplTest, applyOplogEntryOrGroupedInsertsUpdateDocumentIncludesTenantId) { + RAIIServerParameterControllerForTest multitenancyController("multitenancySupport", true); + RAIIServerParameterControllerForTest featureFlagController("featureFlagRequireTenantID", true); + const TenantId tid(OID::gen()); + const NamespaceString nss(tid, "test.t"); + BSONObj doc = BSON("_id" << 0); + + createCollection(_opCtx.get(), nss, {}); + ASSERT_OK(getStorageInterface()->insertDocument(_opCtx.get(), nss, {doc}, 0)); + + auto op = makeOplogEntry(repl::OpTypeEnum::kUpdate, + nss, + boost::none, + update_oplog_entry::makeDeltaOplogEntry( + BSON(doc_diff::kUpdateSectionFieldName << fromjson("{a: 1}"))), + BSON("_id" << 0)); + + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, nss, true); + + // TODO SERVER-67423: use docExists to check that the doc exists in its new updated form +} + +TEST_F(OplogApplierImplTest, applyOplogEntryOrGroupedInsertsUpdateDocumentIncorrectTenantId) { + RAIIServerParameterControllerForTest multitenancyController("multitenancySupport", true); + RAIIServerParameterControllerForTest featureFlagController("featureFlagRequireTenantID", true); + const auto commonNss("test.t"_sd); + const TenantId tid1(OID::gen()); + const TenantId tid2(OID::gen()); + const NamespaceString nssTenant1(tid1, commonNss); + const NamespaceString nssTenant2(tid2, commonNss); + BSONObj doc = BSON("_id" << 0); + + createCollection(_opCtx.get(), nssTenant1, {}); + ASSERT_OK(getStorageInterface()->insertDocument(_opCtx.get(), nssTenant1, {doc}, 0)); + + auto op = makeOplogEntry(repl::OpTypeEnum::kUpdate, + nssTenant2, + boost::none, + update_oplog_entry::makeDeltaOplogEntry( + BSON(doc_diff::kUpdateSectionFieldName << fromjson("{a: 1}"))), + BSON("_id" << 0)); + + ASSERT_THROWS( + _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::OK, op, nssTenant2, true), + ExceptionFor); + + // TODO SERVER-67423: use docExists to check that the original doc still exists on nssTenant1, + // and no doc exists on nssTenant2 +} + class MultiOplogEntryOplogApplierImplTest : public OplogApplierImplTest { public: MultiOplogEntryOplogApplierImplTest() diff --git a/src/mongo/db/repl/oplog_applier_impl_test_fixture.cpp b/src/mongo/db/repl/oplog_applier_impl_test_fixture.cpp index 1070ac64784..007d9da4e0e 100644 --- a/src/mongo/db/repl/oplog_applier_impl_test_fixture.cpp +++ b/src/mongo/db/repl/oplog_applier_impl_test_fixture.cpp @@ -218,17 +218,17 @@ Status OplogApplierImplTest::_applyOplogEntryOrGroupedInsertsWrapper( } void OplogApplierImplTest::_testApplyOplogEntryOrGroupedInsertsCrudOperation( - ErrorCodes::Error expectedError, const OplogEntry& op, bool expectedApplyOpCalled) { + ErrorCodes::Error expectedError, + const OplogEntry& op, + const NamespaceString& targetNss, + bool expectedApplyOpCalled) { bool applyOpCalled = false; - auto checkOpCtx = [](OperationContext* opCtx) { + auto checkOpCtx = [&targetNss](OperationContext* opCtx) { ASSERT_TRUE(opCtx); - ASSERT_TRUE( - opCtx->lockState()->isDbLockedForMode(DatabaseName(boost::none, "test"), MODE_IX)); - ASSERT_FALSE( - opCtx->lockState()->isDbLockedForMode(DatabaseName(boost::none, "test"), MODE_X)); - ASSERT_TRUE( - opCtx->lockState()->isCollectionLockedForMode(NamespaceString("test.t"), MODE_IX)); + ASSERT_TRUE(opCtx->lockState()->isDbLockedForMode(targetNss.dbName(), MODE_IX)); + ASSERT_FALSE(opCtx->lockState()->isDbLockedForMode(targetNss.dbName(), MODE_X)); + ASSERT_TRUE(opCtx->lockState()->isCollectionLockedForMode(targetNss, MODE_IX)); ASSERT_FALSE(opCtx->writesAreReplicated()); ASSERT_TRUE(DocumentValidationSettings::get(opCtx).isSchemaValidationDisabled()); }; @@ -237,7 +237,7 @@ void OplogApplierImplTest::_testApplyOplogEntryOrGroupedInsertsCrudOperation( [&](OperationContext* opCtx, const NamespaceString& nss, const std::vector& docs) { applyOpCalled = true; checkOpCtx(opCtx); - ASSERT_EQUALS(NamespaceString("test.t"), nss); + ASSERT_EQUALS(targetNss, nss); ASSERT_EQUALS(1U, docs.size()); // For upserts we don't know the intended value of the document. if (op.getOpType() == repl::OpTypeEnum::kInsert) { @@ -253,7 +253,7 @@ void OplogApplierImplTest::_testApplyOplogEntryOrGroupedInsertsCrudOperation( const OplogDeleteEntryArgs& args) { applyOpCalled = true; checkOpCtx(opCtx); - ASSERT_EQUALS(NamespaceString("test.t"), nss); + ASSERT_EQUALS(targetNss, nss); ASSERT(args.deletedDoc); ASSERT_BSONOBJ_EQ(op.getObject(), *(args.deletedDoc)); return Status::OK(); @@ -262,7 +262,7 @@ void OplogApplierImplTest::_testApplyOplogEntryOrGroupedInsertsCrudOperation( _opObserver->onUpdateFn = [&](OperationContext* opCtx, const OplogUpdateEntryArgs& args) { applyOpCalled = true; checkOpCtx(opCtx); - ASSERT_EQUALS(NamespaceString("test.t"), args.nss); + ASSERT_EQUALS(targetNss, args.nss); return Status::OK(); }; 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 7b800e5127a..e2c374e24b4 100644 --- a/src/mongo/db/repl/oplog_applier_impl_test_fixture.h +++ b/src/mongo/db/repl/oplog_applier_impl_test_fixture.h @@ -200,6 +200,7 @@ protected: void _testApplyOplogEntryOrGroupedInsertsCrudOperation(ErrorCodes::Error expectedError, const OplogEntry& op, + const NamespaceString& targetNss, bool expectedApplyOpCalled); Status _applyOplogEntryOrGroupedInsertsWrapper(OperationContext* opCtx, diff --git a/src/mongo/db/repl/oplog_applier_utils.cpp b/src/mongo/db/repl/oplog_applier_utils.cpp index 84cfd1b569d..451f3906257 100644 --- a/src/mongo/db/repl/oplog_applier_utils.cpp +++ b/src/mongo/db/repl/oplog_applier_utils.cpp @@ -187,7 +187,7 @@ NamespaceString OplogApplierUtils::parseUUIDOrNs(OperationContext* opCtx, NamespaceStringOrUUID OplogApplierUtils::getNsOrUUID(const NamespaceString& nss, const OplogEntry& op) { if (auto ui = op.getUuid()) { - return {nss.db().toString(), ui.value()}; + return {nss.dbName(), ui.value()}; } return nss; } @@ -206,6 +206,9 @@ Status OplogApplierUtils::applyOplogEntryOrGroupedInsertsCommon( CurOp individualOp(opCtx); const NamespaceString nss(op.getNss()); auto opType = op.getOpType(); + + invariant(op.getTid() == nss.tenantId()); + if (opType == OpTypeEnum::kNoop) { incrementOpsAppliedStats(); return Status::OK(); -- cgit v1.2.1