summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenety Goh <benety@mongodb.com>2021-09-30 15:59:57 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-10-11 23:44:48 +0000
commit4da49024045ef47a6958157b64e73511c4865b49 (patch)
tree7be99d5ce306132e74ad65f306cabfa3abc98bc5
parent3ac74aad2a2b70ad5b1ccb97b07a92c52a51f2f3 (diff)
downloadmongo-4da49024045ef47a6958157b64e73511c4865b49.tar.gz
SERVER-52976 remove unused file collection_validation.cpp
The validation improvement in commit 719513a440fdd5a4b97bdab3bbf0e9748678f3a8, which introduced this unused file, can be found in the function _validateCatalogEntry() (collection_impl.cpp). The replication state check in commit 186079301dc9de56313f5a8e84e6088fec289ded has been moved to CollectionImpl::validate() (colletion_impl.cpp) in commit 3ac74aad2a2b70ad5b1ccb97b07a92c52a51f2f3.
-rw-r--r--src/mongo/db/catalog/collection_validation.cpp644
1 files changed, 0 insertions, 644 deletions
diff --git a/src/mongo/db/catalog/collection_validation.cpp b/src/mongo/db/catalog/collection_validation.cpp
deleted file mode 100644
index f39150516f8..00000000000
--- a/src/mongo/db/catalog/collection_validation.cpp
+++ /dev/null
@@ -1,644 +0,0 @@
-/**
- * Copyright (C) 2019-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kStorage
-
-#include "mongo/platform/basic.h"
-
-#include "mongo/db/catalog/collection_validation.h"
-
-#include <fmt/format.h>
-
-#include "mongo/db/catalog/collection.h"
-#include "mongo/db/catalog/index_consistency.h"
-#include "mongo/db/catalog/throttle_cursor.h"
-#include "mongo/db/db_raii.h"
-#include "mongo/db/index/index_access_method.h"
-#include "mongo/db/operation_context.h"
-#include "mongo/db/storage/durable_catalog.h"
-#include "mongo/db/storage/record_store.h"
-#include "mongo/db/views/view_catalog.h"
-#include "mongo/util/fail_point.h"
-#include "mongo/util/log.h"
-
-namespace mongo {
-
-using logger::LogComponent;
-using std::string;
-
-MONGO_FAIL_POINT_DEFINE(pauseCollectionValidationWithLock);
-
-namespace CollectionValidation {
-
-namespace {
-
-using ValidateResultsMap = std::map<string, ValidateResults>;
-
-// Indicates whether the failpoint turned on by testing has been reached.
-AtomicWord<bool> _validationIsPausedForTest{false};
-
-/**
- * Opens a cursor on each index in the given 'indexCatalog'.
- *
- * Returns a map from indexName -> indexCursor.
- */
-std::map<std::string, std::unique_ptr<SortedDataInterfaceThrottleCursor>> _openIndexCursors(
- OperationContext* opCtx,
- IndexCatalog* indexCatalog,
- std::shared_ptr<DataThrottle> dataThrottle) {
- std::map<std::string, std::unique_ptr<SortedDataInterfaceThrottleCursor>> indexCursors;
- const std::unique_ptr<IndexCatalog::IndexIterator> it =
- indexCatalog->getIndexIterator(opCtx, false);
- while (it->more()) {
- const IndexCatalogEntry* entry = it->next();
- indexCursors.emplace(entry->descriptor()->indexName(),
- std::make_unique<SortedDataInterfaceThrottleCursor>(
- opCtx, entry->accessMethod(), dataThrottle));
- }
- return indexCursors;
-}
-
-/**
- * Validates the internal structure of each index in the Index Catalog 'indexCatalog', ensuring that
- * the index files have not been corrupted or compromised.
- *
- * May close or invalidate open cursors.
- *
- * Returns a map from indexName -> number of keys validated.
- */
-std::map<std::string, int64_t> _validateIndexesInternalStructure(
- OperationContext* opCtx,
- IndexCatalog* indexCatalog,
- ValidateResultsMap* indexNsResultsMap,
- ValidateResults* results) {
- std::map<std::string, int64_t> numIndexKeysPerIndex;
- const std::unique_ptr<IndexCatalog::IndexIterator> it =
- indexCatalog->getIndexIterator(opCtx, false);
-
- // Validate Indexes Internal Structure, checking if index files have been compromised or
- // corrupted.
- while (it->more()) {
- opCtx->checkForInterrupt();
-
- const IndexCatalogEntry* entry = it->next();
- const IndexDescriptor* descriptor = entry->descriptor();
- const IndexAccessMethod* iam = entry->accessMethod();
-
- log(LogComponent::kIndex) << "validating the internal structure of index "
- << descriptor->indexName() << " on collection "
- << descriptor->parentNS();
- ValidateResults& curIndexResults = (*indexNsResultsMap)[descriptor->indexName()];
-
- int64_t numValidated;
- iam->validate(opCtx, &numValidated, &curIndexResults);
-
- numIndexKeysPerIndex[descriptor->indexName()] = numValidated;
- }
- return numIndexKeysPerIndex;
-}
-
-/**
- * Validates each index in the Index Catalog using the cursors in 'indexCursors'.
- *
- * If 'level' is kValidateFull, then we will compare new index entry counts with a previously taken
- * count saved in 'numIndexKeysPerIndex'.
- */
-void _validateIndexes(
- OperationContext* opCtx,
- IndexCatalog* indexCatalog,
- BSONObjBuilder* keysPerIndex,
- ValidateAdaptor* indexValidator,
- ValidateCmdLevel level,
- const std::map<std::string, std::unique_ptr<SortedDataInterfaceThrottleCursor>>& indexCursors,
- const std::map<std::string, int64_t>& numIndexKeysPerIndex,
- ValidateResultsMap* indexNsResultsMap,
- ValidateResults* results) {
-
- const std::unique_ptr<IndexCatalog::IndexIterator> it =
- indexCatalog->getIndexIterator(opCtx, false);
-
- // Validate Indexes, checking for mismatch between index entries and collection records.
- while (it->more()) {
- opCtx->checkForInterrupt();
-
- const IndexDescriptor* descriptor = it->next()->descriptor();
-
- log(LogComponent::kIndex) << "validating index consistency " << descriptor->indexName()
- << " on collection " << descriptor->parentNS();
-
- // Ensure that this index had an index cursor opened in _openIndexCursors.
- const auto indexCursorIt = indexCursors.find(descriptor->indexName());
- invariant(indexCursorIt != indexCursors.end());
-
- ValidateResults& curIndexResults = (*indexNsResultsMap)[descriptor->indexName()];
- int64_t numTraversedKeys;
- indexValidator->traverseIndex(
- opCtx, &numTraversedKeys, indexCursorIt->second, descriptor, &curIndexResults);
-
- // If we are performing a full validation, we have information on the number of index keys
- // validated in _validateIndexesInternalStructure (when we validated the internal structure
- // of the index). Check if this is consistent with 'numTraversedKeys' from traverseIndex
- // above.
- if (level == kValidateFull) {
- invariant(
- opCtx->lockState()->isCollectionLockedForMode(descriptor->parentNS(), MODE_X));
-
- // Ensure that this index was validated in _validateIndexesInternalStructure.
- const auto numIndexKeysIt = numIndexKeysPerIndex.find(descriptor->indexName());
- invariant(numIndexKeysIt != numIndexKeysPerIndex.end());
-
- // The number of keys counted in _validateIndexesInternalStructure, when checking the
- // internal structure of the index.
- const int64_t numIndexKeys = numIndexKeysIt->second;
-
- // Check if currIndexResults is valid to ensure that this index is not corrupted or
- // comprised (which was set in _validateIndexesInternalStructure). If the index is
- // corrupted, there is no use in checking if the traversal yielded the same key count.
- if (curIndexResults.valid) {
- if (numIndexKeys != numTraversedKeys) {
- curIndexResults.valid = false;
- string msg = str::stream()
- << "number of traversed index entries (" << numTraversedKeys
- << ") does not match the number of expected index entries (" << numIndexKeys
- << ")";
- results->errors.push_back(msg);
- results->valid = false;
- }
- }
- }
-
- if (curIndexResults.valid) {
- keysPerIndex->appendNumber(descriptor->indexName(),
- static_cast<long long>(numTraversedKeys));
- } else {
- results->valid = false;
- }
- }
-}
-
-/**
- * Executes the second phase of validation for improved error reporting. This is only done if
- * any index inconsistencies are found during the first phase of validation.
- */
-void _gatherIndexEntryErrors(
- OperationContext* opCtx,
- Collection* coll,
- IndexConsistency* indexConsistency,
- ValidateAdaptor* indexValidator,
- const RecordId& firstRecordId,
- const std::unique_ptr<SeekableRecordThrottleCursor>& traverseRecordStoreCursor,
- const std::unique_ptr<SeekableRecordThrottleCursor>& seekRecordStoreCursor,
- const std::map<std::string, std::unique_ptr<SortedDataInterfaceThrottleCursor>>& indexCursors,
- ValidateResultsMap* indexNsResultsMap,
- ValidateResults* result) {
- indexConsistency->setSecondPhase();
-
- log(LogComponent::kIndex) << "Starting to traverse through all the document key sets.";
-
- // During the second phase of validation, iterate through each documents key set and only record
- // the keys that were inconsistent during the first phase of validation.
- for (auto record = traverseRecordStoreCursor->seekExact(opCtx, firstRecordId); record;
- record = traverseRecordStoreCursor->next(opCtx)) {
- opCtx->checkForInterrupt();
-
- // We can ignore the status of validate as it was already checked during the first phase.
- size_t validatedSize;
- indexValidator
- ->validateRecord(
- opCtx, coll, record->id, record->data, seekRecordStoreCursor, &validatedSize)
- .ignore();
- }
-
- log(LogComponent::kIndex) << "Finished traversing through all the document key sets.";
- log(LogComponent::kIndex) << "Starting to traverse through all the indexes.";
-
- // Iterate through all the indexes in the collection and only record the index entry keys that
- // had inconsistencies during the first phase.
- std::unique_ptr<IndexCatalog::IndexIterator> it =
- coll->getIndexCatalog()->getIndexIterator(opCtx, false);
- while (it->more()) {
- opCtx->checkForInterrupt();
-
- const IndexDescriptor* descriptor = it->next()->descriptor();
-
- log(LogComponent::kIndex) << "Traversing through the index entries for index "
- << descriptor->indexName() << ".";
-
- // Ensure that this index had an index cursor opened in _openIndexCursors.
- const auto indexCursorIt = indexCursors.find(descriptor->indexName());
- invariant(indexCursorIt != indexCursors.end());
-
- indexValidator->traverseIndex(opCtx,
- /*numTraversedKeys=*/nullptr,
- indexCursorIt->second,
- descriptor,
- /*ValidateResults=*/nullptr);
- }
-
- log(LogComponent::kIndex) << "Finished traversing through all the indexes.";
-
- indexConsistency->addIndexEntryErrors(indexNsResultsMap, result);
-}
-
-void _validateIndexKeyCount(OperationContext* opCtx,
- Collection* coll,
- ValidateAdaptor* indexValidator,
- ValidateResultsMap* indexNsResultsMap) {
-
- const std::unique_ptr<IndexCatalog::IndexIterator> indexIterator =
- coll->getIndexCatalog()->getIndexIterator(opCtx, false);
- while (indexIterator->more()) {
- const IndexDescriptor* descriptor = indexIterator->next()->descriptor();
- ValidateResults& curIndexResults = (*indexNsResultsMap)[descriptor->indexName()];
-
- if (curIndexResults.valid) {
- indexValidator->validateIndexKeyCount(
- descriptor, coll->getRecordStore()->numRecords(opCtx), curIndexResults);
- }
- }
-}
-
-void _reportValidationResults(OperationContext* opCtx,
- Collection* collection,
- ValidateResultsMap* indexNsResultsMap,
- BSONObjBuilder* keysPerIndex,
- ValidateCmdLevel level,
- ValidateResults* results,
- BSONObjBuilder* output) {
- std::unique_ptr<BSONObjBuilder> indexDetails;
- if (level == kValidateFull) {
- invariant(opCtx->lockState()->isCollectionLockedForMode(collection->ns(), MODE_X));
- indexDetails = std::make_unique<BSONObjBuilder>();
- }
-
- // Report index validation results.
- for (const auto& it : *indexNsResultsMap) {
- const string indexName = it.first;
- const ValidateResults& vr = it.second;
-
- if (!vr.valid) {
- results->valid = false;
- }
-
- if (indexDetails) {
- BSONObjBuilder bob(indexDetails->subobjStart(indexName));
- bob.appendBool("valid", vr.valid);
-
- if (!vr.warnings.empty()) {
- bob.append("warnings", vr.warnings);
- }
-
- if (!vr.errors.empty()) {
- bob.append("errors", vr.errors);
- }
- }
-
- results->warnings.insert(results->warnings.end(), vr.warnings.begin(), vr.warnings.end());
- results->errors.insert(results->errors.end(), vr.errors.begin(), vr.errors.end());
- }
-
- output->append("nIndexes", collection->getIndexCatalog()->numIndexesReady(opCtx));
- output->append("keysPerIndex", keysPerIndex->done());
- if (indexDetails) {
- output->append("indexDetails", indexDetails->done());
- }
-}
-
-template <typename T>
-void addErrorIfUnequal(T stored, T cached, StringData name, ValidateResults* results) {
- if (stored != cached) {
- results->valid = false;
- results->errors.push_back(str::stream() << "stored value for " << name
- << " does not match cached value: " << stored
- << " != " << cached);
- }
-}
-
-std::string multikeyPathsToString(MultikeyPaths paths) {
- str::stream builder;
- builder << "[";
- auto pathIt = paths.begin();
- while (true) {
- builder << "{";
-
- auto pathSet = *pathIt;
- auto setIt = pathSet.begin();
- while (true) {
- builder << *setIt++;
- if (setIt == pathSet.end()) {
- break;
- } else {
- builder << ",";
- }
- }
- builder << "}";
-
- if (++pathIt == paths.end()) {
- break;
- } else {
- builder << ",";
- }
- }
- builder << "]";
- return builder;
-}
-
-void _validateCatalogEntry(OperationContext* opCtx,
- Collection* coll,
- BSONObj validatorDoc,
- ValidateResults* results) {
- CollectionOptions options = DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, coll->ns());
- if (options.uuid) {
- addErrorIfUnequal(*(options.uuid), coll->uuid(), "UUID", results);
- } else {
- results->valid = false;
- results->errors.push_back("UUID missing on collection.");
- }
- const CollatorInterface* collation = coll->getDefaultCollator();
- addErrorIfUnequal(options.collation.isEmpty(), !collation, "simple collation", results);
- if (!options.collation.isEmpty() && collation)
- addErrorIfUnequal(options.collation.toString(),
- collation->getSpec().toBSON().toString(),
- "collation",
- results);
- addErrorIfUnequal(options.capped, coll->isCapped(), "is capped", results);
-
- addErrorIfUnequal(options.validator.toString(), validatorDoc.toString(), "validator", results);
- if (!options.validator.isEmpty() && !validatorDoc.isEmpty()) {
- addErrorIfUnequal(options.validationAction.length() ? options.validationAction : "error",
- coll->getValidationAction().toString(),
- "validation action",
- results);
- addErrorIfUnequal(options.validationLevel.length() ? options.validationLevel : "strict",
- coll->getValidationLevel().toString(),
- "validation level",
- results);
- }
-
- addErrorIfUnequal(options.isView(), false, "is a view", results);
- auto status = options.validateForStorage();
- if (!status.isOK()) {
- results->valid = false;
- results->errors.push_back(str::stream() << "collection options are not valid for storage: "
- << options.toBSON());
- }
-
- std::vector<std::string> indexes;
- DurableCatalog::get(opCtx)->getReadyIndexes(opCtx, coll->ns(), &indexes);
- for (auto& index : indexes) {
- MultikeyPaths multikeyPaths;
- const bool isMultikey =
- DurableCatalog::get(opCtx)->isIndexMultikey(opCtx, coll->ns(), index, &multikeyPaths);
- const bool hasMultiKeyPaths = std::any_of(multikeyPaths.begin(),
- multikeyPaths.end(),
- [](auto& pathSet) { return pathSet.size() > 0; });
- // It is illegal for multikey paths to exist without the multikey flag set on the index, but
- // it may be possible for multikey to be set on the index while having no multikey paths. If
- // any of the paths are multikey, then the entire index should also be marked multikey.
- if (hasMultiKeyPaths && !isMultikey) {
- results->valid = false;
- results->errors.push_back(fmt::format(
- "The 'multikey' field for index {} was false with non-empty 'multikeyPaths': {}",
- index,
- multikeyPathsToString(multikeyPaths)));
- }
- }
-}
-} // namespace
-
-Status validate(OperationContext* opCtx,
- const NamespaceString& nss,
- ValidateCmdLevel level,
- bool background,
- ValidateResults* results,
- BSONObjBuilder* output) {
- invariant(!opCtx->lockState()->isLocked());
- invariant(!(background && (level == kValidateFull)));
-
- if (background) {
- // Force a checkpoint to ensure background validation has a checkpoint on which to run.
- // TODO (SERVER-43134): to sort out how to do this properly.
- opCtx->recoveryUnit()->waitUntilUnjournaledWritesDurable(opCtx);
- }
-
- AutoGetDb autoDB(opCtx, nss.db(), MODE_IX);
- boost::optional<Lock::CollectionLock> collLock;
- if (background) {
- collLock.emplace(opCtx, nss, MODE_IX);
- } else {
- collLock.emplace(opCtx, nss, MODE_X);
- }
-
- Collection* collection = autoDB.getDb() ? autoDB.getDb()->getCollection(opCtx, nss) : nullptr;
- if (!collection) {
- if (autoDB.getDb() && ViewCatalog::get(autoDB.getDb())->lookup(opCtx, nss.ns())) {
- return {ErrorCodes::CommandNotSupportedOnView, "Cannot validate a view"};
- }
-
- return {ErrorCodes::NamespaceNotFound,
- str::stream() << "Collection '" << nss << "' does not exist to validate."};
- }
-
- output->append("ns", nss.ns());
-
- ValidateResultsMap indexNsResultsMap;
- BSONObjBuilder keysPerIndex; // not using subObjStart to be exception safe.
- IndexConsistency indexConsistency(opCtx, collection);
- ValidateAdaptor indexValidator = ValidateAdaptor(&indexConsistency, level, &indexNsResultsMap);
-
- const auto replCoord = repl::ReplicationCoordinator::get(opCtx);
- // Check whether we are allowed to read from this node after acquiring our locks. If we are
- // in a state where we cannot read, we should not run validate.
- uassertStatusOK(replCoord->checkCanServeReadsFor(
- opCtx, nss, ReadPreferenceSetting::get(opCtx).canRunOnSecondary()));
-
- try {
- std::map<std::string, int64_t> numIndexKeysPerIndex;
-
- // Full validation code is executed before we open cursors because it may close
- // and/or invalidate all open cursors.
- if (level == kValidateFull) {
- invariant(opCtx->lockState()->isCollectionLockedForMode(nss, MODE_X));
-
- // For full validation we use the storage engine's validation functionality.
- collection->getRecordStore()->validate(opCtx, results, output);
-
- // For full validation, we validate the internal structure of each index and save the
- // number of keys in the index to compare against _validateIndexes()'s count results.
- numIndexKeysPerIndex = _validateIndexesInternalStructure(
- opCtx, collection->getIndexCatalog(), &indexNsResultsMap, results);
- }
-
- // Validate in-memory catalog information with persisted info prior to setting the read
- // source to kCheckpoint otherwise we'd use a checkpointed MDB catalog file.
- _validateCatalogEntry(opCtx, collection, collection->getValidatorDoc(), results);
-
- // We want to share the same data throttle instance across all the cursors used during this
- // validation. Validations started on other collections will not share the same data
- // throttle instance.
- std::shared_ptr<DataThrottle> dataThrottle = std::make_shared<DataThrottle>();
-
- if (!background) {
- dataThrottle->turnThrottlingOff();
- }
-
- // Background validation will read from the last stable checkpoint instead of the latest
- // data. This allows concurrent writes to go ahead without interfering with validation's
- // view of the data.
- // The checkpoint lock must be taken around cursor creation to ensure all cursors
- // point at the same checkpoint, i.e. a consistent view of the collection data.
- std::unique_ptr<StorageEngine::CheckpointLock> checkpointCursorsLock;
- if (background) {
- auto storageEngine = opCtx->getServiceContext()->getStorageEngine();
- invariant(storageEngine->supportsCheckpoints());
- opCtx->recoveryUnit()->abandonSnapshot();
- opCtx->recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kCheckpoint);
- checkpointCursorsLock = storageEngine->getCheckpointLock(opCtx);
- }
-
- // Open all cursors at once before running non-full validation code so that all steps of
- // validation during background validation use the same view of the data.
- const std::map<std::string, std::unique_ptr<SortedDataInterfaceThrottleCursor>>
- indexCursors = _openIndexCursors(opCtx, collection->getIndexCatalog(), dataThrottle);
- const std::unique_ptr<SeekableRecordThrottleCursor> traverseRecordStoreCursor =
- std::make_unique<SeekableRecordThrottleCursor>(
- opCtx, collection->getRecordStore(), dataThrottle);
- const std::unique_ptr<SeekableRecordThrottleCursor> seekRecordStoreCursor =
- std::make_unique<SeekableRecordThrottleCursor>(
- opCtx, collection->getRecordStore(), dataThrottle);
-
- checkpointCursorsLock.reset();
-
- // Because SeekableRecordCursors don't have a method to reset to the start, we save and then
- // use a seek to the first RecordId to reset the cursor (and reuse it) as needed. When
- // iterating through a Record Store cursor, we initialize the loop (and obtain the first
- // Record) with a seek to the first Record (using firstRecordId). Subsequent loop iterations
- // use cursor->next() to get subsequent Records. However, if the Record Store is empty,
- // there is no first record. In this case, we set the first Record Id to an invalid RecordId
- // (RecordId()), which will halt iteration at the initialization step.
- const boost::optional<Record> record = traverseRecordStoreCursor->next(opCtx);
- const RecordId firstRecordId = record ? record->id : RecordId();
-
- const string uuidString = str::stream() << " (UUID: " << collection->uuid() << ")";
-
- // Validate the record store.
- log(LogComponent::kIndex) << "validating collection " << collection->ns() << uuidString;
- // In traverseRecordStore(), the index validator keeps track the records in the record
- // store so that _validateIndexes() can confirm that the index entries match the records in
- // the collection.
- indexValidator.traverseRecordStore(opCtx,
- collection,
- firstRecordId,
- traverseRecordStoreCursor,
- seekRecordStoreCursor,
- background,
- results,
- output);
-
- // Pause collection validation while a lock is held and between collection and index data
- // valiation.
- //
- // The IndexConsistency object saves document key information during collection data
- // validation and then compares against that key information during index data validation.
- // This fail point is placed in between them, in an attempt to catch any inconsistencies
- // that concurrent CRUD ops might cause if we were to have a bug.
- //
- // Only useful for background validation because we hold an intent lock instead of an
- // exclusive lock, and thus allow concurrent operations.
- if (MONGO_FAIL_POINT(pauseCollectionValidationWithLock)) {
- invariant(opCtx->lockState()->isCollectionLockedForMode(collection->ns(), MODE_IX));
- _validationIsPausedForTest.store(true);
- log() << "Failpoint 'pauseCollectionValidationWithLock' activated.";
- MONGO_FAIL_POINT_PAUSE_WHILE_SET(pauseCollectionValidationWithLock);
- _validationIsPausedForTest.store(false);
- }
-
- // Validate indexes and check for mismatches.
- if (results->valid) {
- _validateIndexes(opCtx,
- collection->getIndexCatalog(),
- &keysPerIndex,
- &indexValidator,
- level,
- indexCursors,
- numIndexKeysPerIndex,
- &indexNsResultsMap,
- results);
-
- if (indexConsistency.haveEntryMismatch()) {
- log(LogComponent::kIndex)
- << "Index inconsistencies were detected on collection " << collection->ns()
- << ". Starting the second phase of index validation to gather concise errors.";
- _gatherIndexEntryErrors(opCtx,
- collection,
- &indexConsistency,
- &indexValidator,
- firstRecordId,
- traverseRecordStoreCursor,
- seekRecordStoreCursor,
- indexCursors,
- &indexNsResultsMap,
- results);
- }
- }
-
- // Validate index key count.
- if (results->valid) {
- _validateIndexKeyCount(opCtx, collection, &indexValidator, &indexNsResultsMap);
- }
-
- // Report the validation results for the user to see.
- _reportValidationResults(
- opCtx, collection, &indexNsResultsMap, &keysPerIndex, level, results, output);
-
- if (!results->valid) {
- log(LogComponent::kIndex) << "Validation complete for collection " << collection->ns()
- << uuidString << ". Corruption found.";
- } else {
- log(LogComponent::kIndex) << "Validation complete for collection " << collection->ns()
- << uuidString << ". No corruption found.";
- }
- } catch (DBException& e) {
- if (ErrorCodes::isInterruption(e.code())) {
- return e.toStatus();
- }
- string err = str::stream() << "exception during index validation: " << e.toString();
- results->errors.push_back(err);
- results->valid = false;
- }
-
- return Status::OK();
-}
-
-bool getIsValidationPausedForTest() {
- return _validationIsPausedForTest.load();
-}
-
-} // namespace CollectionValidation
-} // namespace mongo