diff options
author | Henrik Edin <henrik.edin@mongodb.com> | 2020-09-17 17:09:19 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-09-26 02:12:49 +0000 |
commit | 2b82ab88982566114d1bb7667477b71c883b0799 (patch) | |
tree | c152b35ff047fdc42f69aa6cd6b04fee1d811fe4 /src/mongo/db/repl | |
parent | 08e92a678a1ed288f6a95e7950597e082556ae59 (diff) | |
download | mongo-2b82ab88982566114d1bb7667477b71c883b0799.tar.gz |
SERVER-50984 Add CollectionPtr to replace usage of const Collection*
It implements a yieldable interface that is used to re-load the
Collection pointer from the catalog after a yield that released locks.
With lock-free reads and copy-on-write on Collection instances releasing
locks without notifying an AutoGetCollection at a higher level may cause
its pointers to dangle if a MODE_X writer installs a new Collection
instance in the catalog.
CollectionPtr should be passed by const reference so a yield can notify
all the way up.
Diffstat (limited to 'src/mongo/db/repl')
30 files changed, 130 insertions, 120 deletions
diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript index de85cf9021e..bff884e7844 100644 --- a/src/mongo/db/repl/SConscript +++ b/src/mongo/db/repl/SConscript @@ -21,6 +21,7 @@ env.Library( 'local_oplog_info.cpp', ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/catalog/collection', '$BUILD_DIR/mongo/db/logical_time', '$BUILD_DIR/mongo/db/storage/flow_control', '$BUILD_DIR/mongo/db/vector_clock_mutable', diff --git a/src/mongo/db/repl/apply_ops.cpp b/src/mongo/db/repl/apply_ops.cpp index d9c8565507f..8643f55ffff 100644 --- a/src/mongo/db/repl/apply_ops.cpp +++ b/src/mongo/db/repl/apply_ops.cpp @@ -315,7 +315,7 @@ Status _checkPrecondition(OperationContext* opCtx, if (!database) { return {ErrorCodes::NamespaceNotFound, "database in ns does not exist: " + nss.ns()}; } - const Collection* collection = + CollectionPtr collection = CollectionCatalog::get(opCtx).lookupCollectionByNamespace(opCtx, nss); if (!collection) { return {ErrorCodes::NamespaceNotFound, "collection in ns does not exist: " + nss.ns()}; diff --git a/src/mongo/db/repl/collection_bulk_loader.h b/src/mongo/db/repl/collection_bulk_loader.h index e58e262a674..7fc018f6a6a 100644 --- a/src/mongo/db/repl/collection_bulk_loader.h +++ b/src/mongo/db/repl/collection_bulk_loader.h @@ -39,6 +39,7 @@ namespace mongo { class Collection; +class CollectionPtr; class OperationContext; namespace repl { diff --git a/src/mongo/db/repl/dbcheck.cpp b/src/mongo/db/repl/dbcheck.cpp index 7da0b9c64a9..34127bb5e95 100644 --- a/src/mongo/db/repl/dbcheck.cpp +++ b/src/mongo/db/repl/dbcheck.cpp @@ -172,7 +172,7 @@ std::unique_ptr<HealthLogEntry> dbCheckBatchEntry(const NamespaceString& nss, } DbCheckHasher::DbCheckHasher(OperationContext* opCtx, - const Collection* collection, + const CollectionPtr& collection, const BSONKey& start, const BSONKey& end, int64_t maxCount, @@ -233,7 +233,7 @@ std::string hashCollectionInfo(const DbCheckCollectionInformation& info) { } std::pair<boost::optional<UUID>, boost::optional<UUID>> getPrevAndNextUUIDs( - OperationContext* opCtx, const Collection* collection) { + OperationContext* opCtx, const CollectionPtr& collection) { const CollectionCatalog& catalog = CollectionCatalog::get(opCtx); const UUID uuid = collection->uuid(); @@ -350,7 +350,7 @@ bool DbCheckHasher::_canHash(const BSONObj& obj) { return true; } -std::vector<BSONObj> collectionIndexInfo(OperationContext* opCtx, const Collection* collection) { +std::vector<BSONObj> collectionIndexInfo(OperationContext* opCtx, const CollectionPtr& collection) { std::vector<BSONObj> result; std::vector<std::string> names; @@ -370,7 +370,7 @@ std::vector<BSONObj> collectionIndexInfo(OperationContext* opCtx, const Collecti return result; } -BSONObj collectionOptions(OperationContext* opCtx, const Collection* collection) { +BSONObj collectionOptions(OperationContext* opCtx, const CollectionPtr& collection) { return DurableCatalog::get(opCtx) ->getCollectionOptions(opCtx, collection->getCatalogId()) .toBSON(); @@ -407,8 +407,7 @@ namespace { Status dbCheckBatchOnSecondary(OperationContext* opCtx, const repl::OpTime& optime, const DbCheckOplogBatch& entry) { - AutoGetCollectionForDbCheck agc(opCtx, entry.getNss(), entry.getType()); - const Collection* collection = agc.getCollection(); + AutoGetCollectionForDbCheck collection(opCtx, entry.getNss(), entry.getType()); std::string msg = "replication consistency check"; if (!collection) { @@ -419,7 +418,7 @@ Status dbCheckBatchOnSecondary(OperationContext* opCtx, Status status = Status::OK(); boost::optional<DbCheckHasher> hasher; try { - hasher.emplace(opCtx, collection, entry.getMinKey(), entry.getMaxKey()); + hasher.emplace(opCtx, collection.getCollection(), entry.getMinKey(), entry.getMaxKey()); } catch (const DBException& exception) { auto logEntry = dbCheckErrorHealthLogEntry( entry.getNss(), msg, OplogEntriesEnum::Batch, exception.toStatus()); diff --git a/src/mongo/db/repl/dbcheck.h b/src/mongo/db/repl/dbcheck.h index 99c28b4be59..2a5b2433cf8 100644 --- a/src/mongo/db/repl/dbcheck.h +++ b/src/mongo/db/repl/dbcheck.h @@ -41,6 +41,7 @@ namespace mongo { // Forward declarations. class Collection; +class CollectionPtr; class OperationContext; namespace repl { @@ -83,7 +84,7 @@ struct DbCheckCollectionInformation { * previous or next UUID, return boost::none respectively. */ std::pair<boost::optional<UUID>, boost::optional<UUID>> getPrevAndNextUUIDs( - OperationContext* opCtx, const Collection* collection); + OperationContext* opCtx, const CollectionPtr& collection); /** * Get a HealthLogEntry for a dbCheck collection. @@ -118,7 +119,7 @@ public: * @param maxBytes The maximum number of bytes to hash. */ DbCheckHasher(OperationContext* opCtx, - const Collection* collection, + const CollectionPtr& collection, const BSONKey& start, const BSONKey& end, int64_t maxCount = std::numeric_limits<int64_t>::max(), @@ -191,26 +192,34 @@ public: AutoGetCollectionForDbCheck(OperationContext* opCtx, const NamespaceString& nss, const OplogEntriesEnum& type); - const Collection* getCollection(void) { + explicit operator bool() const { + return static_cast<bool>(getCollection()); + } + + const Collection* operator->() const { + return getCollection().get(); + } + + const CollectionPtr& getCollection() const { return _collection; } private: AutoGetDbForDbCheck _agd; Lock::CollectionLock _collLock; - const Collection* _collection; + CollectionPtr _collection; }; /** * Gather the index information for a collection. */ -std::vector<BSONObj> collectionIndexInfo(OperationContext* opCtx, const Collection* collection); +std::vector<BSONObj> collectionIndexInfo(OperationContext* opCtx, const CollectionPtr& collection); /** * Gather other information for a collection. */ -BSONObj collectionOptions(OperationContext* opCtx, const Collection* collection); +BSONObj collectionOptions(OperationContext* opCtx, const CollectionPtr& collection); namespace repl { diff --git a/src/mongo/db/repl/idempotency_test_fixture.cpp b/src/mongo/db/repl/idempotency_test_fixture.cpp index ca996de2692..571b5abedfe 100644 --- a/src/mongo/db/repl/idempotency_test_fixture.cpp +++ b/src/mongo/db/repl/idempotency_test_fixture.cpp @@ -324,7 +324,7 @@ OplogEntry IdempotencyTest::partialTxn(LogicalSessionId lsid, prevOpTime); } -std::string IdempotencyTest::computeDataHash(const Collection* collection) { +std::string IdempotencyTest::computeDataHash(const CollectionPtr& collection) { auto desc = collection->getIndexCatalog()->findIdIndex(_opCtx.get()); ASSERT_TRUE(desc); auto exec = InternalPlanner::indexScan(_opCtx.get(), @@ -375,7 +375,7 @@ std::vector<CollectionState> IdempotencyTest::validateAllCollections() { CollectionState IdempotencyTest::validate(const NamespaceString& nss) { auto collUUID = [&]() -> OptionalCollectionUUID { AutoGetCollectionForReadCommand autoColl(_opCtx.get(), nss); - if (auto collection = autoColl.getCollection()) { + if (const auto& collection = autoColl.getCollection()) { return collection->uuid(); } return boost::none; @@ -388,8 +388,7 @@ CollectionState IdempotencyTest::validate(const NamespaceString& nss) { } { - AutoGetCollectionForReadCommand autoColl(_opCtx.get(), nss); - auto collection = autoColl.getCollection(); + AutoGetCollectionForReadCommand collection(_opCtx.get(), nss); if (!collection) { // Return a mostly default initialized CollectionState struct with exists set to false @@ -412,10 +411,9 @@ CollectionState IdempotencyTest::validate(const NamespaceString& nss) { ASSERT_TRUE(validateResults.valid); } - AutoGetCollectionForReadCommand autoColl(_opCtx.get(), nss); - auto collection = autoColl.getCollection(); + AutoGetCollectionForReadCommand collection(_opCtx.get(), nss); - std::string dataHash = computeDataHash(collection); + std::string dataHash = computeDataHash(collection.getCollection()); auto durableCatalog = DurableCatalog::get(_opCtx.get()); auto collectionOptions = diff --git a/src/mongo/db/repl/idempotency_test_fixture.h b/src/mongo/db/repl/idempotency_test_fixture.h index e871517e9f5..654e9c87ddd 100644 --- a/src/mongo/db/repl/idempotency_test_fixture.h +++ b/src/mongo/db/repl/idempotency_test_fixture.h @@ -49,6 +49,7 @@ namespace mongo { class Collection; +class CollectionPtr; namespace repl { @@ -151,7 +152,7 @@ protected: return obj; }; - std::string computeDataHash(const Collection* collection); + std::string computeDataHash(const CollectionPtr& collection); virtual std::string getStatesString(const std::vector<CollectionState>& state1, const std::vector<CollectionState>& state2, const std::vector<OplogEntry>& ops); diff --git a/src/mongo/db/repl/local_oplog_info.cpp b/src/mongo/db/repl/local_oplog_info.cpp index 01f48ac47b5..e73199c00db 100644 --- a/src/mongo/db/repl/local_oplog_info.cpp +++ b/src/mongo/db/repl/local_oplog_info.cpp @@ -81,16 +81,16 @@ void LocalOplogInfo::setOplogCollectionName(ServiceContext* service) { } } -const Collection* LocalOplogInfo::getCollection() const { +const CollectionPtr& LocalOplogInfo::getCollection() const { return _oplog; } -void LocalOplogInfo::setCollection(const Collection* oplog) { - _oplog = oplog; +void LocalOplogInfo::setCollection(const CollectionPtr& oplog) { + _oplog = oplog.detached(); } void LocalOplogInfo::resetCollection() { - _oplog = nullptr; + _oplog = CollectionPtr(); } void LocalOplogInfo::setNewTimestamp(ServiceContext* service, const Timestamp& newTime) { diff --git a/src/mongo/db/repl/local_oplog_info.h b/src/mongo/db/repl/local_oplog_info.h index 417901e4f4f..880e6bb6b0e 100644 --- a/src/mongo/db/repl/local_oplog_info.h +++ b/src/mongo/db/repl/local_oplog_info.h @@ -66,8 +66,8 @@ public: */ void setOplogCollectionName(ServiceContext* service); - const Collection* getCollection() const; - void setCollection(const Collection* oplog); + const CollectionPtr& getCollection() const; + void setCollection(const CollectionPtr& oplog); void resetCollection(); /** @@ -88,7 +88,7 @@ private: // The "oplog" pointer is always valid (or null) because an operation must take the global // exclusive lock to set the pointer to null when the Collection instance is destroyed. See // "oplogCheckCloseDatabase". - const Collection* _oplog = nullptr; + CollectionPtr _oplog; // Synchronizes the section where a new Timestamp is generated and when it is registered in the // storage engine. 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 09d79862c07..e6f426933e4 100644 --- a/src/mongo/db/repl/mock_repl_coord_server_fixture.cpp +++ b/src/mongo/db/repl/mock_repl_coord_server_fixture.cpp @@ -94,9 +94,8 @@ void MockReplCoordServerFixture::setUp() { } void MockReplCoordServerFixture::insertOplogEntry(const repl::OplogEntry& entry) { - AutoGetCollection autoColl(opCtx(), NamespaceString::kRsOplogNamespace, MODE_IX); - auto coll = autoColl.getCollection(); - ASSERT_TRUE(coll != nullptr); + AutoGetCollection coll(opCtx(), NamespaceString::kRsOplogNamespace, MODE_IX); + ASSERT_TRUE(coll); WriteUnitOfWork wuow(opCtx()); auto status = coll->insertDocument(opCtx(), diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index 8b0626fa926..23c148b7f75 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -213,7 +213,7 @@ void _logOpsInner(OperationContext* opCtx, const NamespaceString& nss, std::vector<Record>* records, const std::vector<Timestamp>& timestamps, - const Collection* oplogCollection, + const CollectionPtr& oplogCollection, OpTime finalOpTime, Date_t wallTime) { auto replCoord = ReplicationCoordinator::get(opCtx); @@ -333,7 +333,7 @@ OpTime logOp(OperationContext* opCtx, MutableOplogEntry* oplogEntry) { oplogEntry->setOpTime(slot); } - auto oplog = oplogInfo->getCollection(); + const auto& oplog = oplogInfo->getCollection(); auto wallClockTime = oplogEntry->getWallClockTime(); auto bsonOplogEntry = oplogEntry->toBSON(); @@ -425,7 +425,7 @@ std::vector<OpTime> logInsertOps(OperationContext* opCtx, invariant(!opTimes.empty()); auto lastOpTime = opTimes.back(); invariant(!lastOpTime.isNull()); - auto oplog = oplogInfo->getCollection(); + const auto& oplog = oplogInfo->getCollection(); auto wallClockTime = oplogEntryTemplate->getWallClockTime(); _logOpsInner(opCtx, nss, &records, timestamps, oplog, lastOpTime, wallClockTime); wuow.commit(); @@ -536,7 +536,7 @@ void createOplog(OperationContext* opCtx, const ReplSettings& replSettings = ReplicationCoordinator::get(opCtx)->getSettings(); OldClientContext ctx(opCtx, oplogCollectionName.ns()); - const Collection* collection = + CollectionPtr collection = CollectionCatalog::get(opCtx).lookupCollectionByNamespace(opCtx, oplogCollectionName); if (collection) { @@ -981,7 +981,7 @@ Status applyOperation_inlock(OperationContext* opCtx, } NamespaceString requestNss; - const Collection* collection = nullptr; + CollectionPtr collection = nullptr; if (auto uuid = op.getUuid()) { CollectionCatalog& catalog = CollectionCatalog::get(opCtx); collection = catalog.lookupCollectionByUUID(opCtx, uuid.get()); @@ -1728,14 +1728,14 @@ void acquireOplogCollectionForLogging(OperationContext* opCtx) { } } -void establishOplogCollectionForLogging(OperationContext* opCtx, const Collection* oplog) { +void establishOplogCollectionForLogging(OperationContext* opCtx, const CollectionPtr& oplog) { invariant(opCtx->lockState()->isW()); invariant(oplog); LocalOplogInfo::get(opCtx)->setCollection(oplog); } void signalOplogWaiters() { - auto oplog = LocalOplogInfo::get(getGlobalServiceContext())->getCollection(); + const auto& oplog = LocalOplogInfo::get(getGlobalServiceContext())->getCollection(); if (oplog) { oplog->getCappedCallback()->notifyCappedWaitersIfNeeded(); } diff --git a/src/mongo/db/repl/oplog.h b/src/mongo/db/repl/oplog.h index 17781db4df3..74e607d477e 100644 --- a/src/mongo/db/repl/oplog.h +++ b/src/mongo/db/repl/oplog.h @@ -45,6 +45,7 @@ namespace mongo { class Collection; +class CollectionPtr; class Database; class NamespaceString; class OperationContext; @@ -148,7 +149,7 @@ void acquireOplogCollectionForLogging(OperationContext* opCtx); * Called by catalog::openCatalog() to re-establish the oplog collection pointer while holding onto * the global lock in exclusive mode. */ -void establishOplogCollectionForLogging(OperationContext* opCtx, const Collection* oplog); +void establishOplogCollectionForLogging(OperationContext* opCtx, const CollectionPtr& oplog); using IncrementOpsAppliedStatsFn = std::function<void()>; diff --git a/src/mongo/db/repl/oplog_applier_impl_test.cpp b/src/mongo/db/repl/oplog_applier_impl_test.cpp index 9862126d7e2..f56011c0105 100644 --- a/src/mongo/db/repl/oplog_applier_impl_test.cpp +++ b/src/mongo/db/repl/oplog_applier_impl_test.cpp @@ -349,7 +349,7 @@ TEST_F(OplogApplierImplTest, applyOplogEntryOrGroupedInsertsCommand) { << BSON("create" << nss.coll()) << "ts" << Timestamp(1, 1) << "ui" << UUID::gen()); bool applyCmdCalled = false; _opObserver->onCreateCollectionFn = [&](OperationContext* opCtx, - const Collection*, + const CollectionPtr&, const NamespaceString& collNss, const CollectionOptions&, const BSONObj&) { 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 d75b6469b4a..72f996976c2 100644 --- a/src/mongo/db/repl/oplog_applier_impl_test_fixture.cpp +++ b/src/mongo/db/repl/oplog_applier_impl_test_fixture.cpp @@ -89,7 +89,7 @@ void OplogApplierImplOpObserver::onUpdate(OperationContext* opCtx, } void OplogApplierImplOpObserver::onCreateCollection(OperationContext* opCtx, - const Collection* coll, + const CollectionPtr& coll, const NamespaceString& collectionName, const CollectionOptions& options, const BSONObj& idIndex, 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 1a6c414d182..28fec503692 100644 --- a/src/mongo/db/repl/oplog_applier_impl_test_fixture.h +++ b/src/mongo/db/repl/oplog_applier_impl_test_fixture.h @@ -99,7 +99,7 @@ public: * Called when OplogApplierImpl creates a collection. */ void onCreateCollection(OperationContext* opCtx, - const Collection* coll, + const CollectionPtr& coll, const NamespaceString& collectionName, const CollectionOptions& options, const BSONObj& idIndex, @@ -121,7 +121,7 @@ public: std::function<void(OperationContext*, const OplogUpdateEntryArgs&)> onUpdateFn; std::function<void(OperationContext*, - const Collection*, + const CollectionPtr&, const NamespaceString&, const CollectionOptions&, const BSONObj&)> diff --git a/src/mongo/db/repl/primary_only_service_op_observer.h b/src/mongo/db/repl/primary_only_service_op_observer.h index 7b176eb663e..f0314ab9231 100644 --- a/src/mongo/db/repl/primary_only_service_op_observer.h +++ b/src/mongo/db/repl/primary_only_service_op_observer.h @@ -108,7 +108,7 @@ public: const boost::optional<OplogSlot> slot) final {} void onCreateCollection(OperationContext* opCtx, - const Collection* coll, + const CollectionPtr& coll, const NamespaceString& collectionName, const CollectionOptions& options, const BSONObj& idIndex, diff --git a/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp b/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp index 8e2badd998f..8daa5f92aba 100644 --- a/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp @@ -715,8 +715,7 @@ Timestamp ReplicationCoordinatorExternalStateImpl::getGlobalTimestamp(ServiceCon } bool ReplicationCoordinatorExternalStateImpl::oplogExists(OperationContext* opCtx) { - auto oplog = LocalOplogInfo::get(opCtx)->getCollection(); - return oplog != nullptr; + return static_cast<bool>(LocalOplogInfo::get(opCtx)->getCollection()); } StatusWith<OpTimeAndWallTime> ReplicationCoordinatorExternalStateImpl::loadLastOpTimeAndWallTime( diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp index a5f5d199b2d..766d69ffbc2 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl.cpp @@ -2303,7 +2303,7 @@ StatusWith<OpTime> ReplicationCoordinatorImpl::getLatestWriteOpTime(OperationCon if (!canAcceptNonLocalWrites()) { return {ErrorCodes::NotWritablePrimary, "Not primary so can't get latest write optime"}; } - auto oplog = LocalOplogInfo::get(opCtx)->getCollection(); + const auto& oplog = LocalOplogInfo::get(opCtx)->getCollection(); if (!oplog) { return {ErrorCodes::NamespaceNotFound, "oplog collection does not exist"}; } @@ -2836,7 +2836,7 @@ bool ReplicationCoordinatorImpl::canAcceptWritesFor_UNSAFE(OperationContext* opC if (!ns->isOplog()) { return true; } - } else if (auto oplogCollection = LocalOplogInfo::get(opCtx)->getCollection()) { + } else if (const auto& oplogCollection = LocalOplogInfo::get(opCtx)->getCollection()) { auto uuid = nsOrUUID.uuid(); invariant(uuid, nsOrUUID.toString()); if (oplogCollection->uuid() != *uuid) { diff --git a/src/mongo/db/repl/rollback_impl.cpp b/src/mongo/db/repl/rollback_impl.cpp index 365410970ad..a696a57966b 100644 --- a/src/mongo/db/repl/rollback_impl.cpp +++ b/src/mongo/db/repl/rollback_impl.cpp @@ -603,12 +603,12 @@ void RollbackImpl::_correctRecordStoreCounts(OperationContext* opCtx) { "Scanning collection to fix collection count", "namespace"_attr = nss.ns(), "uuid"_attr = uuid.toString()); - AutoGetCollectionForRead autoCollToScan(opCtx, nss); - auto collToScan = autoCollToScan.getCollection(); - invariant(coll == collToScan, + AutoGetCollectionForRead collToScan(opCtx, nss); + invariant(coll == collToScan.getCollection(), str::stream() << "Catalog returned invalid collection: " << nss.ns() << " (" << uuid.toString() << ")"); auto exec = collToScan->makePlanExecutor(opCtx, + collToScan.getCollection(), PlanYieldPolicy::YieldPolicy::INTERRUPT_ONLY, Collection::ScanDirection::kForward); long long countFromScan = 0; diff --git a/src/mongo/db/repl/rollback_test_fixture.cpp b/src/mongo/db/repl/rollback_test_fixture.cpp index 862ba41e289..91a995fc466 100644 --- a/src/mongo/db/repl/rollback_test_fixture.cpp +++ b/src/mongo/db/repl/rollback_test_fixture.cpp @@ -233,17 +233,20 @@ void RollbackTest::_insertDocument(OperationContext* opCtx, const NamespaceString& nss, const BSONObj& doc) { - AutoGetCollection autoColl(opCtx, nss, MODE_X); - auto collection = autoColl.getCollection(); - if (!collection) { + auto insertDoc = [opCtx, &doc](const CollectionPtr& collection) { + WriteUnitOfWork wuow(opCtx); + OpDebug* const opDebug = nullptr; + ASSERT_OK(collection->insertDocument(opCtx, InsertStatement(doc), opDebug)); + wuow.commit(); + }; + AutoGetCollection collection(opCtx, nss, MODE_X); + if (collection) { + insertDoc(collection.getCollection()); + } else { CollectionOptions options; options.uuid = UUID::gen(); - collection = _createCollection(opCtx, nss, options); + insertDoc(_createCollection(opCtx, nss, options)); } - WriteUnitOfWork wuow(opCtx); - OpDebug* const opDebug = nullptr; - ASSERT_OK(collection->insertDocument(opCtx, InsertStatement(doc), opDebug)); - wuow.commit(); } Status RollbackTest::_insertOplogEntry(const BSONObj& doc) { diff --git a/src/mongo/db/repl/rs_rollback.cpp b/src/mongo/db/repl/rs_rollback.cpp index fa6b07c6696..0689bab6384 100644 --- a/src/mongo/db/repl/rs_rollback.cpp +++ b/src/mongo/db/repl/rs_rollback.cpp @@ -971,7 +971,7 @@ void rollbackDropIndexes(OperationContext* opCtx, invariant(nss); Lock::DBLock dbLock(opCtx, nss->db(), MODE_IX); Lock::CollectionLock collLock(opCtx, *nss, MODE_X); - const Collection* collection = + CollectionPtr collection = CollectionCatalog::get(opCtx).lookupCollectionByNamespace(opCtx, *nss); // If we cannot find the collection, we skip over dropping the index. @@ -1016,7 +1016,7 @@ void rollbackDropIndexes(OperationContext* opCtx, */ void dropCollection(OperationContext* opCtx, NamespaceString nss, - const Collection* collection, + const CollectionPtr& collection, Database* db) { if (RollbackImpl::shouldCreateDataFiles()) { RemoveSaver removeSaver("rollback", "", collection->uuid().toString()); @@ -1499,7 +1499,7 @@ void rollback_internal::syncFixUp(OperationContext* opCtx, Database* db = dbLock.getDb(); if (db) { - const Collection* collection = + CollectionPtr collection = CollectionCatalog::get(opCtx).lookupCollectionByUUID(opCtx, uuid); dropCollection(opCtx, *nss, collection, db); LOGV2_DEBUG(21698, diff --git a/src/mongo/db/repl/rs_rollback_test.cpp b/src/mongo/db/repl/rs_rollback_test.cpp index b785eadeaa5..d7a14c13a35 100644 --- a/src/mongo/db/repl/rs_rollback_test.cpp +++ b/src/mongo/db/repl/rs_rollback_test.cpp @@ -79,7 +79,7 @@ OplogInterfaceMock::Operation makeNoopOplogEntryAndRecordId(Seconds seconds) { return std::make_pair(BSON("ts" << ts.getTimestamp()), RecordId(1)); } -OplogInterfaceMock::Operation makeDropIndexOplogEntry(const Collection* collection, +OplogInterfaceMock::Operation makeDropIndexOplogEntry(const CollectionPtr& collection, BSONObj key, std::string indexName, int time) { @@ -96,7 +96,7 @@ OplogInterfaceMock::Operation makeDropIndexOplogEntry(const Collection* collecti RecordId(time)); } -OplogInterfaceMock::Operation makeStartIndexBuildOplogEntry(const Collection* collection, +OplogInterfaceMock::Operation makeStartIndexBuildOplogEntry(const CollectionPtr& collection, UUID buildUUID, BSONObj spec, int time) { @@ -112,7 +112,7 @@ OplogInterfaceMock::Operation makeStartIndexBuildOplogEntry(const Collection* co RecordId(time)); } -OplogInterfaceMock::Operation makeCommitIndexBuildOplogEntry(const Collection* collection, +OplogInterfaceMock::Operation makeCommitIndexBuildOplogEntry(const CollectionPtr& collection, UUID buildUUID, BSONObj spec, int time) { @@ -128,7 +128,7 @@ OplogInterfaceMock::Operation makeCommitIndexBuildOplogEntry(const Collection* c RecordId(time)); } -OplogInterfaceMock::Operation makeAbortIndexBuildOplogEntry(const Collection* collection, +OplogInterfaceMock::Operation makeAbortIndexBuildOplogEntry(const CollectionPtr& collection, UUID buildUUID, BSONObj spec, int time) { @@ -150,7 +150,7 @@ OplogInterfaceMock::Operation makeAbortIndexBuildOplogEntry(const Collection* co RecordId(time)); } -OplogInterfaceMock::Operation makeCreateIndexOplogEntry(const Collection* collection, +OplogInterfaceMock::Operation makeCreateIndexOplogEntry(const CollectionPtr& collection, BSONObj key, std::string indexName, int time) { @@ -847,14 +847,14 @@ BSONObj idxSpec(NamespaceString nss, std::string id) { } // Returns the number of indexes that exist on the given collection. -int numIndexesOnColl(OperationContext* opCtx, NamespaceString nss, const Collection* coll) { +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 Collection* coll) { +int numIndexesInProgress(OperationContext* opCtx, NamespaceString nss, const CollectionPtr& coll) { Lock::DBLock dbLock(opCtx, nss.db(), MODE_X); auto indexCatalog = coll->getIndexCatalog(); ASSERT(indexCatalog); @@ -1738,7 +1738,7 @@ OpTime getOpTimeFromOplogEntry(const BSONObj& entry) { TEST_F(RSRollbackTest, RollbackApplyOpsCommand) { createOplog(_opCtx.get()); - const Collection* coll = nullptr; + CollectionPtr coll; CollectionOptions options; options.uuid = UUID::gen(); { diff --git a/src/mongo/db/repl/storage_interface.h b/src/mongo/db/repl/storage_interface.h index ef8af4ac2c1..098df44021d 100644 --- a/src/mongo/db/repl/storage_interface.h +++ b/src/mongo/db/repl/storage_interface.h @@ -47,6 +47,7 @@ namespace mongo { class Collection; +class CollectionPtr; struct CollectionOptions; class OperationContext; @@ -326,7 +327,7 @@ public: * matches are found. */ virtual boost::optional<BSONObj> findOplogEntryLessThanOrEqualToTimestamp( - OperationContext* opCtx, const Collection* oplog, const Timestamp& timestamp) = 0; + OperationContext* opCtx, const CollectionPtr& oplog, const Timestamp& timestamp) = 0; /** * Calls findOplogEntryLessThanOrEqualToTimestamp with endless WriteConflictException retries. @@ -337,7 +338,7 @@ public: * fail, say for correctness. */ virtual boost::optional<BSONObj> findOplogEntryLessThanOrEqualToTimestampRetryOnWCE( - OperationContext* opCtx, const Collection* oplog, const Timestamp& timestamp) = 0; + OperationContext* opCtx, const CollectionPtr& oplog, const Timestamp& timestamp) = 0; /** * Fetches the latest oplog entry's timestamp. Bypasses the oplog visibility rules. diff --git a/src/mongo/db/repl/storage_interface_impl.cpp b/src/mongo/db/repl/storage_interface_impl.cpp index f9b6945b259..926cc60efcb 100644 --- a/src/mongo/db/repl/storage_interface_impl.cpp +++ b/src/mongo/db/repl/storage_interface_impl.cpp @@ -299,28 +299,27 @@ Status StorageInterfaceImpl::insertDocument(OperationContext* opCtx, namespace { /** - * Returns const Collection* from database RAII object. + * Returns const CollectionPtr& from database RAII object. * Returns NamespaceNotFound if the database or collection does not exist. */ template <typename AutoGetCollectionType> -StatusWith<decltype(std::declval<AutoGetCollectionType>().getCollection())> getCollection( - const AutoGetCollectionType& autoGetCollection, - const NamespaceStringOrUUID& nsOrUUID, - const std::string& message) { +StatusWith<const CollectionPtr*> getCollection(const AutoGetCollectionType& autoGetCollection, + const NamespaceStringOrUUID& nsOrUUID, + const std::string& message) { if (!autoGetCollection.getDb()) { StringData dbName = nsOrUUID.nss() ? nsOrUUID.nss()->db() : nsOrUUID.dbname(); return {ErrorCodes::NamespaceNotFound, str::stream() << "Database [" << dbName << "] not found. " << message}; } - auto collection = autoGetCollection.getCollection(); + const auto& collection = autoGetCollection.getCollection(); if (!collection) { return {ErrorCodes::NamespaceNotFound, str::stream() << "Collection [" << nsOrUUID.toString() << "] not found. " << message}; } - return collection; + return &collection; } Status insertDocumentsSingleBatch(OperationContext* opCtx, @@ -329,14 +328,14 @@ Status insertDocumentsSingleBatch(OperationContext* opCtx, std::vector<InsertStatement>::const_iterator end) { boost::optional<AutoGetCollection> autoColl; boost::optional<AutoGetOplog> autoOplog; - const Collection* collection; + const CollectionPtr* collection; auto nss = nsOrUUID.nss(); if (nss && nss->isOplog()) { // Simplify locking rules for oplog collection. autoOplog.emplace(opCtx, OplogAccessMode::kWrite); - collection = autoOplog->getCollection(); - if (!collection) { + collection = &autoOplog->getCollection(); + if (!*collection) { return {ErrorCodes::NamespaceNotFound, "Oplog collection does not exist"}; } } else { @@ -351,7 +350,7 @@ Status insertDocumentsSingleBatch(OperationContext* opCtx, WriteUnitOfWork wunit(opCtx); OpDebug* const nullOpDebug = nullptr; - auto status = collection->insertDocuments(opCtx, begin, end, nullOpDebug, false); + auto status = (*collection)->insertDocuments(opCtx, begin, end, nullOpDebug, false); if (!status.isOK()) { return status; } @@ -454,7 +453,7 @@ StatusWith<size_t> StorageInterfaceImpl::getOplogMaxSize(OperationContext* opCtx NamespaceString::kRsOplogNamespace.ns(), [&]() -> StatusWith<size_t> { AutoGetOplog oplogRead(opCtx, OplogAccessMode::kRead); - auto oplog = oplogRead.getCollection(); + const auto& oplog = oplogRead.getCollection(); if (!oplog) { return {ErrorCodes::NamespaceNotFound, "Your oplog doesn't exist."}; } @@ -602,7 +601,7 @@ Status StorageInterfaceImpl::setIndexIsMultikey(OperationContext* opCtx, if (!collectionResult.isOK()) { return collectionResult.getStatus(); } - auto collection = collectionResult.getValue(); + const auto& collection = *collectionResult.getValue(); WriteUnitOfWork wunit(opCtx); auto tsResult = opCtx->recoveryUnit()->setTimestamp(ts); @@ -667,7 +666,7 @@ StatusWith<std::vector<BSONObj>> _findOrDeleteDocuments( if (!collectionResult.isOK()) { return Result(collectionResult.getStatus()); } - auto collection = collectionResult.getValue(); + const auto& collection = *collectionResult.getValue(); auto isForward = scanDirection == StorageInterface::ScanDirection::kForward; auto direction = isForward ? InternalPlanner::FORWARD : InternalPlanner::BACKWARD; @@ -922,7 +921,7 @@ Status _updateWithQuery(OperationContext* opCtx, if (!collectionResult.isOK()) { return collectionResult.getStatus(); } - auto collection = collectionResult.getValue(); + const auto& collection = *collectionResult.getValue(); WriteUnitOfWork wuow(opCtx); if (!ts.isNull()) { uassertStatusOK(opCtx->recoveryUnit()->setTimestamp(ts)); @@ -970,7 +969,7 @@ Status StorageInterfaceImpl::upsertById(OperationContext* opCtx, if (!collectionResult.isOK()) { return collectionResult.getStatus(); } - auto collection = collectionResult.getValue(); + const auto& collection = *collectionResult.getValue(); // We can create an UpdateRequest now that the collection's namespace has been resolved, in // the event it was specified as a UUID. @@ -1080,7 +1079,7 @@ Status StorageInterfaceImpl::deleteByFilter(OperationContext* opCtx, if (!collectionResult.isOK()) { return collectionResult.getStatus(); } - auto collection = collectionResult.getValue(); + const auto& collection = *collectionResult.getValue(); auto planExecutorResult = mongo::getExecutorDelete( nullptr, collection, &parsedDelete, boost::none /* verbosity */); @@ -1103,7 +1102,7 @@ Status StorageInterfaceImpl::deleteByFilter(OperationContext* opCtx, } boost::optional<BSONObj> StorageInterfaceImpl::findOplogEntryLessThanOrEqualToTimestamp( - OperationContext* opCtx, const Collection* oplog, const Timestamp& timestamp) { + OperationContext* opCtx, const CollectionPtr& oplog, const Timestamp& timestamp) { invariant(oplog); invariant(opCtx->lockState()->isLocked()); @@ -1134,7 +1133,7 @@ boost::optional<BSONObj> StorageInterfaceImpl::findOplogEntryLessThanOrEqualToTi } boost::optional<BSONObj> StorageInterfaceImpl::findOplogEntryLessThanOrEqualToTimestampRetryOnWCE( - OperationContext* opCtx, const Collection* oplogCollection, const Timestamp& timestamp) { + OperationContext* opCtx, const CollectionPtr& oplogCollection, const Timestamp& timestamp) { // Oplog reads are specially done under only MODE_IS global locks, without database or // collection level intent locks. Therefore, reads can run concurrently with validate cmds that // take collection MODE_X locks. Validate with {full:true} set calls WT::verify on the @@ -1209,7 +1208,7 @@ StatusWith<StorageInterface::CollectionSize> StorageInterfaceImpl::getCollection if (!collectionResult.isOK()) { return collectionResult.getStatus(); } - auto collection = collectionResult.getValue(); + const auto& collection = *collectionResult.getValue(); return collection->dataSize(opCtx); } @@ -1223,7 +1222,7 @@ StatusWith<StorageInterface::CollectionCount> StorageInterfaceImpl::getCollectio if (!collectionResult.isOK()) { return collectionResult.getStatus(); } - auto collection = collectionResult.getValue(); + const auto& collection = *collectionResult.getValue(); return collection->numRecords(opCtx); } @@ -1238,7 +1237,7 @@ Status StorageInterfaceImpl::setCollectionCount(OperationContext* opCtx, if (!collectionResult.isOK()) { return collectionResult.getStatus(); } - auto collection = collectionResult.getValue(); + const auto& collection = *collectionResult.getValue(); auto rs = collection->getRecordStore(); // We cannot fix the data size correctly, so we just get the current cached value and keep it @@ -1257,7 +1256,7 @@ StatusWith<OptionalCollectionUUID> StorageInterfaceImpl::getCollectionUUID( if (!collectionResult.isOK()) { return collectionResult.getStatus(); } - auto collection = collectionResult.getValue(); + const auto& collection = *collectionResult.getValue(); return collection->uuid(); } @@ -1340,12 +1339,11 @@ Status StorageInterfaceImpl::isAdminDbValid(OperationContext* opCtx) { return Status::OK(); } - const Collection* const usersCollection = - CollectionCatalog::get(opCtx).lookupCollectionByNamespace( - opCtx, AuthorizationManager::usersCollectionNamespace); + CollectionPtr usersCollection = CollectionCatalog::get(opCtx).lookupCollectionByNamespace( + opCtx, AuthorizationManager::usersCollectionNamespace); const bool hasUsers = usersCollection && !Helpers::findOne(opCtx, usersCollection, BSONObj(), false).isNull(); - const Collection* const adminVersionCollection = + CollectionPtr adminVersionCollection = CollectionCatalog::get(opCtx).lookupCollectionByNamespace( opCtx, AuthorizationManager::versionCollectionNamespace); BSONObj authSchemaVersionDocument; @@ -1398,7 +1396,7 @@ void StorageInterfaceImpl::waitForAllEarlierOplogWritesToBeVisible(OperationCont if (primaryOnly && !repl::ReplicationCoordinator::get(opCtx)->canAcceptWritesForDatabase(opCtx, "admin")) return; - auto oplog = oplogRead.getCollection(); + const auto& oplog = oplogRead.getCollection(); uassert(ErrorCodes::NotYetInitialized, "The oplog does not exist", oplog); oplog->getRecordStore()->waitForAllEarlierOplogWritesToBeVisible(opCtx); } diff --git a/src/mongo/db/repl/storage_interface_impl.h b/src/mongo/db/repl/storage_interface_impl.h index 2cddfaa4719..0e13614d443 100644 --- a/src/mongo/db/repl/storage_interface_impl.h +++ b/src/mongo/db/repl/storage_interface_impl.h @@ -148,10 +148,10 @@ public: const BSONObj& filter) override; boost::optional<BSONObj> findOplogEntryLessThanOrEqualToTimestamp( - OperationContext* opCtx, const Collection* oplog, const Timestamp& timestamp) override; + OperationContext* opCtx, const CollectionPtr& oplog, const Timestamp& timestamp) override; boost::optional<BSONObj> findOplogEntryLessThanOrEqualToTimestampRetryOnWCE( - OperationContext* opCtx, const Collection* oplog, const Timestamp& timestamp) override; + OperationContext* opCtx, const CollectionPtr& oplog, const Timestamp& timestamp) override; Timestamp getLatestOplogTimestamp(OperationContext* opCtx) override; diff --git a/src/mongo/db/repl/storage_interface_impl_test.cpp b/src/mongo/db/repl/storage_interface_impl_test.cpp index 3efd6bf1bcb..e78f89427ab 100644 --- a/src/mongo/db/repl/storage_interface_impl_test.cpp +++ b/src/mongo/db/repl/storage_interface_impl_test.cpp @@ -573,8 +573,7 @@ TEST_F(StorageInterfaceImplTest, CreateCollectionWithIDIndexCommits) { ASSERT_OK(loader->insertDocuments(docs.begin(), docs.end())); ASSERT_OK(loader->commit()); - AutoGetCollectionForReadCommand autoColl(opCtx, nss); - auto coll = autoColl.getCollection(); + AutoGetCollectionForReadCommand coll(opCtx, nss); ASSERT(coll); ASSERT_EQ(coll->getRecordStore()->numRecords(opCtx), 2LL); auto collIdxCat = coll->getIndexCatalog(); @@ -601,8 +600,7 @@ void _testDestroyUncommitedCollectionBulkLoader( // Collection and ID index should not exist after 'loader' is destroyed. destroyLoaderFn(std::move(loader)); - AutoGetCollectionForReadCommand autoColl(opCtx, nss); - auto coll = autoColl.getCollection(); + AutoGetCollectionForReadCommand coll(opCtx, nss); // Bulk loader is used to create indexes. The collection is not dropped when the bulk loader is // destroyed. diff --git a/src/mongo/db/repl/storage_interface_mock.h b/src/mongo/db/repl/storage_interface_mock.h index 074f520ef62..9af77afaa55 100644 --- a/src/mongo/db/repl/storage_interface_mock.h +++ b/src/mongo/db/repl/storage_interface_mock.h @@ -273,12 +273,12 @@ public: } boost::optional<BSONObj> findOplogEntryLessThanOrEqualToTimestamp( - OperationContext* opCtx, const Collection* oplog, const Timestamp& timestamp) override { + OperationContext* opCtx, const CollectionPtr& oplog, const Timestamp& timestamp) override { return boost::none; } boost::optional<BSONObj> findOplogEntryLessThanOrEqualToTimestampRetryOnWCE( - OperationContext* opCtx, const Collection* oplog, const Timestamp& timestamp) override { + OperationContext* opCtx, const CollectionPtr& oplog, const Timestamp& timestamp) override { return boost::none; } diff --git a/src/mongo/db/repl/tenant_migration_donor_op_observer.h b/src/mongo/db/repl/tenant_migration_donor_op_observer.h index 302ee5bfaef..d317a518498 100644 --- a/src/mongo/db/repl/tenant_migration_donor_op_observer.h +++ b/src/mongo/db/repl/tenant_migration_donor_op_observer.h @@ -106,7 +106,7 @@ public: const boost::optional<OplogSlot> slot) final {} void onCreateCollection(OperationContext* opCtx, - const Collection* coll, + const CollectionPtr& coll, const NamespaceString& collectionName, const CollectionOptions& options, const BSONObj& idIndex, diff --git a/src/mongo/db/repl/tenant_migration_recipient_entry_helpers.cpp b/src/mongo/db/repl/tenant_migration_recipient_entry_helpers.cpp index 357d38ae466..de656c59ca6 100644 --- a/src/mongo/db/repl/tenant_migration_recipient_entry_helpers.cpp +++ b/src/mongo/db/repl/tenant_migration_recipient_entry_helpers.cpp @@ -52,9 +52,9 @@ namespace { * Creates the tenant migration recipients collection if it doesn't exist. * Note: Throws WriteConflictException if the collection already exist. */ -const Collection* ensureTenantMigrationRecipientsCollectionExists(OperationContext* opCtx, - Database* db, - const NamespaceString& nss) { +CollectionPtr ensureTenantMigrationRecipientsCollectionExists(OperationContext* opCtx, + Database* db, + const NamespaceString& nss) { // Sanity checks. invariant(db); invariant(opCtx->lockState()->isCollectionLockedForMode(nss, MODE_IX)); @@ -129,9 +129,8 @@ StatusWith<TenantMigrationRecipientDocument> getStateDoc(OperationContext* opCtx const UUID& migrationUUID) { // Read the most up to date data. ReadSourceScope readSourceScope(opCtx, RecoveryUnit::ReadSource::kNoTimestamp); - AutoGetCollectionForRead autoCollection(opCtx, - NamespaceString::kTenantMigrationRecipientsNamespace); - const Collection* collection = autoCollection.getCollection(); + AutoGetCollectionForRead collection(opCtx, + NamespaceString::kTenantMigrationRecipientsNamespace); if (!collection) { return Status(ErrorCodes::NamespaceNotFound, @@ -140,8 +139,11 @@ StatusWith<TenantMigrationRecipientDocument> getStateDoc(OperationContext* opCtx } BSONObj result; - auto foundDoc = Helpers::findOne( - opCtx, collection, BSON("_id" << migrationUUID), result, /*requireIndex=*/true); + auto foundDoc = Helpers::findOne(opCtx, + collection.getCollection(), + BSON("_id" << migrationUUID), + result, + /*requireIndex=*/true); if (!foundDoc) { return Status(ErrorCodes::NoMatchingDocument, str::stream() << "No matching state doc found with tenant migration UUID: " diff --git a/src/mongo/db/repl/tenant_oplog_applier_test.cpp b/src/mongo/db/repl/tenant_oplog_applier_test.cpp index 39a07d3d0b7..15efc7052b9 100644 --- a/src/mongo/db/repl/tenant_oplog_applier_test.cpp +++ b/src/mongo/db/repl/tenant_oplog_applier_test.cpp @@ -578,7 +578,7 @@ TEST_F(TenantOplogApplierTest, ApplyCommand_Success) { << BSON("create" << nss.coll()) << "ts" << Timestamp(1, 1) << "ui" << UUID::gen()); bool applyCmdCalled = false; _opObserver->onCreateCollectionFn = [&](OperationContext* opCtx, - const Collection*, + const CollectionPtr&, const NamespaceString& collNss, const CollectionOptions&, const BSONObj&) { @@ -609,7 +609,7 @@ TEST_F(TenantOplogApplierTest, ApplyCommand_WrongNSS) { << BSON("create" << nss.coll()) << "ts" << Timestamp(1, 1) << "ui" << UUID::gen()); bool applyCmdCalled = false; _opObserver->onCreateCollectionFn = [&](OperationContext* opCtx, - const Collection*, + const CollectionPtr&, const NamespaceString& collNss, const CollectionOptions&, const BSONObj&) { applyCmdCalled = true; }; |