diff options
| author | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
|---|---|---|
| committer | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
| commit | 4cb8841196d0625dfa3825aa326f071cd27c7b8b (patch) | |
| tree | 1682a647d4463397c119183369ae6f750d5fdcff /src/mongo/s/catalog_cache.cpp | |
| parent | aa03c6362cbaa767638e6eed9b031d86dd2643d1 (diff) | |
| parent | 8f0827553e09872941945a093b647a4211a9db7f (diff) | |
Update upstream source from tag 'upstream/6.0.0'master
Update to upstream version '6.0.0'
with Debian dir 5604a80ec1c96ca76f25f40d78e6ef855abec322
Diffstat (limited to 'src/mongo/s/catalog_cache.cpp')
| -rw-r--r-- | src/mongo/s/catalog_cache.cpp | 210 |
1 files changed, 107 insertions, 103 deletions
diff --git a/src/mongo/s/catalog_cache.cpp b/src/mongo/s/catalog_cache.cpp index fff547935bc..60314d67ef3 100644 --- a/src/mongo/s/catalog_cache.cpp +++ b/src/mongo/s/catalog_cache.cpp @@ -37,8 +37,6 @@ #include "mongo/s/catalog_cache.h" -#include <fmt/format.h> - #include "mongo/bson/bsonobjbuilder.h" #include "mongo/db/query/collation/collator_factory_interface.h" #include "mongo/db/repl/optime_with.h" @@ -59,7 +57,6 @@ namespace mongo { namespace { MONGO_FAIL_POINT_DEFINE(blockCollectionCacheLookup); -MONGO_FAIL_POINT_DEFINE(blockDatabaseCacheLookup); // How many times to try refreshing the routing info if the set of chunks loaded from the config // server is found to be inconsistent. @@ -71,6 +68,9 @@ const int kCollectionCacheSize = 10000; const OperationContext::Decoration<bool> operationShouldBlockBehindCatalogCacheRefresh = OperationContext::declareDecoration<bool>(); +const OperationContext::Decoration<bool> operationBlockedBehindCatalogCacheRefresh = + OperationContext::declareDecoration<bool>(); + std::shared_ptr<RoutingTableHistory> createUpdatedRoutingTableHistory( OperationContext* opCtx, const NamespaceString& nss, @@ -81,31 +81,28 @@ std::shared_ptr<RoutingTableHistory> createUpdatedRoutingTableHistory( if (isIncremental && collectionAndChunks.changedChunks.size() == 1 && collectionAndChunks.changedChunks[0].getVersion() == existingHistory->optRt->getVersion()) { - tassert(7032310, - fmt::format("allowMigrations field of collection '{}' changed without changing the " - "collection version {}. Old value: {}, new value: {}", - nss.toString(), - existingHistory->optRt->getVersion().toString(), - existingHistory->optRt->allowMigrations(), - collectionAndChunks.allowMigrations), - collectionAndChunks.allowMigrations == existingHistory->optRt->allowMigrations()); + invariant(collectionAndChunks.allowMigrations == existingHistory->optRt->allowMigrations(), + str::stream() << "allowMigrations field of " << nss + << " collection changed without changing the collection version " + << existingHistory->optRt->getVersion().toString() + << ". Old value: " << existingHistory->optRt->allowMigrations() + << ", new value: " << collectionAndChunks.allowMigrations); const auto& oldReshardingFields = existingHistory->optRt->getReshardingFields(); const auto& newReshardingFields = collectionAndChunks.reshardingFields; - tassert(7032311, - fmt::format("reshardingFields field of collection '{}' changed without changing " - "the collection version {}. Old value: {}, new value: {}", - nss.toString(), - existingHistory->optRt->getVersion().toString(), - oldReshardingFields->toBSON().toString(), - newReshardingFields->toBSON().toString()), - [&] { - if (oldReshardingFields && newReshardingFields) - return oldReshardingFields->toBSON().woCompare( - newReshardingFields->toBSON()) == 0; - else - return !oldReshardingFields && !newReshardingFields; - }()); + invariant( + [&] { + if (oldReshardingFields && newReshardingFields) + return oldReshardingFields->toBSON().woCompare(newReshardingFields->toBSON()) == + 0; + else + return !oldReshardingFields && !newReshardingFields; + }(), + str::stream() << "reshardingFields field of " << nss + << " collection changed without changing the collection version " + << existingHistory->optRt->getVersion().toString() + << ". Old value: " << oldReshardingFields->toBSON() + << ", new value: " << newReshardingFields->toBSON()); return existingHistory->optRt; } @@ -117,11 +114,7 @@ std::shared_ptr<RoutingTableHistory> createUpdatedRoutingTableHistory( return 0; } if (collectionAndChunks.maxChunkSizeBytes) { - tassert(7032312, - fmt::format("Invalid maxChunkSizeBytes value {} for collection '{}'", - nss.toString(), - collectionAndChunks.maxChunkSizeBytes.get()), - collectionAndChunks.maxChunkSizeBytes.get() > 0); + invariant(collectionAndChunks.maxChunkSizeBytes.get() > 0); return uint64_t(*collectionAndChunks.maxChunkSizeBytes); } return boost::none; @@ -249,51 +242,26 @@ CatalogCache::CatalogCache(ServiceContext* const service, CatalogCacheLoader& ca } CatalogCache::~CatalogCache() { - // The executor is used by all the caches that correspond to the router role, so it must be - // joined before these caches are destroyed, per the contract of ReadThroughCache. - shutDownAndJoin(); -} - -void CatalogCache::shutDownAndJoin() { + // The executor is used by the Database and Collection caches, + // so it must be joined, before these caches are destroyed, + // per the contract of ReadThroughCache. _executor->shutdown(); _executor->join(); } StatusWith<CachedDatabaseInfo> CatalogCache::getDatabase(OperationContext* opCtx, - StringData dbName) { - return _getDatabase(opCtx, dbName); -} - -StatusWith<CachedDatabaseInfo> CatalogCache::_getDatabase(OperationContext* opCtx, - StringData dbName, - bool allowLocks) { - tassert(7032313, + StringData dbName, + bool allowLocks) { + if (!allowLocks) { + invariant( + !opCtx->lockState() || !opCtx->lockState()->isLocked(), "Do not hold a lock while refreshing the catalog cache. Doing so would potentially " "hold the lock during a network call, and can lead to a deadlock as described in " - "SERVER-37398.", - allowLocks || !opCtx->lockState() || !opCtx->lockState()->isLocked()); + "SERVER-37398."); + } try { - auto dbEntryFuture = - _databaseCache.acquireAsync(dbName, CacheCausalConsistency::kLatestKnown); - - if (allowLocks) { - // When allowLocks is true we may be holding a lock, so we don't want to block the - // current thread: if the future is ready let's use it, otherwise return an error. - if (dbEntryFuture.isReady()) { - return dbEntryFuture.get(opCtx); - } else { - // This error only contains the database name and must be handled by any callers of - // _getDatabase with the potential for allowLocks to be true. The caller should - // convert this to ErrorCodes::ShardCannotRefreshDueToLocksHeld with the full - // namespace. - return Status{ShardCannotRefreshDueToLocksHeldInfo(NamespaceString(dbName)), - "Database info refresh did not complete"}; - } - } - - // From this point we can guarantee that allowLocks is false. - auto dbEntry = dbEntryFuture.get(opCtx); + auto dbEntry = _databaseCache.acquire(opCtx, dbName, CacheCausalConsistency::kLatestKnown); uassert(ErrorCodes::NamespaceNotFound, str::stream() << "database " << dbName << " not found", dbEntry); @@ -309,28 +277,18 @@ StatusWith<ChunkManager> CatalogCache::_getCollectionRoutingInfoAt( const NamespaceString& nss, boost::optional<Timestamp> atClusterTime, bool allowLocks) { - tassert(7032314, - "Do not hold a lock while refreshing the catalog cache. Doing so would potentially " - "hold the lock during a network call, and can lead to a deadlock as described in " - "SERVER-37398.", - allowLocks || !opCtx->lockState() || !opCtx->lockState()->isLocked()); + if (!allowLocks) { + invariant(!opCtx->lockState() || !opCtx->lockState()->isLocked(), + "Do not hold a lock while refreshing the catalog cache. Doing so would " + "potentially hold " + "the lock during a network call, and can lead to a deadlock as described in " + "SERVER-37398."); + } try { - const auto swDbInfo = _getDatabase(opCtx, nss.db(), allowLocks); + const auto swDbInfo = getDatabase(opCtx, nss.db(), allowLocks); if (!swDbInfo.isOK()) { - if (swDbInfo == ErrorCodes::ShardCannotRefreshDueToLocksHeld) { - // Since collection refreshes always imply database refreshes, it is ok to transform - // this error into a collection error rather than a database error. - auto dbRefreshInfo = - swDbInfo.getStatus().extraInfo<ShardCannotRefreshDueToLocksHeldInfo>(); - LOGV2_DEBUG(7850500, - 2, - "Adding collection name to ShardCannotRefreshDueToLocksHeld error", - "dbName"_attr = dbRefreshInfo->getNss().db(), - "nss"_attr = nss); - return Status{ShardCannotRefreshDueToLocksHeldInfo(nss), - "Routing info refresh did not complete"}; - } else if (swDbInfo == ErrorCodes::NamespaceNotFound) { + if (swDbInfo == ErrorCodes::NamespaceNotFound) { LOGV2_FOR_CATALOG_REFRESH( 4947103, 2, @@ -368,6 +326,9 @@ StatusWith<ChunkManager> CatalogCache::_getCollectionRoutingInfoAt( } // From this point we can guarantee that allowLocks is false + + operationBlockedBehindCatalogCacheRefresh(opCtx) = true; + size_t acquireTries = 0; Timer t; @@ -564,6 +525,37 @@ void CatalogCache::report(BSONObjBuilder* builder) const { _collectionCache.reportStats(&cacheStatsBuilder); } +void CatalogCache::checkAndRecordOperationBlockedByRefresh(OperationContext* opCtx, + mongo::LogicalOp opType) { + if (!isMongos() || !operationBlockedBehindCatalogCacheRefresh(opCtx)) { + return; + } + + auto& opsBlockedByRefresh = _stats.operationsBlockedByRefresh; + + opsBlockedByRefresh.countAllOperations.fetchAndAddRelaxed(1); + + switch (opType) { + case LogicalOp::opInsert: + opsBlockedByRefresh.countInserts.fetchAndAddRelaxed(1); + break; + case LogicalOp::opQuery: + opsBlockedByRefresh.countQueries.fetchAndAddRelaxed(1); + break; + case LogicalOp::opUpdate: + opsBlockedByRefresh.countUpdates.fetchAndAddRelaxed(1); + break; + case LogicalOp::opDelete: + opsBlockedByRefresh.countDeletes.fetchAndAddRelaxed(1); + break; + case LogicalOp::opCommand: + opsBlockedByRefresh.countCommands.fetchAndAddRelaxed(1); + break; + default: + MONGO_UNREACHABLE; + } +} + void CatalogCache::invalidateDatabaseEntry_LINEARIZABLE(const StringData& dbName) { _databaseCache.invalidateKey(dbName); } @@ -576,6 +568,26 @@ void CatalogCache::Stats::report(BSONObjBuilder* builder) const { builder->append("countStaleConfigErrors", countStaleConfigErrors.load()); builder->append("totalRefreshWaitTimeMicros", totalRefreshWaitTimeMicros.load()); + + if (isMongos()) { + BSONObjBuilder operationsBlockedByRefreshBuilder( + builder->subobjStart("operationsBlockedByRefresh")); + + operationsBlockedByRefreshBuilder.append( + "countAllOperations", operationsBlockedByRefresh.countAllOperations.load()); + operationsBlockedByRefreshBuilder.append("countInserts", + operationsBlockedByRefresh.countInserts.load()); + operationsBlockedByRefreshBuilder.append("countQueries", + operationsBlockedByRefresh.countQueries.load()); + operationsBlockedByRefreshBuilder.append("countUpdates", + operationsBlockedByRefresh.countUpdates.load()); + operationsBlockedByRefreshBuilder.append("countDeletes", + operationsBlockedByRefresh.countDeletes.load()); + operationsBlockedByRefreshBuilder.append("countCommands", + operationsBlockedByRefresh.countCommands.load()); + + operationsBlockedByRefreshBuilder.done(); + } } CatalogCache::DatabaseCache::DatabaseCache(ServiceContext* service, @@ -598,10 +610,6 @@ CatalogCache::DatabaseCache::LookupResult CatalogCache::DatabaseCache::_lookupDa const std::string& dbName, const DatabaseTypeValueHandle& previousDbType, const ComparableDatabaseVersion& previousDbVersion) { - if (MONGO_unlikely(blockDatabaseCacheLookup.shouldFail())) { - LOGV2(8023400, "Hanging before refreshing cached database entry"); - blockDatabaseCacheLookup.pauseWhileSet(); - } // TODO (SERVER-34164): Track and increment stats for database refreshes LOGV2_FOR_CATALOG_REFRESH(24102, 2, "Refreshing cached database entry", "db"_attr = dbName); @@ -693,7 +701,7 @@ CatalogCache::CollectionCache::LookupResult CatalogCache::CollectionCache::_look OperationContext* opCtx, const NamespaceString& nss, const RoutingTableHistoryValueHandle& existingHistory, - const ComparableChunkVersion& timeInStore) { + const ComparableChunkVersion& previousVersion) { const bool isIncremental(existingHistory && existingHistory->optRt); _updateRefreshesStats(isIncremental, true); blockCollectionCacheLookup.pauseWhileSet(opCtx); @@ -712,7 +720,7 @@ CatalogCache::CollectionCache::LookupResult CatalogCache::CollectionCache::_look "Refreshing cached collection", "namespace"_attr = nss, "lookupSinceVersion"_attr = lookupVersion, - "timeInStore"_attr = timeInStore); + "timeInStore"_attr = previousVersion); auto collectionAndChunks = _catalogCacheLoader.getChunksSince(nss, lookupVersion).get(); @@ -734,18 +742,14 @@ CatalogCache::CollectionCache::LookupResult CatalogCache::CollectionCache::_look const ChunkVersion newVersion = newRoutingHistory->getVersion(); newComparableVersion.setChunkVersion(newVersion); - // The log below is logged at debug(0) (equivalent to info level) only if the new placement - // version is different than the one we already had (if any). - LOGV2_FOR_CATALOG_REFRESH( - 4619901, - (!isIncremental || newVersion != existingHistory->optRt->getVersion()) ? 0 : 1, - "Refreshed cached collection", - "namespace"_attr = nss, - "lookupSinceVersion"_attr = lookupVersion, - "newVersion"_attr = newComparableVersion, - "timeInStore"_attr = timeInStore, - "duration"_attr = Milliseconds(t.millis())); - + LOGV2_FOR_CATALOG_REFRESH(4619901, + isIncremental || newComparableVersion != previousVersion ? 0 : 1, + "Refreshed cached collection", + "namespace"_attr = nss, + "lookupSinceVersion"_attr = lookupVersion, + "newVersion"_attr = newComparableVersion, + "timeInStore"_attr = previousVersion, + "duration"_attr = Milliseconds(t.millis())); _updateRefreshesStats(isIncremental, false); return LookupResult(OptionalRoutingTableHistory(std::move(newRoutingHistory)), |
