diff options
author | Robert Guo <robert.guo@10gen.com> | 2016-04-12 17:47:30 -0400 |
---|---|---|
committer | Robert Guo <robert.guo@10gen.com> | 2016-04-29 16:07:43 -0400 |
commit | 1d58e42a8a2030d956c972dab20da9c9f01d61bf (patch) | |
tree | 05ab35edcb4dd5f30791261fa9ccee23132418a2 /src | |
parent | 98dacf304edac746ffd4f1820c0065fbf9aec7e3 (diff) | |
download | mongo-1d58e42a8a2030d956c972dab20da9c9f01d61bf.tar.gz |
SERVER-23055 optimize perf of hashtable used by validate()
Diffstat (limited to 'src')
25 files changed, 296 insertions, 386 deletions
diff --git a/src/mongo/db/catalog/collection.cpp b/src/mongo/db/catalog/collection.cpp index 6be536aaf0a..2bb3ae63643 100644 --- a/src/mongo/db/catalog/collection.cpp +++ b/src/mongo/db/catalog/collection.cpp @@ -975,318 +975,315 @@ CollatorInterface* Collection::getDefaultCollator() const { } namespace { -class RecordDataValidateAdaptor : public ValidateAdaptor { -public: - virtual ~RecordDataValidateAdaptor() {} - virtual Status validate(const RecordData& record, size_t* dataSize) { - BSONObj obj = record.toBson(); - const Status status = validateBSON(obj.objdata(), obj.objsize()); - if (status.isOK()) - *dataSize = obj.objsize(); - return status; - } -}; +static const uint32_t kKeyCountTableSize = 1U << 22; -using IndexKeyCountMap = std::unordered_map<uint32_t, uint64_t>; +using IndexKeyCountTable = std::array<uint64_t, kKeyCountTableSize>; using ValidateResultsMap = std::map<std::string, ValidateResults>; -class IndexValidator { +class RecordStoreValidateAdaptor : public ValidateAdaptor { public: - IndexValidator(bool full) : _full(full), _ikc(new IndexKeyCountMap()) {} - - /** - * Create one hash map of all entries for all indexes in a collection. - * This ensures that we only need to do one collection scan when validating - * a document against all the indexes that point to it. - */ - void cacheIndexInfo(OperationContext* txn, - const IndexAccessMethod* iam, - const IndexDescriptor* descriptor, - long long numKeys) { - _keyCounts[descriptor->indexNamespace()] = numKeys; - - if (_full) { - std::unique_ptr<SortedDataInterface::Cursor> cursor = iam->newCursor(txn, true); + RecordStoreValidateAdaptor(OperationContext* txn, + ValidateCmdLevel level, + IndexCatalog* ic, + ValidateResultsMap* irm) + : _txn(txn), _level(level), _indexCatalog(ic), _indexNsResultsMap(irm) { + _ikc = std::unique_ptr<IndexKeyCountTable>(new IndexKeyCountTable()); + } - // Seeking to BSONObj() is equivalent to seeking to the first entry of an index. - for (auto indexEntry = cursor->seek(BSONObj(), true); indexEntry; - indexEntry = cursor->next()) { - uint32_t keyHash = hashIndexEntry(indexEntry->key, indexEntry->loc); - (*_ikc)[keyHash]++; - } + virtual Status validate(const RecordId& recordId, const RecordData& record, size_t* dataSize) { + BSONObj recordBson = record.toBson(); + const Status status = validateBSON(recordBson.objdata(), recordBson.objsize()); + if (status.isOK()) { + *dataSize = recordBson.objsize(); + } else { + return status; } - } - void validateIndexes(OperationContext* txn, - RecordStore* rs, - IndexCatalog& indexCatalog, - ValidateResultsMap& indexDetailNsResultsMap, - ValidateResults* globalResults) { - if (!indexCatalog.haveAnyIndexes()) { - return; + if (_level != kValidateFull || !_indexCatalog->haveAnyIndexes()) { + return status; } - auto documentCursor = rs->getCursor(txn, true); - // Only used to determine if any index validation failed in this function, - // doesn't include any indexes that have already been marked as invalid. - bool allIndexesValid = true; - uint64_t documentCount = 0; - int interruptInterval = 4096; - if (_full) { - while (const auto& document = documentCursor->next()) { - if (!(documentCount % interruptInterval)) - txn->checkForInterrupt(); - documentCount++; - IndexCatalog::IndexIterator i = indexCatalog.getIndexIterator(txn, false); - RecordId documentRecordId = document->id; - - while (i.more()) { - const IndexDescriptor* descriptor = i.next(); - string indexNs = descriptor->indexNamespace(); - ValidateResults& results = indexDetailNsResultsMap[indexNs]; - if (!results.valid) { - // No point doing additional validation if the index is already invalid. - continue; - } - IndexAccessMethod* iam = indexCatalog.getIndex(descriptor); - invariant(iam); - BSONObj documentData = document->data.toBson(); + IndexCatalog::IndexIterator i = _indexCatalog->getIndexIterator(_txn, false); - if (descriptor->isPartial()) { - const IndexCatalogEntry* ice = indexCatalog.getEntry(descriptor); - if (!ice->getFilterExpression()->matchesBSON(documentData)) { - continue; - } - } - BSONObjSet documentKeySet; - iam->getKeys(documentData, &documentKeySet); - - if (documentKeySet.size() > 1) { - if (!descriptor->isMultikey(txn)) { - string msg = str::stream() << "Index " << descriptor->indexName() - << " is not multi-key but has more than one" - << " key in one or more document(s)"; - results.errors.push_back(msg); - results.valid = false; - } - } + while (i.more()) { + const IndexDescriptor* descriptor = i.next(); + const string indexNs = descriptor->indexNamespace(); + ValidateResults& results = (*_indexNsResultsMap)[indexNs]; + if (!results.valid) { + // No point doing additional validation if the index is already invalid. + continue; + } - for (const auto& key : documentKeySet) { - if (key.objsize() >= IndexKeyMaxSize) { - // Index keys >= 1024 bytes are not indexed. - _longKeys[indexNs]++; - continue; - } - uint32_t indexEntryHash = hashIndexEntry(key, documentRecordId); - if (_ikc->find(indexEntryHash) != _ikc->end()) { - (*_ikc)[indexEntryHash]--; - - dassert((*_ikc)[indexEntryHash] >= 0); - if ((*_ikc)[indexEntryHash] == 0) { - _ikc->erase(indexEntryHash); - } - } else { - allIndexesValid = false; - results.valid = false; - } - } + const IndexAccessMethod* iam = _indexCatalog->getIndex(descriptor); + BSONObjSet documentKeySet; + iam->getKeys(recordBson, &documentKeySet); + + if (!descriptor->isMultikey(_txn) && documentKeySet.size() > 1) { + string msg = str::stream() << "Index " << descriptor->indexName() + << " is not multi-key but has more than one" + << " key in one or more document(s)"; + results.errors.push_back(msg); + results.valid = false; + } + + if (descriptor->isPartial()) { + const IndexCatalogEntry* ice = _indexCatalog->getEntry(descriptor); + if (!ice->getFilterExpression()->matchesBSON(recordBson)) { + continue; } } - if (!_ikc->empty()) { - allIndexesValid = false; - for (auto& it : indexDetailNsResultsMap) { - // Marking all indexes as invalid since we don't know which one failed. - ValidateResults& r = it.second; - r.valid = false; + for (const auto& key : documentKeySet) { + if (key.objsize() >= IndexKeyMaxSize) { + // Index keys >= 1024 bytes are not indexed. + _longKeys[indexNs]++; + continue; + } + uint32_t indexEntryHash = hashIndexEntry(key, recordId); + uint64_t& indexEntryCount = (*_ikc)[indexEntryHash]; + + if (indexEntryCount != 0) { + indexEntryCount--; + dassert(indexEntryCount >= 0); + if (indexEntryCount == 0) { + _indexKeyCountTableNumEntries--; + } + } else { + _hasDocWithoutIndexEntry = true; + results.valid = false; } } } + return status; + } - // Validate Index Key Count. - if (allIndexesValid) { - IndexCatalog::IndexIterator i = indexCatalog.getIndexIterator(txn, false); - while (i.more()) { - IndexDescriptor* descriptor = i.next(); - ValidateResults& results = indexDetailNsResultsMap[descriptor->indexNamespace()]; + bool tooManyIndexEntries() const { + return _indexKeyCountTableNumEntries != 0; + } + + bool tooFewIndexEntries() const { + return _hasDocWithoutIndexEntry; + } + + /** + * Create one hash map of all entries for all indexes in a collection. + * This ensures that we only need to do one collection scan when validating + * a document against all the indexes that point to it. + */ + void cacheIndexInfo(const IndexAccessMethod* iam, + const IndexDescriptor* descriptor, + long long numKeys) { + _keyCounts[descriptor->indexNamespace()] = numKeys; - if (results.valid) { - validateIndexKeyCount(txn, descriptor, rs->numRecords(txn), &results); + if (_level == kValidateFull) { + std::unique_ptr<SortedDataInterface::Cursor> cursor = iam->newCursor(_txn, true); + // Seeking to BSONObj() is equivalent to seeking to the first entry of an index. + for (auto indexEntry = cursor->seek(BSONObj(), true); indexEntry; + indexEntry = cursor->next()) { + uint32_t keyHash = hashIndexEntry(indexEntry->key, indexEntry->loc); + if ((*_ikc)[keyHash] == 0) { + _indexKeyCountTableNumEntries++; } - allIndexesValid = results.valid ? allIndexesValid : false; + (*_ikc)[keyHash]++; } } - - if (!allIndexesValid) { - string msg = "One or more indexes contain invalid index entries."; - globalResults->errors.push_back(msg); - } } -private: - bool _full; - std::unique_ptr<IndexKeyCountMap> _ikc; - std::map<string, long long> _longKeys; - std::map<string, long long> _keyCounts; - - void validateIndexKeyCount(OperationContext* txn, - IndexDescriptor* idx, - int64_t numRecs, - ValidateResults* results) { - string indexNs = idx->indexNamespace(); + void validateIndexKeyCount(IndexDescriptor* idx, int64_t numRecs, ValidateResults& results) { + const string indexNs = idx->indexNamespace(); long long numIndexedKeys = _keyCounts[indexNs]; long long numLongKeys = _longKeys[indexNs]; auto totalKeys = numLongKeys + numIndexedKeys; bool hasTooFewKeys = false; + bool noErrorOnTooFewKeys = !failIndexKeyTooLong && (_level != kValidateFull); + if (idx->isIdIndex() && totalKeys != numRecs) { hasTooFewKeys = totalKeys < numRecs ? true : hasTooFewKeys; string msg = str::stream() << "number of _id index entries (" << numIndexedKeys << ") does not match the number of documents in the index (" << numRecs - numLongKeys << ")"; - if (!failIndexKeyTooLong && !_full && (numIndexedKeys < numRecs)) { - results->warnings.push_back(msg); + if (noErrorOnTooFewKeys && (numIndexedKeys < numRecs)) { + results.warnings.push_back(msg); } else { - results->errors.push_back(msg); - results->valid = false; + results.errors.push_back(msg); + results.valid = false; } } - if (results->valid && !idx->isMultikey(txn) && totalKeys > numRecs) { + if (results.valid && !idx->isMultikey(_txn) && totalKeys > numRecs) { string err = str::stream() << "index " << idx->indexName() << " is not multi-key, but has more entries (" << numIndexedKeys << ") than documents in the index (" << numRecs - numLongKeys << ")"; - results->errors.push_back(err); - results->valid = false; + results.errors.push_back(err); + results.valid = false; } - // Ensure normal indexes have at least as many keys as the number of documents in the - // collection. - if (results->valid && !idx->isSparse() && !idx->isPartial() && !idx->isIdIndex() && + // Ignore any indexes with a special access method. If an access method name is given, the + // index may be a full text, geo or special index plugin with different semantics. + if (results.valid && !idx->isSparse() && !idx->isPartial() && !idx->isIdIndex() && idx->getAccessMethodName() == "" && totalKeys < numRecs) { hasTooFewKeys = true; string msg = str::stream() << "index " << idx->indexName() << " is not sparse or partial, but has fewer entries (" << numIndexedKeys << ") than documents in the index (" << numRecs - numLongKeys << ")"; - if (!failIndexKeyTooLong && !_full) { - results->warnings.push_back(msg); + if (noErrorOnTooFewKeys) { + results.warnings.push_back(msg); } else { - results->errors.push_back(msg); - results->valid = false; + results.errors.push_back(msg); + results.valid = false; } } - if (!_full && hasTooFewKeys) { + if ((_level != kValidateFull) && hasTooFewKeys) { string warning = str::stream() << "index " << idx->indexName() << " has fewer keys than records. This may be the result of currently or " "previously running the server with the failIndexKeyTooLong parameter set to " "false. Please re-run the validate command with {full: true}"; - results->warnings.push_back(warning); + results.warnings.push_back(warning); } } - uint32_t hashIndexEntry(const BSONObj& key, RecordId& loc) { +private: + std::map<string, long long> _longKeys; + std::map<string, long long> _keyCounts; + std::unique_ptr<IndexKeyCountTable> _ikc; + + uint32_t _indexKeyCountTableNumEntries = 0; + bool _hasDocWithoutIndexEntry = false; + + OperationContext* _txn; // Not owned. + ValidateCmdLevel _level; + IndexCatalog* _indexCatalog; // Not owned. + ValidateResultsMap* _indexNsResultsMap; // Not owned. + + uint32_t hashIndexEntry(const BSONObj& key, const RecordId& loc) { uint32_t hash; // We're only using KeyString to get something hashable here, so version doesn't matter. KeyString ks(KeyString::Version::V1, key, Ordering::make(BSONObj()), loc); MurmurHash3_x86_32(ks.getTypeBits().getBuffer(), ks.getTypeBits().getSize(), 0, &hash); MurmurHash3_x86_32(ks.getBuffer(), ks.getSize(), hash, &hash); - // Take the first 25 bits to conserve memory. - return hash >> 7; + return hash % kKeyCountTableSize; } }; } // namespace Status Collection::validate(OperationContext* txn, - bool full, - bool scanData, + ValidateCmdLevel level, ValidateResults* results, BSONObjBuilder* output) { dassert(txn->lockState()->isCollectionLockedForMode(ns().toString(), MODE_IS)); - RecordDataValidateAdaptor adaptor; - Status status = _recordStore->validate(txn, full, scanData, &adaptor, results, output); - if (!status.isOK()) - return status; + try { + ValidateResultsMap indexNsResultsMap; + std::unique_ptr<RecordStoreValidateAdaptor> indexValidator( + new RecordStoreValidateAdaptor(txn, level, &_indexCatalog, &indexNsResultsMap)); + + BSONObjBuilder keysPerIndex; // not using subObjStart to be exception safe + IndexCatalog::IndexIterator i = _indexCatalog.getIndexIterator(txn, false); + + // Validate Indexes. + while (i.more()) { + txn->checkForInterrupt(); + const IndexDescriptor* descriptor = i.next(); + log(LogComponent::kIndex) << "validating index " << descriptor->indexNamespace() + << endl; + IndexAccessMethod* iam = _indexCatalog.getIndex(descriptor); + ValidateResults curIndexResults; + int64_t numKeys; + iam->validate(txn, &numKeys, &curIndexResults); + keysPerIndex.appendNumber(descriptor->indexNamespace(), + static_cast<long long>(numKeys)); + + indexNsResultsMap[descriptor->indexNamespace()] = curIndexResults; + if (curIndexResults.valid) { + indexValidator->cacheIndexInfo(iam, descriptor, numKeys); + } else { + results->valid = false; + } + } + + // Validate RecordStore and, if `level == kValidateFull`, cross validate indexes and + // RecordStore. + if (results->valid) { + auto status = _recordStore->validate(txn, level, indexValidator.get(), results, output); + // RecordStore::validate always returns Status::OK(). Errors are reported through + // `results`. + dassert(status.isOK()); - { // indexes - int idxn = 0; - try { - // Only applicable when 'full' validation is requested. - std::unique_ptr<BSONObjBuilder> indexDetails(full ? new BSONObjBuilder() : NULL); - std::unique_ptr<IndexValidator> indexValidator(new IndexValidator(full)); - ValidateResultsMap indexDetailNsResultsMap; - BSONObjBuilder keysPerIndex; // not using subObjStart to be exception safe + if (indexValidator->tooManyIndexEntries()) { + for (auto& it : indexNsResultsMap) { + // Marking all indexes as invalid since we don't know which one failed. + ValidateResults& r = it.second; + r.valid = false; + } + string msg = "One or more indexes contain invalid index entries."; + results->errors.push_back(msg); + results->valid = false; + } else if (indexValidator->tooFewIndexEntries()) { + results->valid = false; + } + } + // Validate index key count. + if (results->valid) { IndexCatalog::IndexIterator i = _indexCatalog.getIndexIterator(txn, false); while (i.more()) { - txn->checkForInterrupt(); - const IndexDescriptor* descriptor = i.next(); - log(LogComponent::kIndex) << "validating index " << descriptor->indexNamespace() - << endl; - IndexAccessMethod* iam = _indexCatalog.getIndex(descriptor); - invariant(iam); - - ValidateResults curIndexResults; - int64_t numKeys; - iam->validate(txn, full, &numKeys, &curIndexResults); - keysPerIndex.appendNumber(descriptor->indexNamespace(), - static_cast<long long>(numKeys)); - - indexDetailNsResultsMap[descriptor->indexNamespace()] = curIndexResults; + IndexDescriptor* descriptor = i.next(); + ValidateResults& curIndexResults = indexNsResultsMap[descriptor->indexNamespace()]; + if (curIndexResults.valid) { - indexValidator->cacheIndexInfo(txn, iam, descriptor, numKeys); + indexValidator->validateIndexKeyCount( + descriptor, _recordStore->numRecords(txn), curIndexResults); } - - idxn++; } + } - indexValidator->validateIndexes( - txn, _recordStore, _indexCatalog, indexDetailNsResultsMap, results); + std::unique_ptr<BSONObjBuilder> indexDetails(level == kValidateFull ? new BSONObjBuilder() + : NULL); - for (auto& it : indexDetailNsResultsMap) { - std::string indexNs = it.first; - ValidateResults& vr = it.second; + // Report index validation results. + for (const auto& it : indexNsResultsMap) { + const std::string indexNs = it.first; + const ValidateResults& vr = it.second; - if (indexDetails.get()) { - BSONObjBuilder bob(indexDetails->subobjStart(indexNs)); - bob.appendBool("valid", vr.valid); + if (!vr.valid) { + results->valid = false; + } - if (!vr.warnings.empty()) { - bob.append("warnings", vr.warnings); - } + if (indexDetails.get()) { + BSONObjBuilder bob(indexDetails->subobjStart(indexNs)); + bob.appendBool("valid", vr.valid); - if (!vr.errors.empty()) { - bob.append("errors", vr.errors); - } + if (!vr.warnings.empty()) { + bob.append("warnings", vr.warnings); } - results->warnings.insert( - results->warnings.end(), vr.warnings.begin(), vr.warnings.end()); - results->errors.insert(results->errors.end(), vr.errors.begin(), vr.errors.end()); - - if (!vr.valid) { - results->valid = false; + if (!vr.errors.empty()) { + bob.append("errors", vr.errors); } } - output->append("nIndexes", _indexCatalog.numIndexesReady(txn)); - output->append("keysPerIndex", keysPerIndex.done()); - if (indexDetails.get()) { - output->append("indexDetails", indexDetails->done()); - } - } catch (DBException& e) { - if (ErrorCodes::isInterruption(ErrorCodes::Error(e.getCode()))) { - return e.toStatus(); - } - string err = str::stream() << "exception during index validate idxn " - << BSONObjBuilder::numStr(idxn) << ": " << e.toString(); - results->errors.push_back(err); - results->valid = false; + 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", _indexCatalog.numIndexesReady(txn)); + output->append("keysPerIndex", keysPerIndex.done()); + if (indexDetails.get()) { + output->append("indexDetails", indexDetails->done()); + } + } catch (DBException& e) { + if (ErrorCodes::isInterruption(ErrorCodes::Error(e.getCode()))) { + return e.toStatus(); } + string err = str::stream() << "exception during index validation: " << e.toString(); + results->errors.push_back(err); + results->valid = false; } return Status::OK(); diff --git a/src/mongo/db/catalog/collection.h b/src/mongo/db/catalog/collection.h index 4720c980b9b..b718413e161 100644 --- a/src/mongo/db/catalog/collection.h +++ b/src/mongo/db/catalog/collection.h @@ -346,15 +346,12 @@ public: Status truncate(OperationContext* txn); /** - * @param full - does more checks - * @param scanData - scans each document * @return OK if the validate run successfully * OK will be returned even if corruption is found * deatils will be in result */ Status validate(OperationContext* txn, - bool full, - bool scanData, + ValidateCmdLevel level, ValidateResults* results, BSONObjBuilder* output); diff --git a/src/mongo/db/commands/validate.cpp b/src/mongo/db/commands/validate.cpp index 0037eba6d58..0357a0f7bd3 100644 --- a/src/mongo/db/commands/validate.cpp +++ b/src/mongo/db/commands/validate.cpp @@ -37,6 +37,7 @@ #include "mongo/db/commands.h" #include "mongo/db/db_raii.h" #include "mongo/db/query/internal_plans.h" +#include "mongo/db/storage/record_store.h" #include "mongo/util/fail_point_service.h" #include "mongo/util/log.h" @@ -90,7 +91,15 @@ public: NamespaceString ns_string(ns); const bool full = cmdObj["full"].trueValue(); - const bool scanData = full || cmdObj["scandata"].trueValue(); + const bool scanData = cmdObj["scandata"].trueValue(); + + ValidateCmdLevel level = kValidateIndex; + + if (full) { + level = kValidateFull; + } else if (scanData) { + level = kValidateRecordStore; + } if (!ns_string.isNormal() && full) { errmsg = "Can only run full validate on a regular collection"; @@ -112,7 +121,7 @@ public: result.append("ns", ns); ValidateResults results; - Status status = collection->validate(txn, full, scanData, &results, &result); + Status status = collection->validate(txn, level, &results, &result); if (!status.isOK()) return appendCommandStatus(result, status); diff --git a/src/mongo/db/index/index_access_method.cpp b/src/mongo/db/index/index_access_method.cpp index b10bc6add71..e579d13aacb 100644 --- a/src/mongo/db/index/index_access_method.cpp +++ b/src/mongo/db/index/index_access_method.cpp @@ -249,11 +249,10 @@ RecordId IndexAccessMethod::findSingle(OperationContext* txn, const BSONObj& key } Status IndexAccessMethod::validate(OperationContext* txn, - bool full, int64_t* numKeys, ValidateResults* fullResults) { long long keys = 0; - _newInterface->fullValidate(txn, full, &keys, fullResults); + _newInterface->fullValidate(txn, &keys, fullResults); *numKeys = keys; return Status::OK(); } diff --git a/src/mongo/db/index/index_access_method.h b/src/mongo/db/index/index_access_method.h index 1509500d916..0aa16b791fe 100644 --- a/src/mongo/db/index/index_access_method.h +++ b/src/mongo/db/index/index_access_method.h @@ -163,19 +163,10 @@ public: /** * Walk the entire index, checking the internal structure for consistency. * Set numKeys to the number of keys in the index. - * - * 'output' is used to store results of validate when 'full' is true. - * If 'full' is false, 'output' may be NULL. - * + * Return OK if the index is valid. - * - * Currently wasserts that the index is invalid. This could/should be changed in - * the future to return a Status. */ - Status validate(OperationContext* txn, - bool full, - int64_t* numKeys, - ValidateResults* fullResults); + Status validate(OperationContext* txn, int64_t* numKeys, ValidateResults* fullResults); /** * Add custom statistics about this index to BSON object builder, for display. diff --git a/src/mongo/db/storage/devnull/devnull_kv_engine.cpp b/src/mongo/db/storage/devnull/devnull_kv_engine.cpp index 3ff3ae5ce96..65a16414dcc 100644 --- a/src/mongo/db/storage/devnull/devnull_kv_engine.cpp +++ b/src/mongo/db/storage/devnull/devnull_kv_engine.cpp @@ -145,8 +145,7 @@ public: virtual void temp_cappedTruncateAfter(OperationContext* txn, RecordId end, bool inclusive) {} virtual Status validate(OperationContext* txn, - bool full, - bool scanData, + ValidateCmdLevel level, ValidateAdaptor* adaptor, ValidateResults* results, BSONObjBuilder* output) { @@ -209,7 +208,6 @@ public: } virtual void fullValidate(OperationContext* txn, - bool full, long long* numKeysOut, ValidateResults* fullResults) const {} diff --git a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp index b34318b5ab8..a308b6d7984 100644 --- a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp +++ b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp @@ -189,7 +189,6 @@ public: } virtual void fullValidate(OperationContext* txn, - bool full, long long* numKeysOut, ValidateResults* fullResults) const { // TODO check invariants? diff --git a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_record_store.cpp b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_record_store.cpp index 7fa168612b0..ddee4d85a75 100644 --- a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_record_store.cpp +++ b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_record_store.cpp @@ -525,18 +525,17 @@ void EphemeralForTestRecordStore::temp_cappedTruncateAfter(OperationContext* txn } Status EphemeralForTestRecordStore::validate(OperationContext* txn, - bool full, - bool scanData, + ValidateCmdLevel level, ValidateAdaptor* adaptor, ValidateResults* results, BSONObjBuilder* output) { results->valid = true; - if (scanData && full) { + if (level == kValidateFull) { for (Records::const_iterator it = _data->records.begin(); it != _data->records.end(); ++it) { const EphemeralForTestRecord& rec = it->second; size_t dataSize; - const Status status = adaptor->validate(rec.toRecordData(), &dataSize); + const Status status = adaptor->validate(it->first, rec.toRecordData(), &dataSize); if (!status.isOK()) { results->valid = false; results->errors.push_back("invalid object detected (see logs)"); diff --git a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_record_store.h b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_record_store.h index 8f83cfe9dfd..8df67ece618 100644 --- a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_record_store.h +++ b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_record_store.h @@ -92,8 +92,7 @@ public: virtual void temp_cappedTruncateAfter(OperationContext* txn, RecordId end, bool inclusive); virtual Status validate(OperationContext* txn, - bool full, - bool scanData, + ValidateCmdLevel level, ValidateAdaptor* adaptor, ValidateResults* results, BSONObjBuilder* output); diff --git a/src/mongo/db/storage/mmap_v1/btree/btree_interface.cpp b/src/mongo/db/storage/mmap_v1/btree/btree_interface.cpp index cea3a8b4d91..cdb1bf05583 100644 --- a/src/mongo/db/storage/mmap_v1/btree/btree_interface.cpp +++ b/src/mongo/db/storage/mmap_v1/btree/btree_interface.cpp @@ -96,7 +96,6 @@ public: } virtual void fullValidate(OperationContext* txn, - bool full, long long* numKeysOut, ValidateResults* fullResults) const { *numKeysOut = _btree->fullValidate(txn, NULL, false, false, 0); diff --git a/src/mongo/db/storage/mmap_v1/heap_record_store_btree.h b/src/mongo/db/storage/mmap_v1/heap_record_store_btree.h index 4e984a4469d..32dec97358e 100644 --- a/src/mongo/db/storage/mmap_v1/heap_record_store_btree.h +++ b/src/mongo/db/storage/mmap_v1/heap_record_store_btree.h @@ -114,8 +114,7 @@ public: } virtual Status validate(OperationContext* txn, - bool full, - bool scanData, + ValidateCmdLevel level, ValidateAdaptor* adaptor, ValidateResults* results, BSONObjBuilder* output) { diff --git a/src/mongo/db/storage/mmap_v1/record_store_v1_base.cpp b/src/mongo/db/storage/mmap_v1/record_store_v1_base.cpp index f5089ef787f..790f35e98c2 100644 --- a/src/mongo/db/storage/mmap_v1/record_store_v1_base.cpp +++ b/src/mongo/db/storage/mmap_v1/record_store_v1_base.cpp @@ -539,8 +539,7 @@ void RecordStoreV1Base::increaseStorageSize(OperationContext* txn, int size, boo } Status RecordStoreV1Base::validate(OperationContext* txn, - bool full, - bool scanData, + ValidateCmdLevel level, ValidateAdaptor* adaptor, ValidateResults* results, BSONObjBuilder* output) { @@ -591,7 +590,7 @@ Status RecordStoreV1Base::validate(OperationContext* txn, extentDiskLoc = _details->firstExtent(txn); while (!extentDiskLoc.isNull()) { Extent* thisExtent = _getExtent(txn, extentDiskLoc); - if (full) { + if (level == kValidateFull) { extentData << thisExtent->dump(); } if (!thisExtent->validates(extentDiskLoc, &results->errors)) { @@ -628,7 +627,7 @@ Status RecordStoreV1Base::validate(OperationContext* txn, } output->append("extentCount", extentCount); - if (full) + if (level == kValidateFull) output->appendArray("extents", extentData.arr()); } @@ -678,7 +677,7 @@ Status RecordStoreV1Base::validate(OperationContext* txn, // 4444444444444444444444444 set<DiskLoc> recs; - if (scanData) { + if (level == kValidateRecordStore || level == kValidateFull) { int n = 0; int nInvalid = 0; long long nQuantizedSize = 0; @@ -711,9 +710,10 @@ Status RecordStoreV1Base::validate(OperationContext* txn, ++nQuantizedSize; } - if (full) { + if (level == kValidateFull) { size_t dataSize = 0; - const Status status = adaptor->validate(r->toRecordData(), &dataSize); + const Status status = + adaptor->validate(record->id, r->toRecordData(), &dataSize); if (!status.isOK()) { results->valid = false; if (nInvalid == 0) // only log once; @@ -736,7 +736,7 @@ Status RecordStoreV1Base::validate(OperationContext* txn, } output->append("objectsFound", n); - if (full) { + if (level == kValidateFull) { output->append("invalidObjects", nInvalid); } @@ -744,7 +744,7 @@ Status RecordStoreV1Base::validate(OperationContext* txn, output->appendNumber("bytesWithHeaders", len); output->appendNumber("bytesWithoutHeaders", nlen); - if (full) { + if (level == kValidateFull) { output->appendNumber("bytesBson", bsonLen); } } // end scanData @@ -799,7 +799,7 @@ Status RecordStoreV1Base::validate(OperationContext* txn, } output->appendNumber("deletedCount", ndel); output->appendNumber("deletedSize", delSize); - if (full) { + if (level == kValidateFull) { output->append("delBucketSizes", delBucketSizes.arr()); } diff --git a/src/mongo/db/storage/mmap_v1/record_store_v1_base.h b/src/mongo/db/storage/mmap_v1/record_store_v1_base.h index 4520256f901..c9ee22a40da 100644 --- a/src/mongo/db/storage/mmap_v1/record_store_v1_base.h +++ b/src/mongo/db/storage/mmap_v1/record_store_v1_base.h @@ -219,8 +219,7 @@ public: void increaseStorageSize(OperationContext* txn, int size, bool enforceQuota); virtual Status validate(OperationContext* txn, - bool full, - bool scanData, + ValidateCmdLevel level, ValidateAdaptor* adaptor, ValidateResults* results, BSONObjBuilder* output); diff --git a/src/mongo/db/storage/record_store.h b/src/mongo/db/storage/record_store.h index 64f93e50c62..ea0ad7c69b7 100644 --- a/src/mongo/db/storage/record_store.h +++ b/src/mongo/db/storage/record_store.h @@ -92,6 +92,13 @@ struct BsonRecord { const BSONObj* docPtr; }; +enum ValidateCmdLevel : int { + kValidateIndex = 0x01, + kValidateRecordStore = 0x02, + kValidateFull = 0x03 +}; + + /** * Retrieves Records from a RecordStore. * @@ -517,15 +524,12 @@ public: } /** - * @param full - does more checks - * @param scanData - scans each document * @return OK if the validate run successfully * OK will be returned even if corruption is found * deatils will be in result */ virtual Status validate(OperationContext* txn, - bool full, - bool scanData, + ValidateCmdLevel level, ValidateAdaptor* adaptor, ValidateResults* results, BSONObjBuilder* output) = 0; @@ -613,6 +617,8 @@ class ValidateAdaptor { public: virtual ~ValidateAdaptor() {} - virtual Status validate(const RecordData& recordData, size_t* dataSize) = 0; + virtual Status validate(const RecordId& recordId, + const RecordData& recordData, + size_t* dataSize) = 0; }; } diff --git a/src/mongo/db/storage/record_store_test_validate.cpp b/src/mongo/db/storage/record_store_test_validate.cpp index 71790a376a3..d55d8229526 100644 --- a/src/mongo/db/storage/record_store_test_validate.cpp +++ b/src/mongo/db/storage/record_store_test_validate.cpp @@ -42,8 +42,6 @@ namespace mongo { namespace { // Verify that calling validate() on an empty collection returns an OK status. -// When either of `full` or `scanData` are false, the ValidateAdaptor -// should not be used. TEST(RecordStoreTestHarness, ValidateEmpty) { unique_ptr<HarnessHelper> harnessHelper(newHarnessHelper()); unique_ptr<RecordStore> rs(harnessHelper->newNonCappedRecordStore()); @@ -59,12 +57,7 @@ TEST(RecordStoreTestHarness, ValidateEmpty) { ValidateAdaptorSpy adaptor; ValidateResults results; BSONObjBuilder stats; - ASSERT_OK(rs->validate(opCtx.get(), - false, // full validate - false, // scan data - &adaptor, - &results, - &stats)); + ASSERT_OK(rs->validate(opCtx.get(), kValidateIndex, &adaptor, &results, &stats)); ASSERT(results.valid); ASSERT(results.errors.empty()); } @@ -72,8 +65,6 @@ TEST(RecordStoreTestHarness, ValidateEmpty) { } // Verify that calling validate() on an empty collection returns an OK status. -// When either of `full` or `scanData` are false, the ValidateAdaptor -// should not be used. TEST(RecordStoreTestHarness, ValidateEmptyAndScanData) { unique_ptr<HarnessHelper> harnessHelper(newHarnessHelper()); unique_ptr<RecordStore> rs(harnessHelper->newNonCappedRecordStore()); @@ -89,42 +80,7 @@ TEST(RecordStoreTestHarness, ValidateEmptyAndScanData) { ValidateAdaptorSpy adaptor; ValidateResults results; BSONObjBuilder stats; - ASSERT_OK(rs->validate(opCtx.get(), - false, // full validate - true, // scan data - &adaptor, - &results, - &stats)); - ASSERT(results.valid); - ASSERT(results.errors.empty()); - } - } -} - -// Verify that calling validate() on an empty collection returns an OK status. -// When either of `full` or `scanData` are false, the ValidateAdaptor -// should not be used. -TEST(RecordStoreTestHarness, FullValidateEmpty) { - unique_ptr<HarnessHelper> harnessHelper(newHarnessHelper()); - unique_ptr<RecordStore> rs(harnessHelper->newNonCappedRecordStore()); - - { - unique_ptr<OperationContext> opCtx(harnessHelper->newOperationContext()); - ASSERT_EQUALS(0, rs->numRecords(opCtx.get())); - } - - { - unique_ptr<OperationContext> opCtx(harnessHelper->newOperationContext()); - { - ValidateAdaptorSpy adaptor; - ValidateResults results; - BSONObjBuilder stats; - ASSERT_OK(rs->validate(opCtx.get(), - true, // full validate - false, // scan data - &adaptor, - &results, - &stats)); + ASSERT_OK(rs->validate(opCtx.get(), kValidateRecordStore, &adaptor, &results, &stats)); ASSERT(results.valid); ASSERT(results.errors.empty()); } @@ -147,12 +103,7 @@ TEST(RecordStoreTestHarness, FullValidateEmptyAndScanData) { ValidateAdaptorSpy adaptor; ValidateResults results; BSONObjBuilder stats; - ASSERT_OK(rs->validate(opCtx.get(), - true, // full validate - true, // scan data - &adaptor, - &results, - &stats)); + ASSERT_OK(rs->validate(opCtx.get(), kValidateFull, &adaptor, &results, &stats)); ASSERT(results.valid); ASSERT(results.errors.empty()); } @@ -160,8 +111,7 @@ TEST(RecordStoreTestHarness, FullValidateEmptyAndScanData) { } // Insert multiple records, and verify that calling validate() on a nonempty collection -// returns an OK status. When either of `full` or `scanData` are false, the ValidateAdaptor -// should not be used. +// returns an OK status. TEST_F(ValidateTest, ValidateNonEmpty) { { unique_ptr<OperationContext> opCtx(newOperationContext()); @@ -169,12 +119,8 @@ TEST_F(ValidateTest, ValidateNonEmpty) { ValidateAdaptorSpy adaptor; ValidateResults results; BSONObjBuilder stats; - ASSERT_OK(getRecordStore().validate(opCtx.get(), - false, // full validate - false, // scan data - &adaptor, - &results, - &stats)); + ASSERT_OK( + getRecordStore().validate(opCtx.get(), kValidateIndex, &adaptor, &results, &stats)); ASSERT(results.valid); ASSERT(results.errors.empty()); } @@ -182,8 +128,7 @@ TEST_F(ValidateTest, ValidateNonEmpty) { } // Insert multiple records, and verify that calling validate() on a nonempty collection -// returns an OK status. When either of `full` or `scanData` are false, the ValidateAdaptor -// should not be used. +// returns an OK status. TEST_F(ValidateTest, ValidateAndScanDataNonEmpty) { { unique_ptr<OperationContext> opCtx(newOperationContext()); @@ -191,34 +136,8 @@ TEST_F(ValidateTest, ValidateAndScanDataNonEmpty) { ValidateAdaptorSpy adaptor; ValidateResults results; BSONObjBuilder stats; - ASSERT_OK(getRecordStore().validate(opCtx.get(), - false, // full validate - true, // scan data - &adaptor, - &results, - &stats)); - ASSERT(results.valid); - ASSERT(results.errors.empty()); - } - } -} - -// Insert multiple records, and verify that calling validate() on a nonempty collection -// returns an OK status. When either of `full` or `scanData` are false, the ValidateAdaptor -// should not be used. -TEST_F(ValidateTest, FullValidateNonEmpty) { - { - unique_ptr<OperationContext> opCtx(newOperationContext()); - { - ValidateAdaptorSpy adaptor; - ValidateResults results; - BSONObjBuilder stats; - ASSERT_OK(getRecordStore().validate(opCtx.get(), - true, // full validate - false, // scan data - &adaptor, - &results, - &stats)); + ASSERT_OK(getRecordStore().validate( + opCtx.get(), kValidateRecordStore, &adaptor, &results, &stats)); ASSERT(results.valid); ASSERT(results.errors.empty()); } @@ -234,12 +153,8 @@ TEST_F(ValidateTest, FullValidateNonEmptyAndScanData) { ValidateAdaptorSpy adaptor(getInsertedRecords()); ValidateResults results; BSONObjBuilder stats; - ASSERT_OK(getRecordStore().validate(opCtx.get(), - true, // full validate - true, // scan data - &adaptor, - &results, - &stats)); + ASSERT_OK( + getRecordStore().validate(opCtx.get(), kValidateFull, &adaptor, &results, &stats)); ASSERT(adaptor.allValidated()); ASSERT(results.valid); ASSERT(results.errors.empty()); diff --git a/src/mongo/db/storage/record_store_test_validate.h b/src/mongo/db/storage/record_store_test_validate.h index b5a73e041fa..3ef5bcdd368 100644 --- a/src/mongo/db/storage/record_store_test_validate.h +++ b/src/mongo/db/storage/record_store_test_validate.h @@ -47,7 +47,7 @@ public: ~ValidateAdaptorSpy() {} - Status validate(const RecordData& recordData, size_t* dataSize) { + Status validate(const RecordId& recordId, const RecordData& recordData, size_t* dataSize) { std::string s(recordData.data()); ASSERT(1 == _remain.erase(s)); diff --git a/src/mongo/db/storage/sorted_data_interface.h b/src/mongo/db/storage/sorted_data_interface.h index eeefb10d5ea..d21fb6e3c8f 100644 --- a/src/mongo/db/storage/sorted_data_interface.h +++ b/src/mongo/db/storage/sorted_data_interface.h @@ -135,13 +135,9 @@ public: // /** - * 'output' is used to store results of validate when 'full' is true. - * If 'full' is false, 'output' may be NULL. - * * TODO: expose full set of args for testing? */ virtual void fullValidate(OperationContext* txn, - bool full, long long* numKeysOut, ValidateResults* fullResults) const = 0; @@ -185,7 +181,7 @@ public: */ virtual long long numEntries(OperationContext* txn) const { long long x = -1; - fullValidate(txn, false, &x, NULL); + fullValidate(txn, &x, NULL); return x; } diff --git a/src/mongo/db/storage/sorted_data_interface_test_fullvalidate.cpp b/src/mongo/db/storage/sorted_data_interface_test_fullvalidate.cpp index 6f1b4575a09..98bb9936da9 100644 --- a/src/mongo/db/storage/sorted_data_interface_test_fullvalidate.cpp +++ b/src/mongo/db/storage/sorted_data_interface_test_fullvalidate.cpp @@ -68,7 +68,7 @@ TEST(SortedDataInterface, FullValidate) { { long long numKeysOut; const std::unique_ptr<OperationContext> opCtx(harnessHelper->newOperationContext()); - sorted->fullValidate(opCtx.get(), false, &numKeysOut, NULL); + sorted->fullValidate(opCtx.get(), &numKeysOut, NULL); // fullValidate() can set numKeysOut as the number of existing keys or -1. ASSERT(numKeysOut == nToInsert || numKeysOut == -1); } diff --git a/src/mongo/db/storage/sorted_data_interface_test_harness.cpp b/src/mongo/db/storage/sorted_data_interface_test_harness.cpp index e184b88382f..8506af3e43e 100644 --- a/src/mongo/db/storage/sorted_data_interface_test_harness.cpp +++ b/src/mongo/db/storage/sorted_data_interface_test_harness.cpp @@ -94,7 +94,7 @@ TEST(SortedDataInterface, InsertWithDups1) { ASSERT_EQUALS(2, sorted->numEntries(opCtx.get())); long long x = 0; - sorted->fullValidate(opCtx.get(), false, &x, NULL); + sorted->fullValidate(opCtx.get(), &x, NULL); ASSERT_EQUALS(2, x); } } diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp index 283eca55364..c0b04a41759 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp @@ -266,7 +266,6 @@ void WiredTigerIndex::unindex(OperationContext* txn, } void WiredTigerIndex::fullValidate(OperationContext* txn, - bool full, long long* numKeysOut, ValidateResults* fullResults) const { if (fullResults && !WiredTigerRecoveryUnit::get(txn)->getSessionCache()->isEphemeral()) { diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_index.h b/src/mongo/db/storage/wiredtiger/wiredtiger_index.h index f989f0b1ce5..c2d6c70cf12 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_index.h +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_index.h @@ -91,7 +91,6 @@ public: bool dupsAllowed); virtual void fullValidate(OperationContext* txn, - bool full, long long* numKeysOut, ValidateResults* fullResults) const; virtual bool appendCustomStats(OperationContext* txn, diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp index 636f2d86ffd..87fd30bb27d 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp @@ -1494,8 +1494,7 @@ Status WiredTigerRecordStore::compact(OperationContext* txn, } Status WiredTigerRecordStore::validate(OperationContext* txn, - bool full, - bool scanData, + ValidateCmdLevel level, ValidateAdaptor* adaptor, ValidateResults* results, BSONObjBuilder* output) { @@ -1528,9 +1527,9 @@ Status WiredTigerRecordStore::validate(OperationContext* txn, ++nrecords; auto dataSize = record->data.size(); dataSizeTotal += dataSize; - if (full && scanData) { + if (level == kValidateFull) { size_t validatedSize; - Status status = adaptor->validate(record->data, &validatedSize); + Status status = adaptor->validate(record->id, record->data, &validatedSize); // The validatedSize equals dataSize below is not a general requirement, but must be // true for WT today because we never pad records. diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h index 9e7cc01f276..3ef4626d206 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h @@ -170,8 +170,7 @@ public: CompactStats* stats); virtual Status validate(OperationContext* txn, - bool full, - bool scanData, + ValidateCmdLevel level, ValidateAdaptor* adaptor, ValidateResults* results, BSONObjBuilder* output); diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp index e09ccdf3e65..37d64e8bd00 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp @@ -386,7 +386,7 @@ namespace { class GoodValidateAdaptor : public ValidateAdaptor { public: - virtual Status validate(const RecordData& record, size_t* dataSize) { + virtual Status validate(const RecordId& recordId, const RecordData& record, size_t* dataSize) { *dataSize = static_cast<size_t>(record.size()); return Status::OK(); } @@ -394,7 +394,7 @@ public: class BadValidateAdaptor : public ValidateAdaptor { public: - virtual Status validate(const RecordData& record, size_t* dataSize) { + virtual Status validate(const RecordId& recordId, const RecordData& record, size_t* dataSize) { *dataSize = static_cast<size_t>(record.size()); return Status(ErrorCodes::UnknownError, ""); } @@ -463,7 +463,7 @@ TEST_F(SizeStorerValidateTest, Basic) { unique_ptr<OperationContext> opCtx(harnessHelper->newOperationContext()); ValidateResults results; BSONObjBuilder output; - ASSERT_OK(rs->validate(opCtx.get(), false, false, NULL, &results, &output)); + ASSERT_OK(rs->validate(opCtx.get(), kValidateIndex, NULL, &results, &output)); BSONObj obj = output.obj(); ASSERT_EQUALS(expectedNumRecords, obj.getIntField("nrecords")); ASSERT_EQUALS(expectedNumRecords, getNumRecords()); @@ -476,20 +476,31 @@ TEST_F(SizeStorerValidateTest, FullWithGoodAdaptor) { GoodValidateAdaptor adaptor; ValidateResults results; BSONObjBuilder output; - ASSERT_OK(rs->validate(opCtx.get(), true, true, &adaptor, &results, &output)); + ASSERT_OK(rs->validate(opCtx.get(), kValidateFull, &adaptor, &results, &output)); BSONObj obj = output.obj(); ASSERT_EQUALS(expectedNumRecords, obj.getIntField("nrecords")); ASSERT_EQUALS(expectedNumRecords, getNumRecords()); ASSERT_EQUALS(expectedDataSize, getDataSize()); } +// Basic validation does not use the validation adaptor. So passing a bad adaptor +// should not cause validate to fail. +TEST_F(SizeStorerValidateTest, BasicWithBadAdapter) { + unique_ptr<OperationContext> opCtx(harnessHelper->newOperationContext()); + BadValidateAdaptor adaptor; + ValidateResults results; + BSONObjBuilder output; + ASSERT_OK(rs->validate(opCtx.get(), kValidateIndex, &adaptor, &results, &output)); + ASSERT_EQUALS(true, results.valid); +} + // Full validation with a validation adaptor that fails - size storer data is not updated. TEST_F(SizeStorerValidateTest, FullWithBadAdapter) { unique_ptr<OperationContext> opCtx(harnessHelper->newOperationContext()); BadValidateAdaptor adaptor; ValidateResults results; BSONObjBuilder output; - ASSERT_OK(rs->validate(opCtx.get(), true, true, &adaptor, &results, &output)); + ASSERT_OK(rs->validate(opCtx.get(), kValidateFull, &adaptor, &results, &output)); BSONObj obj = output.obj(); ASSERT_EQUALS(expectedNumRecords, obj.getIntField("nrecords")); ASSERT_EQUALS(0, getNumRecords()); @@ -519,7 +530,7 @@ TEST_F(SizeStorerValidateTest, InvalidSizeStorerAtCreation) { GoodValidateAdaptor adaptor; ValidateResults results; BSONObjBuilder output; - ASSERT_OK(rs->validate(opCtx.get(), true, true, &adaptor, &results, &output)); + ASSERT_OK(rs->validate(opCtx.get(), kValidateFull, &adaptor, &results, &output)); BSONObj obj = output.obj(); ASSERT_EQUALS(expectedNumRecords, obj.getIntField("nrecords")); ASSERT_EQUALS(expectedNumRecords, getNumRecords()); diff --git a/src/mongo/dbtests/validate_tests.cpp b/src/mongo/dbtests/validate_tests.cpp index 308c81482d1..1c32e715510 100644 --- a/src/mongo/dbtests/validate_tests.cpp +++ b/src/mongo/dbtests/validate_tests.cpp @@ -70,7 +70,8 @@ protected: bool checkValid() { ValidateResults results; BSONObjBuilder output; - ASSERT_OK(collection()->validate(&_txn, _full, false, &results, &output)); + ASSERT_OK(collection()->validate( + &_txn, _full ? kValidateFull : kValidateIndex, &results, &output)); // Check if errors are reported if and only if valid is set to false. ASSERT_EQ(results.valid, results.errors.empty()); |