summaryrefslogtreecommitdiff
path: root/src/mongo/db/catalog/index_catalog_impl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/catalog/index_catalog_impl.cpp')
-rw-r--r--src/mongo/db/catalog/index_catalog_impl.cpp266
1 files changed, 69 insertions, 197 deletions
diff --git a/src/mongo/db/catalog/index_catalog_impl.cpp b/src/mongo/db/catalog/index_catalog_impl.cpp
index 2c3086a54cf..6733dac0ba1 100644
--- a/src/mongo/db/catalog/index_catalog_impl.cpp
+++ b/src/mongo/db/catalog/index_catalog_impl.cpp
@@ -47,6 +47,7 @@
#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"
@@ -204,30 +205,13 @@ 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(),
- TTLCollectionCache::Info{
- indexName, spec[IndexDescriptor::kExpireAfterSecondsFieldName].isNaN()});
+ .registerTTLInfo(collection->uuid(), indexName);
}
bool ready = collection->isIndexReady(indexName);
@@ -273,8 +257,8 @@ Status IndexCatalogImpl::init(OperationContext* opCtx, Collection* collection) {
}
std::unique_ptr<IndexCatalog::IndexIterator> IndexCatalogImpl::getIndexIterator(
- OperationContext* const opCtx, InclusionPolicy inclusionPolicy) const {
- if (inclusionPolicy == InclusionPolicy::kReady) {
+ OperationContext* const opCtx, const bool includeUnfinishedIndexes) const {
+ if (!includeUnfinishedIndexes) {
// 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.
@@ -282,28 +266,17 @@ std::unique_ptr<IndexCatalog::IndexIterator> IndexCatalogImpl::getIndexIterator(
opCtx, _readyIndexes.begin(), _readyIndexes.end());
}
- // 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.
+ // 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.
auto allIndexes = std::make_unique<std::vector<IndexCatalogEntry*>>();
-
- if (inclusionPolicy & InclusionPolicy::kReady) {
- for (auto it = _readyIndexes.begin(); it != _readyIndexes.end(); ++it) {
- allIndexes->push_back(it->get());
- }
+ 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());
- }
- }
-
- if (inclusionPolicy & InclusionPolicy::kFrozen) {
- for (auto it = _frozenIndexes.begin(); it != _frozenIndexes.end(); ++it) {
- allIndexes->push_back(it->get());
- }
+ for (auto it = _buildingIndexes.begin(); it != _buildingIndexes.end(); ++it) {
+ allIndexes->push_back(it->get());
}
return std::make_unique<AllIndexesIterator>(opCtx, std::move(allIndexes));
@@ -377,7 +350,6 @@ 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.
@@ -453,8 +425,7 @@ StatusWith<BSONObj> IndexCatalogImpl::prepareSpecForCreate(
}
// First check against only the ready indexes for conflicts.
- status =
- _doesSpecConflictWithExisting(opCtx, collection, validatedSpec, InclusionPolicy::kReady);
+ status = _doesSpecConflictWithExisting(opCtx, collection, validatedSpec, false);
if (!status.isOK()) {
return status;
}
@@ -470,12 +441,7 @@ 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,
- IndexCatalog::InclusionPolicy::kReady |
- IndexCatalog::InclusionPolicy::kUnfinished |
- IndexCatalog::InclusionPolicy::kFrozen);
+ status = _doesSpecConflictWithExisting(opCtx, collection, validatedSpec, true);
if (!status.isOK()) {
if (ErrorCodes::IndexAlreadyExists == status.code()) {
// Callers need to be able to distinguish conflicts against ready indexes versus
@@ -504,11 +470,8 @@ 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,
- IndexCatalog::InclusionPolicy::kReady |
- IndexCatalog::InclusionPolicy::kUnfinished)) {
+ _doesSpecConflictWithExisting(
+ opCtx, collection, spec, true /*includeUnfinishedIndexes*/)) {
continue;
}
@@ -571,20 +534,19 @@ IndexCatalogEntry* IndexCatalogImpl::createIndexEntry(OperationContext* opCtx,
engine->getEngine()->alterIdentMetadata(opCtx, ident, desc, isForceUpdateMetadata);
}
- 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));
- }
+ 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));
+
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));
}
@@ -623,7 +585,7 @@ StatusWith<BSONObj> IndexCatalogImpl::createIndexOnEmptyCollection(OperationCont
boost::optional<UUID> buildUUID = boost::none;
IndexBuildBlock indexBuildBlock(
collection->ns(), spec, IndexBuildMethod::kForeground, buildUUID);
- status = indexBuildBlock.init(opCtx, collection, /*forRecovery=*/false);
+ status = indexBuildBlock.init(opCtx, collection);
if (!status.isOK())
return status;
@@ -911,11 +873,10 @@ Status IndexCatalogImpl::_isSpecOk(OperationContext* opCtx,
}
const std::unique_ptr<MatchExpression> filterExpr = std::move(statusWithMatcher.getValue());
- Status status = _checkValidFilterExpressions(
- filterExpr.get(),
- !serverGlobalParams.featureCompatibility.isVersionInitialized() ||
- feature_flags::gTimeseriesMetricIndexes.isEnabled(
- serverGlobalParams.featureCompatibility));
+ Status status =
+ _checkValidFilterExpressions(filterExpr.get(),
+ feature_flags::gTimeseriesMetricIndexes.isEnabled(
+ serverGlobalParams.featureCompatibility));
if (!status.isOK()) {
return status;
}
@@ -990,7 +951,7 @@ Status IndexCatalogImpl::_isSpecOk(OperationContext* opCtx,
Status IndexCatalogImpl::_doesSpecConflictWithExisting(OperationContext* opCtx,
const CollectionPtr& collection,
const BSONObj& spec,
- InclusionPolicy inclusionPolicy) const {
+ const bool includeUnfinishedIndexes) const {
StringData name = spec.getStringField(IndexDescriptor::kIndexNameFieldName);
invariant(name[0]);
@@ -1004,7 +965,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, inclusionPolicy);
+ const IndexDescriptor* desc = findIndexByName(opCtx, name, includeUnfinishedIndexes);
if (desc) {
// Index already exists with same name. Check whether the options are the same as well.
@@ -1057,7 +1018,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, inclusionPolicy);
+ findIndexByKeyPatternAndOptions(opCtx, key, spec, includeUnfinishedIndexes);
if (desc) {
LOGV2_DEBUG(20353,
@@ -1108,7 +1069,7 @@ Status IndexCatalogImpl::_doesSpecConflictWithExisting(OperationContext* opCtx,
string pluginName = IndexNames::findPluginName(key);
if (pluginName == IndexNames::TEXT) {
vector<const IndexDescriptor*> textIndexes;
- findIndexByType(opCtx, IndexNames::TEXT, textIndexes, inclusionPolicy);
+ findIndexByType(opCtx, IndexNames::TEXT, textIndexes, includeUnfinishedIndexes);
if (textIndexes.size() > 0) {
return Status(ErrorCodes::CannotCreateIndex,
str::stream() << "only one text index per collection allowed, "
@@ -1149,10 +1110,7 @@ void IndexCatalogImpl::dropIndexes(OperationContext* opCtx,
vector<string> indexNamesToDrop;
{
int seen = 0;
- auto ii = getIndexIterator(opCtx,
- IndexCatalog::InclusionPolicy::kReady |
- IndexCatalog::InclusionPolicy::kUnfinished |
- IndexCatalog::InclusionPolicy::kFrozen);
+ std::unique_ptr<IndexIterator> ii = getIndexIterator(opCtx, true);
while (ii->more()) {
seen++;
const IndexDescriptor* desc = ii->next()->descriptor();
@@ -1167,11 +1125,7 @@ void IndexCatalogImpl::dropIndexes(OperationContext* opCtx,
for (size_t i = 0; i < indexNamesToDrop.size(); i++) {
string indexName = indexNamesToDrop[i];
- const IndexDescriptor* desc = findIndexByName(
- opCtx,
- indexName,
- IndexCatalog::InclusionPolicy::kReady | IndexCatalog::InclusionPolicy::kUnfinished |
- IndexCatalog::InclusionPolicy::kFrozen);
+ const IndexDescriptor* desc = findIndexByName(opCtx, indexName, true);
invariant(desc);
LOGV2_DEBUG(20355, 1, "\t dropAllIndexes dropping: {desc}", "desc"_attr = *desc);
IndexCatalogEntry* entry = desc->getEntry();
@@ -1230,73 +1184,6 @@ Status IndexCatalogImpl::dropIndex(OperationContext* opCtx,
return dropIndexEntry(opCtx, collection, entry);
}
-Status IndexCatalogImpl::resetUnfinishedIndexForRecovery(OperationContext* opCtx,
- Collection* collection,
- const IndexDescriptor* desc) {
- invariant(opCtx->lockState()->isCollectionLockedForMode(collection->ns(), MODE_X));
- invariant(opCtx->lockState()->inAWriteUnitOfWork());
-
- IndexCatalogEntry* entry = desc->getEntry();
- const std::string indexName = entry->descriptor()->indexName();
-
- // Only indexes that aren't ready can be reset.
- invariant(!collection->isIndexReady(indexName));
-
- auto released = [&] {
- if (auto released = _readyIndexes.release(entry->descriptor())) {
- invariant(!released, "Cannot reset a ready index");
- }
- if (auto released = _buildingIndexes.release(entry->descriptor())) {
- return released;
- }
- if (auto released = _frozenIndexes.release(entry->descriptor())) {
- return released;
- }
- MONGO_UNREACHABLE;
- }();
-
- LOGV2(6987700,
- "Resetting unfinished index",
- logAttrs(collection->ns()),
- "index"_attr = indexName,
- "ident"_attr = released->getIdent());
-
- invariant(released.get() == entry);
-
- // Drop the ident if it exists. The storage engine will return OK if the ident is not found.
- auto engine = opCtx->getServiceContext()->getStorageEngine();
- const std::string ident = released->getIdent();
- Status status = engine->getEngine()->dropIdent(opCtx->recoveryUnit(), ident);
- if (!status.isOK()) {
- return status;
- }
-
- // Recreate the ident on-disk. DurableCatalog::createIndex() will lookup the ident internally
- // using the catalogId and index name.
- status = DurableCatalog::get(opCtx)->createIndex(opCtx,
- collection->getCatalogId(),
- collection->ns(),
- collection->getCollectionOptions(),
- released->descriptor());
- if (!status.isOK()) {
- return status;
- }
-
- // Update the index entry state in preparation to rebuild the index.
- if (!released->accessMethod()) {
- std::unique_ptr<SortedDataInterface> sdi = engine->getEngine()->getSortedDataInterface(
- opCtx, collection->ns(), collection->getCollectionOptions(), ident, desc);
- std::unique_ptr<IndexAccessMethod> accessMethod =
- IndexAccessMethod::make(released.get(), std::move(sdi));
- released->setAccessMethod(std::move(accessMethod));
- }
-
- released->setIsFrozen(false);
- _buildingIndexes.add(std::move(released));
-
- return Status::OK();
-}
-
Status IndexCatalogImpl::dropUnfinishedIndex(OperationContext* opCtx,
Collection* collection,
const IndexDescriptor* desc) {
@@ -1364,26 +1251,25 @@ Status IndexCatalogImpl::dropIndexEntry(OperationContext* opCtx,
audit::logDropIndex(opCtx->getClient(), indexName, collection->ns());
- 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()));
+ 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()));
+ }
CollectionQueryInfo::get(collection).rebuildIndexData(opCtx, collection);
CollectionIndexUsageTrackerDecoration::get(collection->getSharedDecorations())
@@ -1403,11 +1289,7 @@ void IndexCatalogImpl::_deleteIndexFromDisk(OperationContext* opCtx,
Collection* collection,
const string& indexName,
std::shared_ptr<Ident> ident) {
- invariant(!findIndexByName(opCtx,
- indexName,
- IndexCatalog::InclusionPolicy::kReady |
- IndexCatalog::InclusionPolicy::kUnfinished |
- IndexCatalog::InclusionPolicy::kFrozen));
+ invariant(!findIndexByName(opCtx, indexName, true /* includeUnfinishedIndexes*/));
catalog::removeIndex(opCtx, indexName, collection, std::move(ident));
}
@@ -1437,7 +1319,7 @@ int IndexCatalogImpl::numIndexesTotal(OperationContext* opCtx) const {
int IndexCatalogImpl::numIndexesReady(OperationContext* opCtx) const {
std::vector<const IndexDescriptor*> itIndexes;
- auto ii = getIndexIterator(opCtx, InclusionPolicy::kReady);
+ std::unique_ptr<IndexIterator> ii = getIndexIterator(opCtx, /*includeUnfinished*/ false);
while (ii->more()) {
itIndexes.push_back(ii->next()->descriptor());
}
@@ -1449,7 +1331,7 @@ bool IndexCatalogImpl::haveIdIndex(OperationContext* opCtx) const {
}
const IndexDescriptor* IndexCatalogImpl::findIdIndex(OperationContext* opCtx) const {
- auto ii = getIndexIterator(opCtx, InclusionPolicy::kReady);
+ std::unique_ptr<IndexIterator> ii = getIndexIterator(opCtx, false);
while (ii->more()) {
const IndexDescriptor* desc = ii->next()->descriptor();
if (desc->isIdIndex())
@@ -1460,8 +1342,8 @@ const IndexDescriptor* IndexCatalogImpl::findIdIndex(OperationContext* opCtx) co
const IndexDescriptor* IndexCatalogImpl::findIndexByName(OperationContext* opCtx,
StringData name,
- InclusionPolicy inclusionPolicy) const {
- auto ii = getIndexIterator(opCtx, inclusionPolicy);
+ bool includeUnfinishedIndexes) const {
+ std::unique_ptr<IndexIterator> ii = getIndexIterator(opCtx, includeUnfinishedIndexes);
while (ii->more()) {
const IndexDescriptor* desc = ii->next()->descriptor();
if (desc->indexName() == name)
@@ -1474,8 +1356,8 @@ const IndexDescriptor* IndexCatalogImpl::findIndexByKeyPatternAndOptions(
OperationContext* opCtx,
const BSONObj& key,
const BSONObj& indexSpec,
- InclusionPolicy inclusionPolicy) const {
- auto ii = getIndexIterator(opCtx, inclusionPolicy);
+ bool includeUnfinishedIndexes) const {
+ std::unique_ptr<IndexIterator> ii = getIndexIterator(opCtx, includeUnfinishedIndexes);
IndexDescriptor needle(_getAccessMethodName(key), indexSpec);
while (ii->more()) {
const auto* entry = ii->next();
@@ -1489,10 +1371,10 @@ const IndexDescriptor* IndexCatalogImpl::findIndexByKeyPatternAndOptions(
void IndexCatalogImpl::findIndexesByKeyPattern(OperationContext* opCtx,
const BSONObj& key,
- InclusionPolicy inclusionPolicy,
+ bool includeUnfinishedIndexes,
std::vector<const IndexDescriptor*>* matches) const {
invariant(matches);
- auto ii = getIndexIterator(opCtx, inclusionPolicy);
+ std::unique_ptr<IndexIterator> ii = getIndexIterator(opCtx, includeUnfinishedIndexes);
while (ii->more()) {
const IndexDescriptor* desc = ii->next()->descriptor();
if (SimpleBSONObjComparator::kInstance.evaluate(desc->keyPattern() == key)) {
@@ -1504,8 +1386,8 @@ void IndexCatalogImpl::findIndexesByKeyPattern(OperationContext* opCtx,
void IndexCatalogImpl::findIndexByType(OperationContext* opCtx,
const string& type,
vector<const IndexDescriptor*>& matches,
- InclusionPolicy inclusionPolicy) const {
- auto ii = getIndexIterator(opCtx, inclusionPolicy);
+ bool includeUnfinishedIndexes) const {
+ std::unique_ptr<IndexIterator> ii = getIndexIterator(opCtx, includeUnfinishedIndexes);
while (ii->more()) {
const IndexDescriptor* desc = ii->next()->descriptor();
if (IndexNames::findPluginName(desc->keyPattern()) == type) {
@@ -1746,10 +1628,7 @@ Status IndexCatalogImpl::indexRecords(OperationContext* opCtx,
for (const MultikeyPathInfo& newPath : newPaths) {
invariant(newPath.nss == coll->ns());
- auto idx = findIndexByName(opCtx,
- newPath.indexName,
- IndexCatalog::InclusionPolicy::kReady |
- IndexCatalog::InclusionPolicy::kUnfinished);
+ auto idx = findIndexByName(opCtx, newPath.indexName, /*includeUnfinishedIndexes=*/true);
if (!idx) {
return Status(ErrorCodes::IndexNotFound,
str::stream()
@@ -1852,10 +1731,7 @@ Status IndexCatalogImpl::compactIndexes(OperationContext* opCtx) const {
}
std::string::size_type IndexCatalogImpl::getLongestIndexNameLength(OperationContext* opCtx) const {
- auto it = getIndexIterator(opCtx,
- IndexCatalog::InclusionPolicy::kReady |
- IndexCatalog::InclusionPolicy::kUnfinished |
- IndexCatalog::InclusionPolicy::kFrozen);
+ std::unique_ptr<IndexIterator> it = getIndexIterator(opCtx, true);
std::string::size_type longestIndexNameLength = 0;
while (it->more()) {
auto thisLength = it->next()->descriptor()->indexName().length();
@@ -1903,11 +1779,7 @@ void IndexCatalogImpl::indexBuildSuccess(OperationContext* opCtx,
invariant(releasedEntry.get() == index);
_readyIndexes.add(std::move(releasedEntry));
- // 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->setIndexBuildInterceptor(nullptr);
index->setIsReady(true);
}