diff options
-rw-r--r-- | src/mongo/db/catalog/collection_catalog.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_catalog.h | 23 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_catalog_test.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/catalog/database.h | 13 | ||||
-rw-r--r-- | src/mongo/db/catalog/database_holder_impl.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/catalog/database_holder_impl.h | 10 | ||||
-rw-r--r-- | src/mongo/db/catalog/database_impl.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/catalog/database_impl.h | 8 | ||||
-rw-r--r-- | src/mongo/db/exec/requires_collection_stage.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/exec/requires_collection_stage.h | 16 |
10 files changed, 48 insertions, 47 deletions
diff --git a/src/mongo/db/catalog/collection_catalog.cpp b/src/mongo/db/catalog/collection_catalog.cpp index 8b1de565c47..c6e4973f259 100644 --- a/src/mongo/db/catalog/collection_catalog.cpp +++ b/src/mongo/db/catalog/collection_catalog.cpp @@ -249,6 +249,11 @@ void CollectionCatalog::onOpenCatalog(OperationContext* opCtx) { stdx::lock_guard<Latch> lock(_catalogLock); invariant(_shadowCatalog); _shadowCatalog.reset(); + ++_epoch; +} + +uint64_t CollectionCatalog::getEpoch() const { + return _epoch; } Collection* CollectionCatalog::lookupCollectionByUUID(OperationContext* opCtx, diff --git a/src/mongo/db/catalog/collection_catalog.h b/src/mongo/db/catalog/collection_catalog.h index 23d0bf88b25..1a57e6f55f5 100644 --- a/src/mongo/db/catalog/collection_catalog.h +++ b/src/mongo/db/catalog/collection_catalog.h @@ -235,6 +235,17 @@ public: */ void onOpenCatalog(OperationContext* opCtx); + /** + * The epoch is incremented whenever the catalog is closed and re-opened. + * + * Callers of this method must hold the global lock in at least MODE_IS. + * + * This allows callers to detect an intervening catalog close. For example, closing the catalog + * must kill all active queries. This is implemented by checking that the epoch has not changed + * during query yield recovery. + */ + uint64_t getEpoch() const; + iterator begin(StringData db) const; iterator end() const; @@ -285,6 +296,18 @@ private: */ uint64_t _generationNumber; + // Incremented whenever the CollectionCatalog gets closed and reopened (onCloseCatalog and + // onOpenCatalog). + // + // Catalog objects are destroyed and recreated when the catalog is closed and re-opened. We + // increment this counter to track when the catalog is reopened. This permits callers to detect + // after yielding whether their catalog pointers are still valid. Collection UUIDs are not + // sufficient, since they remain stable across catalog re-opening. + // + // A thread must hold the global exclusive lock to write to this variable, and must hold the + // global lock in at least MODE_IS to read it. + uint64_t _epoch = 0; + // Protects _resourceInformation. mutable Mutex _resourceLock = MONGO_MAKE_LATCH("CollectionCatalog::_resourceLock"); diff --git a/src/mongo/db/catalog/collection_catalog_test.cpp b/src/mongo/db/catalog/collection_catalog_test.cpp index 573ee9f5b3e..4cf75ec7962 100644 --- a/src/mongo/db/catalog/collection_catalog_test.cpp +++ b/src/mongo/db/catalog/collection_catalog_test.cpp @@ -576,6 +576,15 @@ TEST_F(CollectionCatalogTest, LookupNSSByUUIDForClosedCatalogReturnsFreshestNSS) ASSERT_EQUALS(*catalog.lookupNSSByUUID(&opCtx, colUUID), newNss); } +// Re-opening the catalog should increment the CollectionCatalog's epoch. +TEST_F(CollectionCatalogTest, CollectionCatalogEpoch) { + auto originalEpoch = catalog.getEpoch(); + catalog.onCloseCatalog(&opCtx); + catalog.onOpenCatalog(&opCtx); + auto incrementedEpoch = catalog.getEpoch(); + ASSERT_EQ(originalEpoch + 1, incrementedEpoch); +} + DEATH_TEST_F(CollectionCatalogResourceTest, AddInvalidResourceType, "invariant") { auto rid = ResourceId(RESOURCE_GLOBAL, 0); catalog.addResource(rid, ""); diff --git a/src/mongo/db/catalog/database.h b/src/mongo/db/catalog/database.h index f0ae23db785..bf8c12638d2 100644 --- a/src/mongo/db/catalog/database.h +++ b/src/mongo/db/catalog/database.h @@ -172,19 +172,6 @@ public: * DropPendingCollectionReaper to clean up eventually. */ virtual void checkForIdIndexesAndDropPendingCollections(OperationContext* opCtx) const = 0; - - /** - * A database is assigned a new epoch whenever it is closed and re-opened. This involves - * deleting and reallocating a new Database object, so the epoch for a particular Database - * instance is immutable. - * - * Callers of this method must hold the global lock in at least MODE_IS. - * - * This allows callers which drop and reacquire locks to detect an intervening database close. - * For example, closing a database must kill all active queries against the database. This is - * implemented by checking that the epoch has not changed during query yield recovery. - */ - virtual uint64_t epoch() const = 0; }; } // namespace mongo diff --git a/src/mongo/db/catalog/database_holder_impl.cpp b/src/mongo/db/catalog/database_holder_impl.cpp index 93e1a98b0fa..7d72ed98cef 100644 --- a/src/mongo/db/catalog/database_holder_impl.cpp +++ b/src/mongo/db/catalog/database_holder_impl.cpp @@ -147,7 +147,7 @@ Database* DatabaseHolderImpl::openDb(OperationContext* opCtx, StringData ns, boo *justCreated = true; } - auto newDb = std::make_unique<DatabaseImpl>(dbname, ++_epoch); + auto newDb = std::make_unique<DatabaseImpl>(dbname); newDb->init(opCtx); // Finally replace our nullptr entry with the new Database pointer. diff --git a/src/mongo/db/catalog/database_holder_impl.h b/src/mongo/db/catalog/database_holder_impl.h index cede54eab55..8b200c22a51 100644 --- a/src/mongo/db/catalog/database_holder_impl.h +++ b/src/mongo/db/catalog/database_holder_impl.h @@ -60,16 +60,6 @@ private: typedef StringMap<Database*> DBs; mutable SimpleMutex _m; DBs _dbs; - - // Databases objects and their constituent collections are destroyed and recreated when - // databases are closed and opened. We use this counter to assign a new epoch to a database when - // it is reopened. This permits callers to detect after yielding and reacquiring locks whether - // their catalog pointers are still valid. Collection UUIDs are not sufficient, since they - // remain stable when databases are closed and reopened. - // - // A thread must hold the global exclusive lock to write to this variable, and must hold the - // global lock in at least MODE_IS to read it. - uint64_t _epoch = 0; }; } // namespace mongo diff --git a/src/mongo/db/catalog/database_impl.cpp b/src/mongo/db/catalog/database_impl.cpp index 4258a66dab5..bfc4ff75ca0 100644 --- a/src/mongo/db/catalog/database_impl.cpp +++ b/src/mongo/db/catalog/database_impl.cpp @@ -129,9 +129,8 @@ Status DatabaseImpl::validateDBName(StringData dbname) { return Status::OK(); } -DatabaseImpl::DatabaseImpl(const StringData name, uint64_t epoch) +DatabaseImpl::DatabaseImpl(const StringData name) : _name(name.toString()), - _epoch(epoch), _viewsName(_name + "." + DurableViewCatalog::viewsCollectionName().toString()) { auto durableViewCatalog = std::make_unique<DurableViewCatalogImpl>(this); auto viewCatalog = std::make_unique<ViewCatalog>(std::move(durableViewCatalog)); diff --git a/src/mongo/db/catalog/database_impl.h b/src/mongo/db/catalog/database_impl.h index c9ab3b210f1..3992a645e04 100644 --- a/src/mongo/db/catalog/database_impl.h +++ b/src/mongo/db/catalog/database_impl.h @@ -35,7 +35,7 @@ namespace mongo { class DatabaseImpl final : public Database { public: - explicit DatabaseImpl(StringData name, uint64_t epoch); + explicit DatabaseImpl(StringData name); void init(OperationContext*) const final; @@ -132,10 +132,6 @@ public: return CollectionCatalog::get(opCtx).end(); } - uint64_t epoch() const { - return _epoch; - } - private: /** * Throws if there is a reason 'ns' cannot be created as a user collection. @@ -163,8 +159,6 @@ private: const std::string _name; // "dbname" - const uint64_t _epoch; - const NamespaceString _viewsName; // "dbname.system.views" AtomicWord<int> _profile{0}; // 0=off diff --git a/src/mongo/db/exec/requires_collection_stage.cpp b/src/mongo/db/exec/requires_collection_stage.cpp index 0d120e413cc..59f41a27e53 100644 --- a/src/mongo/db/exec/requires_collection_stage.cpp +++ b/src/mongo/db/exec/requires_collection_stage.cpp @@ -31,8 +31,6 @@ #include "mongo/db/exec/requires_collection_stage.h" -#include "mongo/db/catalog/collection_catalog.h" - namespace mongo { template <typename CollectionT> @@ -72,8 +70,8 @@ void RequiresCollectionStageBase<CollectionT>::doRestoreState() { invariant(_collection); uassert(ErrorCodes::QueryPlanKilled, - str::stream() << "Database epoch changed due to a database-level event.", - getDatabaseEpoch(_collection) == _databaseEpoch); + str::stream() << "The catalog was closed and reopened", + getCatalogEpoch() == _catalogEpoch); doRestoreStateRequiresCollection(); } diff --git a/src/mongo/db/exec/requires_collection_stage.h b/src/mongo/db/exec/requires_collection_stage.h index 3b0520281e1..648cd0aa927 100644 --- a/src/mongo/db/exec/requires_collection_stage.h +++ b/src/mongo/db/exec/requires_collection_stage.h @@ -30,6 +30,7 @@ #pragma once #include "mongo/db/catalog/collection.h" +#include "mongo/db/catalog/collection_catalog.h" #include "mongo/db/catalog/database.h" #include "mongo/db/catalog/database_holder.h" #include "mongo/db/exec/plan_stage.h" @@ -59,7 +60,7 @@ public: : PlanStage(stageType, expCtx), _collection(coll), _collectionUUID(_collection->uuid()), - _databaseEpoch(getDatabaseEpoch(_collection)), + _catalogEpoch(getCatalogEpoch()), _nss(_collection->ns()) { invariant(_collection); } @@ -90,19 +91,14 @@ protected: } private: - // This can only be called when the plan stage is attached to an operation context. The - // collection pointer 'coll' must be non-null and must point to a valid collection. - uint64_t getDatabaseEpoch(CollectionT coll) const { - invariant(coll); - auto databaseHolder = DatabaseHolder::get(opCtx()); - auto db = databaseHolder->getDb(opCtx(), coll->ns().ns()); - invariant(db); - return db->epoch(); + // This can only be called when the plan stage is attached to an operation context. + uint64_t getCatalogEpoch() const { + return CollectionCatalog::get(opCtx()).getEpoch(); } CollectionT _collection; const UUID _collectionUUID; - const uint64_t _databaseEpoch; + const uint64_t _catalogEpoch; // TODO SERVER-31695: The namespace will no longer be needed once queries can survive collection // renames. |