diff options
author | auto-revert-processor <dev-prod-dag@mongodb.com> | 2022-10-22 03:34:21 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-10-22 04:06:30 +0000 |
commit | e5fa2aabe4ddfe1d18d94e326d1ef3dc4ca2af26 (patch) | |
tree | 76b6db279d573582be14a2812ac8b184a97a0f74 /src/mongo/db | |
parent | 0fb4acf0e581936924c2353a6cfdb29ce5f06348 (diff) | |
download | mongo-e5fa2aabe4ddfe1d18d94e326d1ef3dc4ca2af26.tar.gz |
Revert "SERVER-62880 Use tid field to apply applyOps and transactions oplog entries"
This reverts commit 9a60ad4e90d5e2faccedcea26e31b1992676d395.
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/commands/oplog_application_checks.cpp | 22 | ||||
-rw-r--r-- | src/mongo/db/repl/oplog_applier_impl_test.cpp | 216 | ||||
-rw-r--r-- | src/mongo/db/repl/oplog_entry.cpp | 11 | ||||
-rw-r--r-- | src/mongo/db/repl/transaction_oplog_application.cpp | 4 |
4 files changed, 13 insertions, 240 deletions
diff --git a/src/mongo/db/commands/oplog_application_checks.cpp b/src/mongo/db/commands/oplog_application_checks.cpp index 816a8157403..c4f65bb478b 100644 --- a/src/mongo/db/commands/oplog_application_checks.cpp +++ b/src/mongo/db/commands/oplog_application_checks.cpp @@ -62,19 +62,15 @@ Status OplogApplicationChecks::checkOperationAuthorization(OperationContext* opC BSONElement nsElem = oplogEntry["ns"]; checkBSONType(BSONType::String, nsElem); - boost::optional<TenantId> tid = oplogEntry.hasElement("tid") - ? boost::make_optional<TenantId>(TenantId::parseFromBSON(oplogEntry["tid"])) - : boost::none; - NamespaceString nss = - NamespaceStringUtil::deserialize(tid, oplogEntry["ns"].checkAndGetStringData()); + NamespaceString ns(oplogEntry["ns"].checkAndGetStringData()); if (oplogEntry.hasField("ui"_sd)) { // ns by UUID overrides the ns specified if they are different. auto catalog = CollectionCatalog::get(opCtx); boost::optional<NamespaceString> uuidCollNS = catalog->lookupNSSByUUID(opCtx, getUUIDFromOplogEntry(oplogEntry)); - if (uuidCollNS && *uuidCollNS != nss) - nss = *uuidCollNS; + if (uuidCollNS && *uuidCollNS != ns) + ns = *uuidCollNS; } BSONElement oElem = oplogEntry["o"]; @@ -88,19 +84,19 @@ Status OplogApplicationChecks::checkOperationAuthorization(OperationContext* opC return Status(ErrorCodes::FailedToParse, "Unrecognized command in op"); } - auto dbNameForAuthCheck = nss.dbName(); + std::string dbNameForAuthCheck = ns.db().toString(); if (commandName == "renameCollection") { // renameCollection commands must be run on the 'admin' database. Its arguments are // fully qualified namespaces. Catalog internals don't know the op produced by running // renameCollection was originally run on 'admin', so we must restore this. - dbNameForAuthCheck = DatabaseName(nss.tenantId(), "admin"); + dbNameForAuthCheck = "admin"; } // TODO reuse the parse result for when we run() later. Note that when running, // we must use a potentially different dbname. return [&] { try { - auto request = OpMsgRequestBuilder::create(nss.dbName(), o); + auto request = OpMsgRequest::fromDBAndBody(dbNameForAuthCheck, o); commandInOplogEntry->parse(opCtx, request)->checkAuthorization(opCtx, request); return Status::OK(); } catch (const DBException& e) { @@ -110,7 +106,7 @@ Status OplogApplicationChecks::checkOperationAuthorization(OperationContext* opC } if (opType == "i"_sd) { - return auth::checkAuthForInsert(authSession, opCtx, nss); + return auth::checkAuthForInsert(authSession, opCtx, ns); } else if (opType == "u"_sd) { BSONElement o2Elem = oplogEntry["o2"]; checkBSONType(BSONType::Object, o2Elem); @@ -126,14 +122,14 @@ Status OplogApplicationChecks::checkOperationAuthorization(OperationContext* opC return auth::checkAuthForUpdate(authSession, opCtx, - nss, + ns, o2, write_ops::UpdateModification::parseFromOplogEntry( o, write_ops::UpdateModification::DiffOptions{}), upsert); } else if (opType == "d"_sd) { - return auth::checkAuthForDelete(authSession, opCtx, nss, o); + return auth::checkAuthForDelete(authSession, opCtx, ns, o); } else if (opType == "db"_sd) { // It seems that 'db' isn't used anymore. Require all actions to prevent casual use. ActionSet allActions; diff --git a/src/mongo/db/repl/oplog_applier_impl_test.cpp b/src/mongo/db/repl/oplog_applier_impl_test.cpp index 3ded20a0e83..07dbe78a257 100644 --- a/src/mongo/db/repl/oplog_applier_impl_test.cpp +++ b/src/mongo/db/repl/oplog_applier_impl_test.cpp @@ -1559,222 +1559,6 @@ TEST_F(MultiOplogEntryOplogApplierImplTest, MultiApplyTwoTransactionsOneBatch) { ASSERT_BSONOBJ_EQ(BSON("_id" << 4), *(nss1It++)); } -class MultiOplogEntryOplogApplierImplTestMultitenant : public OplogApplierImplTest { -public: - MultiOplogEntryOplogApplierImplTestMultitenant() - : _tenantId(OID::gen()), - _nss(_tenantId, "test.preptxn"), - _cmdNss(_tenantId, "admin", "$cmd"), - _txnNum(1) {} - -protected: - void setUp() override { - OplogApplierImplTest::setUp(); - - createCollectionWithUuid(_opCtx.get(), NamespaceString::kSessionTransactionsTableNamespace); - - _uuid = UUID::gen(); - _lsid = makeLogicalSessionId(_opCtx.get()); - - _opObserver->onCreateCollectionFn = [&](OperationContext* opCtx, - const CollectionPtr&, - const NamespaceString& collNss, - const CollectionOptions&, - const BSONObj&) { - stdx::lock_guard<Latch> lock(_mutex); - if (collNss.isOplog()) { - _oplogDocs.insert(_oplogDocs.end(), BSON("create" << collNss.coll())); - } else if (collNss == _nss || - collNss == NamespaceString::kSessionTransactionsTableNamespace) { - // Storing the documents in a sorted data structure to make checking for valid - // results easier. The inserts will be performed by different threads and - // there's no guarantee of the order. - (_docs[collNss]).push_back(BSON("create" << collNss.coll())); - } else - FAIL("Unexpected create") << " on " << collNss; - }; - - _opObserver->onInsertsFn = [&](OperationContext*, - const NamespaceString& nss, - const std::vector<BSONObj>& docs) { - stdx::lock_guard<Latch> lock(_mutex); - if (nss.isOplog()) { - _oplogDocs.insert(_oplogDocs.end(), docs.begin(), docs.end()); - } else if (nss == _nss || nss == NamespaceString::kSessionTransactionsTableNamespace) { - // Storing the inserted documents in a sorted data structure to make checking - // for valid results easier. The inserts will be performed by different threads - // and there's no guarantee of the order. - (_docs[nss]).insert(_docs[nss].end(), docs.begin(), docs.end()); - } else - FAIL("Unexpected insert") << " into " << nss << " first doc: " << docs.front(); - }; - - _writerPool = makeReplWriterPool(); - } - - void tearDown() override { - OplogApplierImplTest::tearDown(); - } - - std::vector<BSONObj>& oplogDocs() { - return _oplogDocs; - } - -protected: - TenantId _tenantId; - NamespaceString _nss; - NamespaceString _cmdNss; - boost::optional<UUID> _uuid; - LogicalSessionId _lsid; - TxnNumber _txnNum; - boost::optional<OplogEntry> _commitOp; - std::map<NamespaceString, std::vector<BSONObj>> _docs; - std::vector<BSONObj> _oplogDocs; - std::unique_ptr<ThreadPool> _writerPool; - -private: - Mutex _mutex = MONGO_MAKE_LATCH("MultiOplogEntryOplogApplierImplTest::_mutex"); -}; - -TEST_F(MultiOplogEntryOplogApplierImplTestMultitenant, - MultiApplyUnpreparedTransactionTwoBatchesFeatureFlagOn) { - RAIIServerParameterControllerForTest multitenanyController("multitenancySupport", true); - RAIIServerParameterControllerForTest featureFlagController("featureFlagRequireTenantID", true); - // Tests an unprepared transaction with ops both in the batch with the commit and prior - // batches. Populate transaction with 2 linked entries - a create collection and an insert. - std::vector<OplogEntry> ops; - ops.push_back(makeCommandOplogEntryWithSessionInfoAndStmtIds( - {Timestamp(Seconds(1), 1), 1LL}, - _cmdNss, - BSON("applyOps" << BSON_ARRAY(BSON("op" - << "c" - << "tid" << _tenantId << "ns" << _nss.ns() << "ui" - << *_uuid << "o" << BSON("create" << _nss.coll()))) - << "partialTxn" << true), - _lsid, - _txnNum, - {StmtId(0)}, - OpTime())); - - ops.push_back(makeCommandOplogEntryWithSessionInfoAndStmtIds( - {Timestamp(Seconds(1), 2), 1LL}, - _cmdNss, - BSON("applyOps" << BSON_ARRAY(BSON("op" - << "i" - << "tid" << _tenantId << "ns" << _nss.ns() << "ui" - << *_uuid << "o" << BSON("_id" << 1))) - << "partialTxn" << true), - _lsid, - _txnNum, - {StmtId(1)}, - ops.back().getOpTime())); - - auto commitOp = makeCommandOplogEntryWithSessionInfoAndStmtIds({Timestamp(Seconds(1), 3), 1LL}, - _cmdNss, - BSON("applyOps" << BSONArray()), - _lsid, - _txnNum, - {StmtId(2)}, - ops.back().getOpTime()); - - NoopOplogApplierObserver observer; - OplogApplierImpl oplogApplier( - nullptr, // executor - nullptr, // oplogBuffer - &observer, - ReplicationCoordinator::get(_opCtx.get()), - getConsistencyMarkers(), - getStorageInterface(), - repl::OplogApplier::Options(repl::OplogApplication::Mode::kSecondary), - _writerPool.get()); - - // Insert the first entry in its own batch. This should result in the oplog entry being written - // but the entry should not be applied as it is part of a pending transaction. - ASSERT_OK(oplogApplier.applyOplogBatch(_opCtx.get(), {ops[0]})); - ASSERT_EQ(1U, oplogDocs().size()); - ASSERT_EQ(0U, _docs[_nss].size()); - - // Insert the rest of the entries, including the commit. These entries should be added to the - // oplog, and all the entries including the first should be applied. - ASSERT_OK(oplogApplier.applyOplogBatch(_opCtx.get(), {ops[1], commitOp})); - ASSERT_EQ(3U, oplogDocs().size()); - ASSERT_EQ(2U, _docs[_nss].size()); - - // Check that we applied the expected documents - auto nssIt = _docs[_nss].begin(); - ASSERT_BSONOBJ_EQ(BSON("create" << _nss.coll()), *nssIt); - ASSERT_BSONOBJ_EQ(BSON("_id" << 1), *(++nssIt)); -} - -TEST_F(MultiOplogEntryOplogApplierImplTestMultitenant, - MultiApplyUnpreparedTransactionTwoBatchesFeatureFlagOff) { - RAIIServerParameterControllerForTest multitenanyController("multitenancySupport", true); - RAIIServerParameterControllerForTest featureFlagController("featureFlagRequireTenantID", false); - // Tests an unprepared transaction with ops both in the batch with the commit and prior - // batches. Populate transaction with 2 linked entries - a create collection and an insert. - std::vector<OplogEntry> ops; - ops.push_back(makeCommandOplogEntryWithSessionInfoAndStmtIds( - {Timestamp(Seconds(1), 1), 1LL}, - _cmdNss, - BSON("applyOps" << BSON_ARRAY(BSON("op" - << "c" - << "ns" << _nss.toStringWithTenantId() << "ui" << *_uuid - << "o" << BSON("create" << _nss.coll()))) - << "partialTxn" << true), - _lsid, - _txnNum, - {StmtId(0)}, - OpTime())); - - ops.push_back(makeCommandOplogEntryWithSessionInfoAndStmtIds( - {Timestamp(Seconds(1), 2), 1LL}, - _cmdNss, - BSON("applyOps" << BSON_ARRAY(BSON("op" - << "i" - << "ns" << _nss.toStringWithTenantId() << "ui" << *_uuid - << "o" << BSON("_id" << 1))) - << "partialTxn" << true), - _lsid, - _txnNum, - {StmtId(1)}, - ops.back().getOpTime())); - - auto commitOp = makeCommandOplogEntryWithSessionInfoAndStmtIds({Timestamp(Seconds(1), 3), 1LL}, - _cmdNss, - BSON("applyOps" << BSONArray()), - _lsid, - _txnNum, - {StmtId(2)}, - ops.back().getOpTime()); - - NoopOplogApplierObserver observer; - OplogApplierImpl oplogApplier( - nullptr, // executor - nullptr, // oplogBuffer - &observer, - ReplicationCoordinator::get(_opCtx.get()), - getConsistencyMarkers(), - getStorageInterface(), - repl::OplogApplier::Options(repl::OplogApplication::Mode::kSecondary), - _writerPool.get()); - - // Insert the first entry in its own batch. This should result in the oplog entry being written - // but the entry should not be applied as it is part of a pending transaction. - ASSERT_OK(oplogApplier.applyOplogBatch(_opCtx.get(), {ops[0]})); - ASSERT_EQ(1U, oplogDocs().size()); - ASSERT_EQ(0U, _docs[_nss].size()); - - // Insert the rest of the entries, including the commit. These entries should be added to the - // oplog, and all the entries including the first should be applied. - ASSERT_OK(oplogApplier.applyOplogBatch(_opCtx.get(), {ops[1], commitOp})); - ASSERT_EQ(3U, oplogDocs().size()); - ASSERT_EQ(2U, _docs[_nss].size()); - - // Check that we applied the expected documents - auto nssIt = _docs[_nss].begin(); - ASSERT_BSONOBJ_EQ(BSON("create" << _nss.coll()), *nssIt); - ASSERT_BSONOBJ_EQ(BSON("_id" << 1), *(++nssIt)); -} class MultiOplogEntryPreparedTransactionTest : public MultiOplogEntryOplogApplierImplTest { protected: diff --git a/src/mongo/db/repl/oplog_entry.cpp b/src/mongo/db/repl/oplog_entry.cpp index 4f394c573a5..1bbcc9027be 100644 --- a/src/mongo/db/repl/oplog_entry.cpp +++ b/src/mongo/db/repl/oplog_entry.cpp @@ -508,15 +508,8 @@ bool DurableOplogEntry::isSingleOplogEntryTransactionWithCommand() const { // entries with commands at the beginning. for (BSONElement e : applyOps.Array()) { auto ns = e.Obj().getField("ns"); - if (!ns.eoo()) { - auto tid = e.Obj().getField("tid"); - auto tenantId = tid.eoo() - ? boost::none - : boost::make_optional<TenantId>(TenantId::parseFromBSON(tid)); - - if (NamespaceStringUtil::deserialize(tenantId, ns.String()).isCommand()) { - return true; - } + if (!ns.eoo() && NamespaceString(ns.String()).isCommand()) { + return true; } } return false; diff --git a/src/mongo/db/repl/transaction_oplog_application.cpp b/src/mongo/db/repl/transaction_oplog_application.cpp index 5ea9efb3731..2c77e473588 100644 --- a/src/mongo/db/repl/transaction_oplog_application.cpp +++ b/src/mongo/db/repl/transaction_oplog_application.cpp @@ -136,10 +136,10 @@ Status _applyTransactionFromOplogChain(OperationContext* opCtx, auto ops = readTransactionOperationsFromOplogChain(opCtx, entry, {}); - const auto dbName = entry.getNss().dbName(); + const auto dbName = entry.getNss().db().toString(); Status status = Status::OK(); - writeConflictRetry(opCtx, "replaying prepared transaction", dbName.db(), [&] { + writeConflictRetry(opCtx, "replaying prepared transaction", dbName, [&] { WriteUnitOfWork wunit(opCtx); // we might replay a prepared transaction behind oldest timestamp. |