summaryrefslogtreecommitdiff
path: root/src/mongo/db/catalog/collection_catalog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/catalog/collection_catalog.cpp')
-rw-r--r--src/mongo/db/catalog/collection_catalog.cpp405
1 files changed, 193 insertions, 212 deletions
diff --git a/src/mongo/db/catalog/collection_catalog.cpp b/src/mongo/db/catalog/collection_catalog.cpp
index cdaef1c8e55..4e5df27b592 100644
--- a/src/mongo/db/catalog/collection_catalog.cpp
+++ b/src/mongo/db/catalog/collection_catalog.cpp
@@ -52,13 +52,10 @@ const ServiceContext::Decoration<LatestCollectionCatalog> getCatalog =
ServiceContext::declareDecoration<LatestCollectionCatalog>();
std::shared_ptr<CollectionCatalog> batchedCatalogWriteInstance;
-absl::flat_hash_set<Collection*> batchedCatalogClonedCollections;
const OperationContext::Decoration<std::shared_ptr<const CollectionCatalog>> stashedCatalog =
OperationContext::declareDecoration<std::shared_ptr<const CollectionCatalog>>();
-const auto maxUuid = UUID::parse("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF").getValue();
-const auto minUuid = UUID::parse("00000000-0000-0000-0000-000000000000").getValue();
} // namespace
class IgnoreExternalViewChangesForDatabase {
@@ -94,12 +91,12 @@ public:
static void setCollectionInCatalog(CollectionCatalog& catalog,
std::shared_ptr<Collection> collection) {
- catalog._collections = catalog._collections.set(collection->ns(), collection);
- catalog._catalog = catalog._catalog.set(collection->uuid(), collection);
+ catalog._collections[collection->ns()] = collection;
+ catalog._catalog[collection->uuid()] = collection;
// TODO SERVER-64608 Use tenantID from ns
auto dbIdPair = std::make_pair(TenantDatabaseName(boost::none, collection->ns().db()),
collection->uuid());
- catalog._orderedCollections = catalog._orderedCollections.set(dbIdPair, collection);
+ catalog._orderedCollections[dbIdPair] = collection;
}
PublishCatalogUpdates(OperationContext* opCtx,
@@ -133,7 +130,7 @@ public:
case UncommittedCatalogUpdates::Entry::Action::kRenamedCollection: {
writeJobs.push_back(
[& from = entry.nss, &to = entry.renameTo](CollectionCatalog& catalog) {
- catalog._collections = catalog._collections.erase(from);
+ catalog._collections.erase(from);
auto fromStr = from.ns();
auto toStr = to.ns();
@@ -154,9 +151,10 @@ public:
break;
}
case UncommittedCatalogUpdates::Entry::Action::kRecreatedCollection: {
- writeJobs.push_back([opCtx = _opCtx, collection = entry.collection](
- CollectionCatalog& catalog) {
- catalog.registerCollection(opCtx, std::move(collection));
+ writeJobs.push_back([opCtx = _opCtx,
+ collection = entry.collection,
+ uuid = *entry.externalUUID](CollectionCatalog& catalog) {
+ catalog.registerCollection(opCtx, uuid, std::move(collection));
});
// Fallthrough to the createCollection case to finish committing the collection.
}
@@ -223,65 +221,90 @@ private:
UncommittedCatalogUpdates& _uncommittedCatalogUpdates;
};
-CollectionCatalog::iterator::iterator(const TenantDatabaseName& tenantDbName,
- OrderedCollectionMap::iterator it,
- const OrderedCollectionMap& map)
- : _map{map}, _mapIter{it}, _end(_map.upper_bound(std::make_pair(tenantDbName, maxUuid))) {
- _skipUncommitted();
+CollectionCatalog::iterator::iterator(OperationContext* opCtx,
+ const TenantDatabaseName& tenantDbName,
+ const CollectionCatalog& catalog)
+ : _opCtx(opCtx), _tenantDbName(tenantDbName), _catalog(&catalog) {
+ auto minUuid = UUID::parse("00000000-0000-0000-0000-000000000000").getValue();
+
+ _mapIter = _catalog->_orderedCollections.lower_bound(std::make_pair(_tenantDbName, minUuid));
+
+ // Start with the first collection that is visible outside of its transaction.
+ while (!_exhausted() && !_mapIter->second->isCommitted()) {
+ _mapIter++;
+ }
+
+ if (!_exhausted()) {
+ _uuid = _mapIter->first.second;
+ }
}
+CollectionCatalog::iterator::iterator(OperationContext* opCtx,
+ std::map<std::pair<TenantDatabaseName, UUID>,
+ std::shared_ptr<Collection>>::const_iterator mapIter,
+ const CollectionCatalog& catalog)
+ : _opCtx(opCtx), _mapIter(mapIter), _catalog(&catalog) {}
+
CollectionCatalog::iterator::value_type CollectionCatalog::iterator::operator*() {
- if (_mapIter == _map.end()) {
- return nullptr;
+ if (_exhausted()) {
+ return CollectionPtr();
}
- return _mapIter->second.get();
+
+ return {
+ _opCtx, _mapIter->second.get(), LookupCollectionForYieldRestore(_mapIter->second->ns())};
+}
+
+Collection* CollectionCatalog::iterator::getWritableCollection(OperationContext* opCtx) {
+ return CollectionCatalog::get(opCtx)->lookupCollectionByUUIDForMetadataWrite(
+ opCtx, operator*()->uuid());
+}
+
+boost::optional<UUID> CollectionCatalog::iterator::uuid() {
+ return _uuid;
}
CollectionCatalog::iterator CollectionCatalog::iterator::operator++() {
- invariant(_mapIter != _map.end());
- invariant(_mapIter != _end);
_mapIter++;
- _skipUncommitted();
- return *this;
-}
-bool CollectionCatalog::iterator::operator==(const iterator& other) const {
- invariant(_map == other._map);
+ // Skip any collections that are not yet visible outside of their respective transactions.
+ while (!_exhausted() && !_mapIter->second->isCommitted()) {
+ _mapIter++;
+ }
- if (other._mapIter == other._map.end()) {
- return _mapIter == _map.end();
- } else if (_mapIter == _map.end()) {
- return other._mapIter == other._map.end();
+ if (_exhausted()) {
+ // If the iterator is at the end of the map or now points to an entry that does not
+ // correspond to the correct database.
+ _mapIter = _catalog->_orderedCollections.end();
+ _uuid = boost::none;
+ return *this;
}
- return _mapIter->first.second == other._mapIter->first.second;
+ _uuid = _mapIter->first.second;
+ return *this;
}
-bool CollectionCatalog::iterator::operator!=(const iterator& other) const {
- return !(*this == other);
+CollectionCatalog::iterator CollectionCatalog::iterator::operator++(int) {
+ auto oldPosition = *this;
+ ++(*this);
+ return oldPosition;
}
-void CollectionCatalog::iterator::_skipUncommitted() {
- // Advance to the next collection that is visible outside of its transaction.
- while (_mapIter != _end && !_mapIter->second->isCommitted()) {
- ++_mapIter;
+bool CollectionCatalog::iterator::operator==(const iterator& other) const {
+ invariant(_catalog == other._catalog);
+ if (other._mapIter == _catalog->_orderedCollections.end()) {
+ return _uuid == boost::none;
}
-}
-CollectionCatalog::Range::Range(const OrderedCollectionMap& map,
- const TenantDatabaseName& tenantDbName)
- : _map{map}, _tenantDbName{tenantDbName} {}
-
-CollectionCatalog::iterator CollectionCatalog::Range::begin() const {
- return {_tenantDbName, _map.lower_bound(std::make_pair(_tenantDbName, minUuid)), _map};
+ return _uuid == other._uuid;
}
-CollectionCatalog::iterator CollectionCatalog::Range::end() const {
- return {_tenantDbName, _map.upper_bound(std::make_pair(_tenantDbName, maxUuid)), _map};
+bool CollectionCatalog::iterator::operator!=(const iterator& other) const {
+ return !(*this == other);
}
-bool CollectionCatalog::Range::empty() const {
- return begin() == end();
+bool CollectionCatalog::iterator::_exhausted() {
+ return _mapIter == _catalog->_orderedCollections.end() ||
+ _mapIter->first.first != _tenantDbName;
}
std::shared_ptr<const CollectionCatalog> CollectionCatalog::get(ServiceContext* svcCtx) {
@@ -435,13 +458,6 @@ void CollectionCatalog::write(ServiceContext* svcCtx, CatalogWriteFn job) {
void CollectionCatalog::write(OperationContext* opCtx,
std::function<void(CollectionCatalog&)> job) {
- // Calling the writer must be done with the GlobalLock held. Otherwise we risk having the
- // BatchedCollectionCatalogWriter and this caller concurrently modifying the catalog. This is
- // because normal operations calling this will all be serialized, but
- // BatchedCollectionCatalogWriter skips this mechanism as it knows it is the sole user of the
- // server by holding a Global MODE_X lock.
- invariant(opCtx->lockState()->isNoop() || opCtx->lockState()->isLocked());
-
// If global MODE_X lock are held we can re-use a cloned CollectionCatalog instance when
// 'batchedCatalogWriteInstance' is set. Make sure we are the one holding the write lock.
if (batchedCatalogWriteInstance) {
@@ -453,33 +469,25 @@ void CollectionCatalog::write(OperationContext* opCtx,
write(opCtx->getServiceContext(), std::move(job));
}
-Status CollectionCatalog::createView(OperationContext* opCtx,
- const NamespaceString& viewName,
- const NamespaceString& viewOn,
- const BSONArray& pipeline,
- const BSONObj& collation,
- const ViewsForDatabase::PipelineValidatorFn& pipelineValidator,
- const ViewUpsertMode insertViewMode) const {
- // A view document direct write can occur via the oplog application path, which may only hold a
- // lock on the collection being updated (the database views collection).
- invariant(insertViewMode == ViewUpsertMode::kAlreadyDurableView ||
- opCtx->lockState()->isCollectionLockedForMode(viewName, MODE_IX));
+Status CollectionCatalog::createView(
+ OperationContext* opCtx,
+ const NamespaceString& viewName,
+ const NamespaceString& viewOn,
+ const BSONArray& pipeline,
+ const BSONObj& collation,
+ const ViewsForDatabase::PipelineValidatorFn& pipelineValidator) const {
+ invariant(opCtx->lockState()->isCollectionLockedForMode(viewName, MODE_IX));
invariant(opCtx->lockState()->isCollectionLockedForMode(
NamespaceString(viewName.db(), NamespaceString::kSystemDotViewsCollectionName), MODE_X));
- invariant(_viewsForDatabase.find(viewName.db()));
+ invariant(_viewsForDatabase.contains(viewName.db()));
const ViewsForDatabase& viewsForDb = *_getViewsForDatabase(opCtx, viewName.db());
- auto& uncommittedCatalogUpdates = UncommittedCatalogUpdates::get(opCtx);
- if (uncommittedCatalogUpdates.shouldIgnoreExternalViewChanges(viewName.db())) {
- return Status::OK();
- }
-
if (viewName.db() != viewOn.db())
return Status(ErrorCodes::BadValue,
"View must be created on a view or collection in the same database");
- if (viewsForDb.lookup(viewName) || _collections.find(viewName))
+ if (viewsForDb.lookup(viewName) || _collections.contains(viewName))
return Status(ErrorCodes::NamespaceExists, "Namespace already exists");
if (!NamespaceString::validCollectionName(viewOn.coll()))
@@ -500,8 +508,7 @@ Status CollectionCatalog::createView(OperationContext* opCtx,
pipeline,
pipelineValidator,
std::move(collator.getValue()),
- ViewsForDatabase{viewsForDb},
- insertViewMode);
+ ViewsForDatabase{viewsForDb});
}
return result;
@@ -517,7 +524,7 @@ Status CollectionCatalog::modifyView(
invariant(opCtx->lockState()->isCollectionLockedForMode(
NamespaceString(viewName.db(), NamespaceString::kSystemDotViewsCollectionName), MODE_X));
- invariant(_viewsForDatabase.find(viewName.db()));
+ invariant(_viewsForDatabase.contains(viewName.db()));
const ViewsForDatabase& viewsForDb = *_getViewsForDatabase(opCtx, viewName.db());
if (viewName.db() != viewOn.db())
@@ -543,8 +550,7 @@ Status CollectionCatalog::modifyView(
pipeline,
pipelineValidator,
CollatorInterface::cloneCollator(viewPtr->defaultCollator()),
- ViewsForDatabase{viewsForDb},
- ViewUpsertMode::kUpdateView);
+ ViewsForDatabase{viewsForDb});
}
return result;
@@ -555,12 +561,12 @@ Status CollectionCatalog::dropView(OperationContext* opCtx, const NamespaceStrin
invariant(opCtx->lockState()->isCollectionLockedForMode(
NamespaceString(viewName.db(), NamespaceString::kSystemDotViewsCollectionName), MODE_X));
- invariant(_viewsForDatabase.find(viewName.db()));
+ invariant(_viewsForDatabase.contains(viewName.db()));
const ViewsForDatabase& viewsForDb = *_getViewsForDatabase(opCtx, viewName.db());
viewsForDb.requireValidCatalog();
// Make sure the view exists before proceeding.
- if (!viewsForDb.lookup(viewName)) {
+ if (auto viewPtr = viewsForDb.lookup(viewName); !viewPtr) {
return {ErrorCodes::NamespaceNotFound,
str::stream() << "cannot drop missing view: " << viewName.ns()};
}
@@ -604,10 +610,9 @@ Status CollectionCatalog::reloadViews(OperationContext* opCtx, StringData dbName
// Create a copy of the ViewsForDatabase instance to modify it. Reset the views for this
// database, but preserve the DurableViewCatalog pointer.
- const ViewsForDatabase* viewsForDbPtr = _viewsForDatabase.find(dbName);
- invariant(viewsForDbPtr);
- ViewsForDatabase viewsForDb = *viewsForDbPtr;
-
+ auto it = _viewsForDatabase.find(dbName);
+ invariant(it != _viewsForDatabase.end());
+ ViewsForDatabase viewsForDb{it->second.durable};
viewsForDb.valid = false;
viewsForDb.viewGraphNeedsRefresh = true;
viewsForDb.viewMap.clear();
@@ -672,29 +677,28 @@ void CollectionCatalog::onOpenDatabase(OperationContext* opCtx,
invariant(opCtx->lockState()->isDbLockedForMode(dbName, MODE_IS));
uassert(ErrorCodes::AlreadyInitialized,
str::stream() << "Database " << dbName << " is already initialized",
- !_viewsForDatabase.find(dbName));
+ _viewsForDatabase.find(dbName) == _viewsForDatabase.end());
- _viewsForDatabase = _viewsForDatabase.set(dbName.toString(), std::move(viewsForDb));
+ _viewsForDatabase[dbName] = std::move(viewsForDb);
}
void CollectionCatalog::onCloseDatabase(OperationContext* opCtx, TenantDatabaseName tenantDbName) {
invariant(opCtx->lockState()->isDbLockedForMode(tenantDbName.dbName(), MODE_X));
auto rid = ResourceId(RESOURCE_DATABASE, tenantDbName.dbName());
removeResource(rid, tenantDbName.dbName());
- _viewsForDatabase = _viewsForDatabase.erase(tenantDbName.dbName());
+ _viewsForDatabase.erase(tenantDbName.dbName());
}
-void CollectionCatalog::onCloseCatalog() {
- if (_shadowCatalog) {
- return;
- }
-
+void CollectionCatalog::onCloseCatalog(OperationContext* opCtx) {
+ invariant(opCtx->lockState()->isW());
+ invariant(!_shadowCatalog);
_shadowCatalog.emplace();
for (auto& entry : _catalog)
- _shadowCatalog = _shadowCatalog->insert({entry.first, entry.second->ns()});
+ _shadowCatalog->insert({entry.first, entry.second->ns()});
}
-void CollectionCatalog::onOpenCatalog() {
+void CollectionCatalog::onOpenCatalog(OperationContext* opCtx) {
+ invariant(opCtx->lockState()->isW());
invariant(_shadowCatalog);
_shadowCatalog.reset();
++_epoch;
@@ -704,10 +708,6 @@ uint64_t CollectionCatalog::getEpoch() const {
return _epoch;
}
-CollectionCatalog::Range CollectionCatalog::range(const TenantDatabaseName& tenantDbName) const {
- return {_orderedCollections, tenantDbName};
-}
-
std::shared_ptr<const Collection> CollectionCatalog::lookupCollectionByUUIDForRead(
OperationContext* opCtx, const UUID& uuid) const {
auto [found, uncommittedColl, newColl] =
@@ -761,7 +761,6 @@ Collection* CollectionCatalog::lookupCollectionByUUIDForMetadataWrite(OperationC
// on the thread doing the batch write and it would trigger the regular path where we do a
// copy-on-write on the catalog when committing.
if (_isCatalogBatchWriter()) {
- batchedCatalogClonedCollections.emplace(cloned.get());
PublishCatalogUpdates::setCollectionInCatalog(*batchedCatalogWriteInstance,
std::move(cloned));
return ptr;
@@ -795,8 +794,8 @@ bool CollectionCatalog::isCollectionAwaitingVisibility(UUID uuid) const {
}
std::shared_ptr<Collection> CollectionCatalog::_lookupCollectionByUUID(UUID uuid) const {
- const std::shared_ptr<Collection>* coll = _catalog.find(uuid);
- return coll ? *coll : nullptr;
+ auto foundIt = _catalog.find(uuid);
+ return foundIt == _catalog.end() ? nullptr : foundIt->second;
}
std::shared_ptr<const Collection> CollectionCatalog::lookupCollectionByNamespaceForRead(
@@ -813,8 +812,8 @@ std::shared_ptr<const Collection> CollectionCatalog::lookupCollectionByNamespace
return nullptr;
}
- const std::shared_ptr<Collection>* collPtr = _collections.find(nss);
- auto coll = collPtr ? *collPtr : nullptr;
+ auto it = _collections.find(nss);
+ auto coll = (it == _collections.end() ? nullptr : it->second);
return (coll && coll->isCommitted()) ? coll : nullptr;
}
@@ -844,8 +843,8 @@ Collection* CollectionCatalog::lookupCollectionByNamespaceForMetadataWrite(
return nullptr;
}
- const std::shared_ptr<Collection>* collPtr = _collections.find(nss);
- auto coll = collPtr ? *collPtr : nullptr;
+ auto it = _collections.find(nss);
+ auto coll = (it == _collections.end() ? nullptr : it->second);
if (!coll || !coll->isCommitted())
return nullptr;
@@ -865,7 +864,6 @@ Collection* CollectionCatalog::lookupCollectionByNamespaceForMetadataWrite(
// on the thread doing the batch write and it would trigger the regular path where we do a
// copy-on-write on the catalog when committing.
if (_isCatalogBatchWriter()) {
- batchedCatalogClonedCollections.emplace(cloned.get());
PublishCatalogUpdates::setCollectionInCatalog(*batchedCatalogWriteInstance,
std::move(cloned));
return ptr;
@@ -892,8 +890,8 @@ CollectionPtr CollectionCatalog::lookupCollectionByNamespace(OperationContext* o
return nullptr;
}
- const std::shared_ptr<Collection>* collPtr = _collections.find(nss);
- auto coll = collPtr ? *collPtr : nullptr;
+ auto it = _collections.find(nss);
+ auto coll = (it == _collections.end() ? nullptr : it->second);
return (coll && coll->isCommitted())
? CollectionPtr(opCtx, coll.get(), LookupCollectionForYieldRestore(coll->ns()))
: nullptr;
@@ -911,21 +909,20 @@ boost::optional<NamespaceString> CollectionCatalog::lookupNSSByUUID(OperationCon
return boost::none;
}
- const std::shared_ptr<Collection>* collPtr = _catalog.find(uuid);
- if (collPtr) {
- auto coll = *collPtr;
- boost::optional<NamespaceString> ns = coll->ns();
- invariant(!ns.value().isEmpty());
- return coll->isCommitted() ? ns : boost::none;
+ auto foundIt = _catalog.find(uuid);
+ if (foundIt != _catalog.end()) {
+ boost::optional<NamespaceString> ns = foundIt->second->ns();
+ invariant(!ns.get().isEmpty());
+ return _collections.find(ns.get())->second->isCommitted() ? ns : boost::none;
}
// Only in the case that the catalog is closed and a UUID is currently unknown, resolve it
// using the pre-close state. This ensures that any tasks reloading the catalog can see their
// own updates.
if (_shadowCatalog) {
- auto* shadowIt = _shadowCatalog->find(uuid);
- if (shadowIt)
- return *shadowIt;
+ auto shadowIt = _shadowCatalog->find(uuid);
+ if (shadowIt != _shadowCatalog->end())
+ return shadowIt->second;
}
return boost::none;
}
@@ -941,11 +938,10 @@ boost::optional<UUID> CollectionCatalog::lookupUUIDByNSS(OperationContext* opCtx
return boost::none;
}
- const std::shared_ptr<Collection>* collPtr = _collections.find(nss);
- if (collPtr) {
- auto coll = *collPtr;
- const boost::optional<UUID>& uuid = coll->uuid();
- return coll->isCommitted() ? uuid : boost::none;
+ auto it = _collections.find(nss);
+ if (it != _collections.end()) {
+ const boost::optional<UUID>& uuid = it->second->uuid();
+ return it->second->isCommitted() ? uuid : boost::none;
}
return boost::none;
}
@@ -1090,34 +1086,23 @@ std::vector<TenantDatabaseName> CollectionCatalog::getAllDbNames() const {
return ret;
}
-void CollectionCatalog::setAllDatabaseProfileFilters(std::shared_ptr<ProfileFilter> filter) {
- auto dbProfileSettingsWriter = _databaseProfileSettings.transient();
- for (const auto& [dbName, settings] : _databaseProfileSettings) {
- ProfileSettings clone = settings;
- clone.filter = filter;
- dbProfileSettingsWriter.set(dbName, std::move(clone));
- }
- _databaseProfileSettings = dbProfileSettingsWriter.persistent();
-}
-
void CollectionCatalog::setDatabaseProfileSettings(
StringData dbName, CollectionCatalog::ProfileSettings newProfileSettings) {
- _databaseProfileSettings =
- _databaseProfileSettings.set(dbName.toString(), std::move(newProfileSettings));
+ _databaseProfileSettings[dbName] = newProfileSettings;
}
CollectionCatalog::ProfileSettings CollectionCatalog::getDatabaseProfileSettings(
StringData dbName) const {
- const ProfileSettings* settings = _databaseProfileSettings.find(dbName);
- if (settings) {
- return *settings;
+ auto it = _databaseProfileSettings.find(dbName);
+ if (it != _databaseProfileSettings.end()) {
+ return it->second;
}
return {serverGlobalParams.defaultProfile, ProfileFilter::getDefault()};
}
void CollectionCatalog::clearDatabaseProfileSettings(StringData dbName) {
- _databaseProfileSettings = _databaseProfileSettings.erase(dbName.toString());
+ _databaseProfileSettings.erase(dbName);
}
CollectionCatalog::Stats CollectionCatalog::getStats() const {
@@ -1145,9 +1130,9 @@ CollectionCatalog::ViewCatalogSet CollectionCatalog::getViewCatalogDbNames(
}
void CollectionCatalog::registerCollection(OperationContext* opCtx,
+ const UUID& uuid,
std::shared_ptr<Collection> coll) {
auto nss = coll->ns();
- auto uuid = coll->uuid();
// TODO SERVER-64608 Use tenantId from nss
auto tenantDbName = TenantDatabaseName(boost::none, nss.db());
_ensureNamespaceDoesNotExist(opCtx, nss, NamespaceType::kAll);
@@ -1162,12 +1147,12 @@ void CollectionCatalog::registerCollection(OperationContext* opCtx,
auto dbIdPair = std::make_pair(tenantDbName, uuid);
// Make sure no entry related to this uuid.
- invariant(!_catalog.find(uuid));
+ invariant(_catalog.find(uuid) == _catalog.end());
invariant(_orderedCollections.find(dbIdPair) == _orderedCollections.end());
- _catalog = _catalog.set(uuid, coll);
- _collections = _collections.set(nss, coll);
- _orderedCollections = _orderedCollections.set(dbIdPair, coll);
+ _catalog[uuid] = coll;
+ _collections[nss] = coll;
+ _orderedCollections[dbIdPair] = coll;
if (!nss.isOnInternalDb() && !nss.isSystem()) {
_stats.userCollections += 1;
@@ -1193,7 +1178,7 @@ void CollectionCatalog::registerCollection(OperationContext* opCtx,
std::shared_ptr<Collection> CollectionCatalog::deregisterCollection(OperationContext* opCtx,
const UUID& uuid) {
- invariant(_catalog.find(uuid));
+ invariant(_catalog.find(uuid) != _catalog.end());
auto coll = std::move(_catalog[uuid]);
auto ns = coll->ns();
@@ -1204,12 +1189,12 @@ std::shared_ptr<Collection> CollectionCatalog::deregisterCollection(OperationCon
LOGV2_DEBUG(20281, 1, "Deregistering collection", logAttrs(ns), "uuid"_attr = uuid);
// Make sure collection object exists.
- invariant(_collections.find(ns));
+ invariant(_collections.find(ns) != _collections.end());
invariant(_orderedCollections.find(dbIdPair) != _orderedCollections.end());
- _orderedCollections = _orderedCollections.erase(dbIdPair);
- _collections = _collections.erase(ns);
- _catalog = _catalog.erase(uuid);
+ _orderedCollections.erase(dbIdPair);
+ _collections.erase(ns);
+ _catalog.erase(uuid);
if (!ns.isOnInternalDb() && !ns.isSystem()) {
_stats.userCollections -= 1;
@@ -1242,18 +1227,18 @@ void CollectionCatalog::registerUncommittedView(OperationContext* opCtx,
// namespaces here.
_ensureNamespaceDoesNotExist(opCtx, nss, NamespaceType::kCollection);
- _uncommittedViews = _uncommittedViews.insert(nss);
+ _uncommittedViews.emplace(nss);
}
void CollectionCatalog::deregisterUncommittedView(const NamespaceString& nss) {
- _uncommittedViews = _uncommittedViews.erase(nss);
+ _uncommittedViews.erase(nss);
}
void CollectionCatalog::_ensureNamespaceDoesNotExist(OperationContext* opCtx,
const NamespaceString& nss,
NamespaceType type) const {
auto existingCollection = _collections.find(nss);
- if (existingCollection) {
+ if (existingCollection != _collections.end()) {
LOGV2(5725001,
"Conflicted registering namespace, already have a collection with the same namespace",
"nss"_attr = nss);
@@ -1261,7 +1246,7 @@ void CollectionCatalog::_ensureNamespaceDoesNotExist(OperationContext* opCtx,
}
if (type == NamespaceType::kAll) {
- if (_uncommittedViews.find(nss)) {
+ if (_uncommittedViews.contains(nss)) {
LOGV2(5725002,
"Conflicted registering namespace, already have a view with the same namespace",
"nss"_attr = nss);
@@ -1289,25 +1274,26 @@ void CollectionCatalog::deregisterAllCollectionsAndViews() {
auto ns = entry.second->ns();
LOGV2_DEBUG(20283, 1, "Deregistering collection", logAttrs(ns), "uuid"_attr = uuid);
+
+ entry.second.reset();
}
- _collections = {};
- _orderedCollections = {};
- _catalog = {};
- _viewsForDatabase = {};
+ _collections.clear();
+ _orderedCollections.clear();
+ _catalog.clear();
+ _viewsForDatabase.clear();
_stats = {};
- _resourceInformation = {};
+ _resourceInformation.clear();
}
void CollectionCatalog::clearViews(OperationContext* opCtx, StringData dbName) const {
invariant(opCtx->lockState()->isCollectionLockedForMode(
NamespaceString(dbName, NamespaceString::kSystemDotViewsCollectionName), MODE_X));
- const ViewsForDatabase* viewsForDbPtr = _viewsForDatabase.find(dbName);
- invariant(viewsForDbPtr);
-
- ViewsForDatabase viewsForDb = *viewsForDbPtr;
+ auto it = _viewsForDatabase.find(dbName);
+ invariant(it != _viewsForDatabase.end());
+ ViewsForDatabase viewsForDb = it->second;
viewsForDb.viewMap.clear();
viewsForDb.viewGraph.clear();
@@ -1318,6 +1304,16 @@ void CollectionCatalog::clearViews(OperationContext* opCtx, StringData dbName) c
catalog._replaceViewsForDatabase(dbName, std::move(viewsForDb));
});
}
+
+CollectionCatalog::iterator CollectionCatalog::begin(OperationContext* opCtx,
+ const TenantDatabaseName& tenantDbName) const {
+ return iterator(opCtx, tenantDbName, *this);
+}
+
+CollectionCatalog::iterator CollectionCatalog::end(OperationContext* opCtx) const {
+ return iterator(opCtx, _orderedCollections.end(), *this);
+}
+
boost::optional<std::string> CollectionCatalog::lookupResourceName(const ResourceId& rid) const {
invariant(rid.getType() == RESOURCE_DATABASE || rid.getType() == RESOURCE_COLLECTION);
@@ -1325,6 +1321,7 @@ boost::optional<std::string> CollectionCatalog::lookupResourceName(const Resourc
if (search == _resourceInformation.end()) {
return boost::none;
}
+
const std::set<std::string>& namespaces = search->second;
// When there are multiple namespaces mapped to the same ResourceId, return boost::none as the
@@ -1344,14 +1341,12 @@ void CollectionCatalog::removeResource(const ResourceId& rid, const std::string&
return;
}
- std::set<std::string> namespaces = search->second;
+ std::set<std::string>& namespaces = search->second;
namespaces.erase(entry);
// Remove the map entry if this is the last namespace in the set for the ResourceId.
if (namespaces.size() == 0) {
- _resourceInformation = _resourceInformation.erase(search, rid);
- } else {
- _resourceInformation = _resourceInformation.set(rid, std::move(namespaces));
+ _resourceInformation.erase(search);
}
}
@@ -1361,17 +1356,16 @@ void CollectionCatalog::addResource(const ResourceId& rid, const std::string& en
auto search = _resourceInformation.find(rid);
if (search == _resourceInformation.end()) {
std::set<std::string> newSet = {entry};
- _resourceInformation = _resourceInformation.set(rid, std::move(newSet));
+ _resourceInformation.insert(std::make_pair(rid, newSet));
return;
}
- if (const auto& namespaces = search->second; namespaces.count(entry) > 0) {
+ std::set<std::string>& namespaces = search->second;
+ if (namespaces.count(entry) > 0) {
return;
}
- std::set<std::string> namespaces = search->second;
namespaces.insert(entry);
- _resourceInformation = _resourceInformation.set(rid, std::move(namespaces));
}
void CollectionCatalog::invariantHasExclusiveAccessToCollection(OperationContext* opCtx,
@@ -1391,15 +1385,15 @@ boost::optional<const ViewsForDatabase&> CollectionCatalog::_getViewsForDatabase
return uncommittedViews;
}
- const ViewsForDatabase* viewsForDb = _viewsForDatabase.find(dbName);
- if (!viewsForDb) {
+ auto it = _viewsForDatabase.find(dbName);
+ if (it == _viewsForDatabase.end()) {
return boost::none;
}
- return *viewsForDb;
+ return it->second;
}
void CollectionCatalog::_replaceViewsForDatabase(StringData dbName, ViewsForDatabase&& views) {
- _viewsForDatabase = _viewsForDatabase.set(dbName.toString(), std::move(views));
+ _viewsForDatabase[dbName] = std::move(views);
}
Status CollectionCatalog::_createOrUpdateView(
@@ -1409,19 +1403,15 @@ Status CollectionCatalog::_createOrUpdateView(
const BSONArray& pipeline,
const ViewsForDatabase::PipelineValidatorFn& pipelineValidator,
std::unique_ptr<CollatorInterface> collator,
- ViewsForDatabase&& viewsForDb,
- ViewUpsertMode insertViewMode) const {
- // A view document direct write can occur via the oplog application path, which may only hold a
- // lock on the collection being updated (the database views collection).
- invariant(insertViewMode == ViewUpsertMode::kAlreadyDurableView ||
- opCtx->lockState()->isCollectionLockedForMode(viewName, MODE_IX));
+ ViewsForDatabase&& viewsForDb) const {
+ invariant(opCtx->lockState()->isCollectionLockedForMode(viewName, MODE_IX));
invariant(opCtx->lockState()->isCollectionLockedForMode(
NamespaceString(viewName.db(), NamespaceString::kSystemDotViewsCollectionName), MODE_X));
viewsForDb.requireValidCatalog();
- // Build the BSON definition for this view to be saved in the durable view catalog and/or to
- // insert in the viewMap. If the collation is empty, omit it from the definition altogether.
+ // Build the BSON definition for this view to be saved in the durable view catalog. If the
+ // collation is empty, omit it from the definition altogether.
BSONObjBuilder viewDefBuilder;
viewDefBuilder.append("_id", viewName.ns());
viewDefBuilder.append("viewOn", viewOn.coll());
@@ -1430,42 +1420,25 @@ Status CollectionCatalog::_createOrUpdateView(
viewDefBuilder.append("collation", collator->getSpec().toBSON());
}
- BSONObj viewDef = viewDefBuilder.obj();
BSONObj ownedPipeline = pipeline.getOwned();
- ViewDefinition view(
+ auto view = std::make_shared<ViewDefinition>(
viewName.db(), viewName.coll(), viewOn.coll(), ownedPipeline, std::move(collator));
- // If the view is already in the durable view catalog, we don't need to validate the graph. If
- // we need to update the durable view catalog, we need to check that the resulting dependency
- // graph is acyclic and within the maximum depth.
- const bool viewGraphNeedsValidation = insertViewMode != ViewUpsertMode::kAlreadyDurableView;
- Status graphStatus =
- viewsForDb.upsertIntoGraph(opCtx, view, pipelineValidator, viewGraphNeedsValidation);
+ // Check that the resulting dependency graph is acyclic and within the maximum depth.
+ Status graphStatus = viewsForDb.upsertIntoGraph(opCtx, *(view.get()), pipelineValidator);
if (!graphStatus.isOK()) {
return graphStatus;
}
- if (insertViewMode != ViewUpsertMode::kAlreadyDurableView) {
- viewsForDb.durable->upsert(opCtx, viewName, viewDef);
- }
+ viewsForDb.durable->upsert(opCtx, viewName, viewDefBuilder.obj());
+ viewsForDb.viewMap.clear();
viewsForDb.valid = false;
- auto res = [&] {
- switch (insertViewMode) {
- case ViewUpsertMode::kCreateView:
- case ViewUpsertMode::kAlreadyDurableView:
- return viewsForDb.insert(opCtx, viewDef);
- case ViewUpsertMode::kUpdateView:
- viewsForDb.viewMap.clear();
- viewsForDb.viewGraphNeedsRefresh = true;
- viewsForDb.stats = {};
-
- // Reload the view catalog with the changes applied.
- return viewsForDb.reload(opCtx);
- }
- MONGO_UNREACHABLE;
- }();
+ viewsForDb.viewGraphNeedsRefresh = true;
+ viewsForDb.stats = {};
+ // Reload the view catalog with the changes applied.
+ auto res = viewsForDb.reload(opCtx);
if (res.isOK()) {
auto& uncommittedCatalogUpdates = UncommittedCatalogUpdates::get(opCtx);
uncommittedCatalogUpdates.addView(opCtx, viewName);
@@ -1484,9 +1457,16 @@ bool CollectionCatalog::_isCatalogBatchWriter() const {
bool CollectionCatalog::_alreadyClonedForBatchedWriter(
const std::shared_ptr<Collection>& collection) const {
- // We may skip cloning the Collection instance if and only if have already cloned it for write
- // use in this batch writer.
- return _isCatalogBatchWriter() && batchedCatalogClonedCollections.contains(collection.get());
+ // We may skip cloning the Collection instance if and only if we are currently in a batched
+ // catalog write and all references to this Collection is owned by the cloned CollectionCatalog
+ // instance owned by the batch writer. i.e. the Collection is uniquely owned by the batch
+ // writer. When the batch writer initially clones the catalog, all collections will have a
+ // 'use_count' of at least kNumCollectionReferencesStored*2 (because there are at least 2
+ // catalog instances). To check for uniquely owned we need to check that the reference count is
+ // exactly kNumCollectionReferencesStored (owned by a single catalog) while also account for the
+ // instance that is extracted from the catalog and provided as a parameter to this function, we
+ // therefore need to add 1.
+ return _isCatalogBatchWriter() && collection.use_count() == kNumCollectionReferencesStored + 1;
}
CollectionCatalogStasher::CollectionCatalogStasher(OperationContext* opCtx)
@@ -1547,7 +1527,10 @@ const Collection* LookupCollectionForYieldRestore::operator()(OperationContext*
// state. After a query yields its locks, the replication state may have changed, invalidating
// our current choice of ReadSource. Using the same preconditions, change our ReadSource if
// necessary.
- SnapshotHelper::changeReadSourceIfNeeded(opCtx, collection->ns());
+ auto [newReadSource, _] = SnapshotHelper::shouldChangeReadSource(opCtx, collection->ns());
+ if (newReadSource) {
+ opCtx->recoveryUnit()->setTimestampReadSource(*newReadSource);
+ }
return collection.get();
}
@@ -1556,7 +1539,6 @@ BatchedCollectionCatalogWriter::BatchedCollectionCatalogWriter(OperationContext*
: _opCtx(opCtx) {
invariant(_opCtx->lockState()->isW());
invariant(!batchedCatalogWriteInstance);
- invariant(batchedCatalogClonedCollections.empty());
auto& storage = getCatalog(_opCtx->getServiceContext());
// hold onto base so if we need to delete it we can do it outside of the lock
@@ -1579,7 +1561,6 @@ BatchedCollectionCatalogWriter::~BatchedCollectionCatalogWriter() {
// Clear out batched pointer so no more attempts of batching are made
_batchedInstance = nullptr;
batchedCatalogWriteInstance = nullptr;
- batchedCatalogClonedCollections.clear();
}
} // namespace mongo