diff options
| author | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-14 14:26:38 -0300 |
|---|---|---|
| committer | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-14 14:26:38 -0300 |
| commit | 294bc6ecabf14c09c9bc8644704921dcf97cb44e (patch) | |
| tree | 279b1e0bab53901a1647ac63c1c724f0f789a663 /src/mongo/db/catalog/index_catalog_impl.cpp | |
| parent | 70be7c27a251621187a1de533462ae2bb1e3bd39 (diff) | |
| parent | 1e917fd798aa25b7066d4b414b51184f13d5a092 (diff) | |
Update upstream source from tag 'upstream/6.0.10'debian/6.0.10-1
Update to upstream version '6.0.10'
with Debian dir 2d176fa254eee97b139f712fec5709641335a8c3
Diffstat (limited to 'src/mongo/db/catalog/index_catalog_impl.cpp')
| -rw-r--r-- | src/mongo/db/catalog/index_catalog_impl.cpp | 197 |
1 files changed, 129 insertions, 68 deletions
diff --git a/src/mongo/db/catalog/index_catalog_impl.cpp b/src/mongo/db/catalog/index_catalog_impl.cpp index 6733dac0ba1..4a4d0b64826 100644 --- a/src/mongo/db/catalog/index_catalog_impl.cpp +++ b/src/mongo/db/catalog/index_catalog_impl.cpp @@ -47,7 +47,6 @@ #include "mongo/db/catalog/uncommitted_catalog_updates.h" #include "mongo/db/client.h" #include "mongo/db/clientcursor.h" -#include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/curop.h" #include "mongo/db/field_ref.h" #include "mongo/db/fts/fts_spec.h" @@ -205,13 +204,30 @@ Status IndexCatalogImpl::init(OperationContext* opCtx, Collection* collection) { auto descriptor = std::make_unique<IndexDescriptor>(_getAccessMethodName(keyPattern), spec); + // TTL indexes with NaN 'expireAfterSeconds' cause problems in multiversion settings. + if (spec.hasField(IndexDescriptor::kExpireAfterSecondsFieldName)) { + if (spec[IndexDescriptor::kExpireAfterSecondsFieldName].isNaN()) { + LOGV2_OPTIONS(6852200, + {logv2::LogTag::kStartupWarnings}, + "Found an existing TTL index with NaN 'expireAfterSeconds' in the " + "catalog.", + "ns"_attr = collection->ns(), + "uuid"_attr = collection->uuid(), + "index"_attr = indexName, + "spec"_attr = spec); + } + } + // TTL indexes are not compatible with capped collections. // Note that TTL deletion is supported on capped clustered collections via bounded // collection scan, which does not use an index. if (spec.hasField(IndexDescriptor::kExpireAfterSecondsFieldName) && !collection->isCapped()) { TTLCollectionCache::get(opCtx->getServiceContext()) - .registerTTLInfo(collection->uuid(), indexName); + .registerTTLInfo( + collection->uuid(), + TTLCollectionCache::Info{ + indexName, spec[IndexDescriptor::kExpireAfterSecondsFieldName].isNaN()}); } bool ready = collection->isIndexReady(indexName); @@ -257,8 +273,8 @@ Status IndexCatalogImpl::init(OperationContext* opCtx, Collection* collection) { } std::unique_ptr<IndexCatalog::IndexIterator> IndexCatalogImpl::getIndexIterator( - OperationContext* const opCtx, const bool includeUnfinishedIndexes) const { - if (!includeUnfinishedIndexes) { + OperationContext* const opCtx, InclusionPolicy inclusionPolicy) const { + if (inclusionPolicy == InclusionPolicy::kReady) { // If the caller only wants the ready indexes, we return an iterator over the catalog's // ready indexes vector. When the user advances this iterator, it will filter out any // indexes that were not ready at the OperationContext's read timestamp. @@ -266,17 +282,28 @@ std::unique_ptr<IndexCatalog::IndexIterator> IndexCatalogImpl::getIndexIterator( opCtx, _readyIndexes.begin(), _readyIndexes.end()); } - // If the caller wants all indexes, for simplicity of implementation, we copy the pointers to - // a new vector. The vector's ownership is passed to the iterator. The query code path from an - // external client is not expected to hit this case so the cost isn't paid by the important - // code path. + // If the caller doesn't only want the ready indexes, for simplicity of implementation, we copy + // the pointers to a new vector. The vector's ownership is passed to the iterator. The query + // code path from an external client is not expected to hit this case so the cost isn't paid by + // the important code path. auto allIndexes = std::make_unique<std::vector<IndexCatalogEntry*>>(); - for (auto it = _readyIndexes.begin(); it != _readyIndexes.end(); ++it) { - allIndexes->push_back(it->get()); + + if (inclusionPolicy & InclusionPolicy::kReady) { + for (auto it = _readyIndexes.begin(); it != _readyIndexes.end(); ++it) { + allIndexes->push_back(it->get()); + } + } + + if (inclusionPolicy & InclusionPolicy::kUnfinished) { + for (auto it = _buildingIndexes.begin(); it != _buildingIndexes.end(); ++it) { + allIndexes->push_back(it->get()); + } } - for (auto it = _buildingIndexes.begin(); it != _buildingIndexes.end(); ++it) { - allIndexes->push_back(it->get()); + if (inclusionPolicy & InclusionPolicy::kFrozen) { + for (auto it = _frozenIndexes.begin(); it != _frozenIndexes.end(); ++it) { + allIndexes->push_back(it->get()); + } } return std::make_unique<AllIndexesIterator>(opCtx, std::move(allIndexes)); @@ -350,6 +377,7 @@ void IndexCatalogImpl::_logInternalState(OperationContext* opCtx, "numIndexesInCollectionCatalogEntry"_attr = numIndexesInCollectionCatalogEntry, "numReadyIndexes"_attr = _readyIndexes.size(), "numBuildingIndexes"_attr = _buildingIndexes.size(), + "numFrozenIndexes"_attr = _frozenIndexes.size(), "indexNamesToDrop"_attr = indexNamesToDrop); // Report the ready indexes. @@ -425,7 +453,8 @@ StatusWith<BSONObj> IndexCatalogImpl::prepareSpecForCreate( } // First check against only the ready indexes for conflicts. - status = _doesSpecConflictWithExisting(opCtx, collection, validatedSpec, false); + status = + _doesSpecConflictWithExisting(opCtx, collection, validatedSpec, InclusionPolicy::kReady); if (!status.isOK()) { return status; } @@ -441,7 +470,12 @@ StatusWith<BSONObj> IndexCatalogImpl::prepareSpecForCreate( // The index catalog cannot currently iterate over only in-progress indexes. So by previously // checking against only ready indexes without error, we know that any errors encountered // checking against all indexes occurred due to an in-progress index. - status = _doesSpecConflictWithExisting(opCtx, collection, validatedSpec, true); + status = _doesSpecConflictWithExisting(opCtx, + collection, + validatedSpec, + IndexCatalog::InclusionPolicy::kReady | + IndexCatalog::InclusionPolicy::kUnfinished | + IndexCatalog::InclusionPolicy::kFrozen); if (!status.isOK()) { if (ErrorCodes::IndexAlreadyExists == status.code()) { // Callers need to be able to distinguish conflicts against ready indexes versus @@ -470,8 +504,11 @@ std::vector<BSONObj> IndexCatalogImpl::removeExistingIndexesNoChecks( // _doesSpecConflictWithExisting currently does more work than we require here: we are only // interested in the index already exists error. if (ErrorCodes::IndexAlreadyExists == - _doesSpecConflictWithExisting( - opCtx, collection, spec, true /*includeUnfinishedIndexes*/)) { + _doesSpecConflictWithExisting(opCtx, + collection, + spec, + IndexCatalog::InclusionPolicy::kReady | + IndexCatalog::InclusionPolicy::kUnfinished)) { continue; } @@ -534,19 +571,20 @@ IndexCatalogEntry* IndexCatalogImpl::createIndexEntry(OperationContext* opCtx, engine->getEngine()->alterIdentMetadata(opCtx, ident, desc, isForceUpdateMetadata); } - const auto& collOptions = collection->getCollectionOptions(); - std::unique_ptr<SortedDataInterface> sdi = engine->getEngine()->getSortedDataInterface( - opCtx, collection->ns(), collOptions, ident, desc); - - std::unique_ptr<IndexAccessMethod> accessMethod = - IndexAccessMethodFactory::get(opCtx)->make(entry.get(), std::move(sdi)); - - entry->init(std::move(accessMethod)); - + if (!frozen) { + const auto& collOptions = collection->getCollectionOptions(); + std::unique_ptr<SortedDataInterface> sdi = engine->getEngine()->getSortedDataInterface( + opCtx, collection->ns(), collOptions, ident, desc); + std::unique_ptr<IndexAccessMethod> accessMethod = + IndexAccessMethod::make(entry.get(), std::move(sdi)); + entry->setAccessMethod(std::move(accessMethod)); + } IndexCatalogEntry* save = entry.get(); if (isReadyIndex) { _readyIndexes.add(std::move(entry)); + } else if (frozen) { + _frozenIndexes.add(std::move(entry)); } else { _buildingIndexes.add(std::move(entry)); } @@ -873,10 +911,11 @@ Status IndexCatalogImpl::_isSpecOk(OperationContext* opCtx, } const std::unique_ptr<MatchExpression> filterExpr = std::move(statusWithMatcher.getValue()); - Status status = - _checkValidFilterExpressions(filterExpr.get(), - feature_flags::gTimeseriesMetricIndexes.isEnabled( - serverGlobalParams.featureCompatibility)); + Status status = _checkValidFilterExpressions( + filterExpr.get(), + !serverGlobalParams.featureCompatibility.isVersionInitialized() || + feature_flags::gTimeseriesMetricIndexes.isEnabled( + serverGlobalParams.featureCompatibility)); if (!status.isOK()) { return status; } @@ -951,7 +990,7 @@ Status IndexCatalogImpl::_isSpecOk(OperationContext* opCtx, Status IndexCatalogImpl::_doesSpecConflictWithExisting(OperationContext* opCtx, const CollectionPtr& collection, const BSONObj& spec, - const bool includeUnfinishedIndexes) const { + InclusionPolicy inclusionPolicy) const { StringData name = spec.getStringField(IndexDescriptor::kIndexNameFieldName); invariant(name[0]); @@ -965,7 +1004,7 @@ Status IndexCatalogImpl::_doesSpecConflictWithExisting(OperationContext* opCtx, { // Check whether an index with the specified candidate name already exists in the catalog. - const IndexDescriptor* desc = findIndexByName(opCtx, name, includeUnfinishedIndexes); + const IndexDescriptor* desc = findIndexByName(opCtx, name, inclusionPolicy); if (desc) { // Index already exists with same name. Check whether the options are the same as well. @@ -1018,7 +1057,7 @@ Status IndexCatalogImpl::_doesSpecConflictWithExisting(OperationContext* opCtx, { // No index with the candidate name exists. Check for an index with conflicting options. const IndexDescriptor* desc = - findIndexByKeyPatternAndOptions(opCtx, key, spec, includeUnfinishedIndexes); + findIndexByKeyPatternAndOptions(opCtx, key, spec, inclusionPolicy); if (desc) { LOGV2_DEBUG(20353, @@ -1069,7 +1108,7 @@ Status IndexCatalogImpl::_doesSpecConflictWithExisting(OperationContext* opCtx, string pluginName = IndexNames::findPluginName(key); if (pluginName == IndexNames::TEXT) { vector<const IndexDescriptor*> textIndexes; - findIndexByType(opCtx, IndexNames::TEXT, textIndexes, includeUnfinishedIndexes); + findIndexByType(opCtx, IndexNames::TEXT, textIndexes, inclusionPolicy); if (textIndexes.size() > 0) { return Status(ErrorCodes::CannotCreateIndex, str::stream() << "only one text index per collection allowed, " @@ -1110,7 +1149,10 @@ void IndexCatalogImpl::dropIndexes(OperationContext* opCtx, vector<string> indexNamesToDrop; { int seen = 0; - std::unique_ptr<IndexIterator> ii = getIndexIterator(opCtx, true); + auto ii = getIndexIterator(opCtx, + IndexCatalog::InclusionPolicy::kReady | + IndexCatalog::InclusionPolicy::kUnfinished | + IndexCatalog::InclusionPolicy::kFrozen); while (ii->more()) { seen++; const IndexDescriptor* desc = ii->next()->descriptor(); @@ -1125,7 +1167,11 @@ void IndexCatalogImpl::dropIndexes(OperationContext* opCtx, for (size_t i = 0; i < indexNamesToDrop.size(); i++) { string indexName = indexNamesToDrop[i]; - const IndexDescriptor* desc = findIndexByName(opCtx, indexName, true); + const IndexDescriptor* desc = findIndexByName( + opCtx, + indexName, + IndexCatalog::InclusionPolicy::kReady | IndexCatalog::InclusionPolicy::kUnfinished | + IndexCatalog::InclusionPolicy::kFrozen); invariant(desc); LOGV2_DEBUG(20355, 1, "\t dropAllIndexes dropping: {desc}", "desc"_attr = *desc); IndexCatalogEntry* entry = desc->getEntry(); @@ -1251,25 +1297,26 @@ Status IndexCatalogImpl::dropIndexEntry(OperationContext* opCtx, audit::logDropIndex(opCtx->getClient(), indexName, collection->ns()); - auto released = _readyIndexes.release(entry->descriptor()); - if (released) { - invariant(released.get() == entry); - opCtx->recoveryUnit()->registerChange( - std::make_unique<IndexRemoveChange>(opCtx, - collection->ns(), - collection->uuid(), - std::move(released), - collection->getSharedDecorations())); - } else { - released = _buildingIndexes.release(entry->descriptor()); - invariant(released.get() == entry); - opCtx->recoveryUnit()->registerChange( - std::make_unique<IndexRemoveChange>(opCtx, - collection->ns(), - collection->uuid(), - std::move(released), - collection->getSharedDecorations())); - } + auto released = [&] { + if (auto released = _readyIndexes.release(entry->descriptor())) { + return released; + } + if (auto released = _buildingIndexes.release(entry->descriptor())) { + return released; + } + if (auto released = _frozenIndexes.release(entry->descriptor())) { + return released; + } + MONGO_UNREACHABLE; + }(); + + invariant(released.get() == entry); + opCtx->recoveryUnit()->registerChange( + std::make_unique<IndexRemoveChange>(opCtx, + collection->ns(), + collection->uuid(), + std::move(released), + collection->getSharedDecorations())); CollectionQueryInfo::get(collection).rebuildIndexData(opCtx, collection); CollectionIndexUsageTrackerDecoration::get(collection->getSharedDecorations()) @@ -1289,7 +1336,11 @@ void IndexCatalogImpl::_deleteIndexFromDisk(OperationContext* opCtx, Collection* collection, const string& indexName, std::shared_ptr<Ident> ident) { - invariant(!findIndexByName(opCtx, indexName, true /* includeUnfinishedIndexes*/)); + invariant(!findIndexByName(opCtx, + indexName, + IndexCatalog::InclusionPolicy::kReady | + IndexCatalog::InclusionPolicy::kUnfinished | + IndexCatalog::InclusionPolicy::kFrozen)); catalog::removeIndex(opCtx, indexName, collection, std::move(ident)); } @@ -1319,7 +1370,7 @@ int IndexCatalogImpl::numIndexesTotal(OperationContext* opCtx) const { int IndexCatalogImpl::numIndexesReady(OperationContext* opCtx) const { std::vector<const IndexDescriptor*> itIndexes; - std::unique_ptr<IndexIterator> ii = getIndexIterator(opCtx, /*includeUnfinished*/ false); + auto ii = getIndexIterator(opCtx, InclusionPolicy::kReady); while (ii->more()) { itIndexes.push_back(ii->next()->descriptor()); } @@ -1331,7 +1382,7 @@ bool IndexCatalogImpl::haveIdIndex(OperationContext* opCtx) const { } const IndexDescriptor* IndexCatalogImpl::findIdIndex(OperationContext* opCtx) const { - std::unique_ptr<IndexIterator> ii = getIndexIterator(opCtx, false); + auto ii = getIndexIterator(opCtx, InclusionPolicy::kReady); while (ii->more()) { const IndexDescriptor* desc = ii->next()->descriptor(); if (desc->isIdIndex()) @@ -1342,8 +1393,8 @@ const IndexDescriptor* IndexCatalogImpl::findIdIndex(OperationContext* opCtx) co const IndexDescriptor* IndexCatalogImpl::findIndexByName(OperationContext* opCtx, StringData name, - bool includeUnfinishedIndexes) const { - std::unique_ptr<IndexIterator> ii = getIndexIterator(opCtx, includeUnfinishedIndexes); + InclusionPolicy inclusionPolicy) const { + auto ii = getIndexIterator(opCtx, inclusionPolicy); while (ii->more()) { const IndexDescriptor* desc = ii->next()->descriptor(); if (desc->indexName() == name) @@ -1356,8 +1407,8 @@ const IndexDescriptor* IndexCatalogImpl::findIndexByKeyPatternAndOptions( OperationContext* opCtx, const BSONObj& key, const BSONObj& indexSpec, - bool includeUnfinishedIndexes) const { - std::unique_ptr<IndexIterator> ii = getIndexIterator(opCtx, includeUnfinishedIndexes); + InclusionPolicy inclusionPolicy) const { + auto ii = getIndexIterator(opCtx, inclusionPolicy); IndexDescriptor needle(_getAccessMethodName(key), indexSpec); while (ii->more()) { const auto* entry = ii->next(); @@ -1371,10 +1422,10 @@ const IndexDescriptor* IndexCatalogImpl::findIndexByKeyPatternAndOptions( void IndexCatalogImpl::findIndexesByKeyPattern(OperationContext* opCtx, const BSONObj& key, - bool includeUnfinishedIndexes, + InclusionPolicy inclusionPolicy, std::vector<const IndexDescriptor*>* matches) const { invariant(matches); - std::unique_ptr<IndexIterator> ii = getIndexIterator(opCtx, includeUnfinishedIndexes); + auto ii = getIndexIterator(opCtx, inclusionPolicy); while (ii->more()) { const IndexDescriptor* desc = ii->next()->descriptor(); if (SimpleBSONObjComparator::kInstance.evaluate(desc->keyPattern() == key)) { @@ -1386,8 +1437,8 @@ void IndexCatalogImpl::findIndexesByKeyPattern(OperationContext* opCtx, void IndexCatalogImpl::findIndexByType(OperationContext* opCtx, const string& type, vector<const IndexDescriptor*>& matches, - bool includeUnfinishedIndexes) const { - std::unique_ptr<IndexIterator> ii = getIndexIterator(opCtx, includeUnfinishedIndexes); + InclusionPolicy inclusionPolicy) const { + auto ii = getIndexIterator(opCtx, inclusionPolicy); while (ii->more()) { const IndexDescriptor* desc = ii->next()->descriptor(); if (IndexNames::findPluginName(desc->keyPattern()) == type) { @@ -1628,7 +1679,10 @@ Status IndexCatalogImpl::indexRecords(OperationContext* opCtx, for (const MultikeyPathInfo& newPath : newPaths) { invariant(newPath.nss == coll->ns()); - auto idx = findIndexByName(opCtx, newPath.indexName, /*includeUnfinishedIndexes=*/true); + auto idx = findIndexByName(opCtx, + newPath.indexName, + IndexCatalog::InclusionPolicy::kReady | + IndexCatalog::InclusionPolicy::kUnfinished); if (!idx) { return Status(ErrorCodes::IndexNotFound, str::stream() @@ -1731,7 +1785,10 @@ Status IndexCatalogImpl::compactIndexes(OperationContext* opCtx) const { } std::string::size_type IndexCatalogImpl::getLongestIndexNameLength(OperationContext* opCtx) const { - std::unique_ptr<IndexIterator> it = getIndexIterator(opCtx, true); + auto it = getIndexIterator(opCtx, + IndexCatalog::InclusionPolicy::kReady | + IndexCatalog::InclusionPolicy::kUnfinished | + IndexCatalog::InclusionPolicy::kFrozen); std::string::size_type longestIndexNameLength = 0; while (it->more()) { auto thisLength = it->next()->descriptor()->indexName().length(); @@ -1779,7 +1836,11 @@ void IndexCatalogImpl::indexBuildSuccess(OperationContext* opCtx, invariant(releasedEntry.get() == index); _readyIndexes.add(std::move(releasedEntry)); - index->setIndexBuildInterceptor(nullptr); + // Wait to unset the interceptor until the index actually commits. If a write conflict is + // encountered and the index commit process is restated, the multikey information from the + // interceptor may still be needed. + opCtx->recoveryUnit()->onCommit( + [index](boost::optional<Timestamp>) { index->setIndexBuildInterceptor(nullptr); }); index->setIsReady(true); } |
