diff options
author | Gregory Wlodarek <gregory.wlodarek@mongodb.com> | 2017-08-01 21:24:45 -0400 |
---|---|---|
committer | Gregory Wlodarek <gregory.wlodarek@mongodb.com> | 2017-08-01 21:24:45 -0400 |
commit | c99aaa0d4152783f533883ebf311a947b7854d3d (patch) | |
tree | b55234979a536a80ae431e49a732468b32407a51 | |
parent | 9be0ac031fd016f768297b3647a4b786aa7ae5b6 (diff) | |
download | mongo-c99aaa0d4152783f533883ebf311a947b7854d3d.tar.gz |
SERVER-30351 Add a traverseRecordStore() function in the RecordStoreValidateAdaptor
-rw-r--r-- | src/mongo/db/catalog/collection_impl.cpp | 20 | ||||
-rw-r--r-- | src/mongo/db/catalog/private/record_store_validate_adaptor.cpp | 55 | ||||
-rw-r--r-- | src/mongo/db/catalog/private/record_store_validate_adaptor.h | 9 |
3 files changed, 77 insertions, 7 deletions
diff --git a/src/mongo/db/catalog/collection_impl.cpp b/src/mongo/db/catalog/collection_impl.cpp index c229698b205..b4780bd66a7 100644 --- a/src/mongo/db/catalog/collection_impl.cpp +++ b/src/mongo/db/catalog/collection_impl.cpp @@ -1007,16 +1007,21 @@ using ValidateResultsMap = std::map<std::string, ValidateResults>; void _validateRecordStore(OperationContext* opCtx, RecordStore* recordStore, ValidateCmdLevel level, + bool background, RecordStoreValidateAdaptor* indexValidator, ValidateResults* results, BSONObjBuilder* output) { - // Validate RecordStore and, if `level == kValidateFull`, cross validate indexes and - // RecordStore. - auto status = recordStore->validate(opCtx, level, indexValidator, results, output); - // RecordStore::validate always returns Status::OK(). Errors are reported through - // `results`. - dassert(status.isOK()); + // Validate RecordStore and, if `level == kValidateFull`, use the RecordStore's validate + // function. + if (background) { + indexValidator->traverseRecordStore(recordStore, level, results, output); + } else { + auto status = recordStore->validate(opCtx, level, indexValidator, results, output); + // RecordStore::validate always returns Status::OK(). Errors are reported through + // `results`. + dassert(status.isOK()); + } } void _validateIndexes(OperationContext* opCtx, @@ -1165,7 +1170,8 @@ Status CollectionImpl::validate(OperationContext* opCtx, // Validate the record store log(LogComponent::kIndex) << "validating collection " << ns().toString() << endl; - _validateRecordStore(opCtx, _recordStore, level, &indexValidator, results, output); + _validateRecordStore( + opCtx, _recordStore, level, /*somgarg*/ false, &indexValidator, results, output); // Validate indexes and check for mismatches. if (results->valid) { diff --git a/src/mongo/db/catalog/private/record_store_validate_adaptor.cpp b/src/mongo/db/catalog/private/record_store_validate_adaptor.cpp index a7f70e96b9f..8b978820b9b 100644 --- a/src/mongo/db/catalog/private/record_store_validate_adaptor.cpp +++ b/src/mongo/db/catalog/private/record_store_validate_adaptor.cpp @@ -42,6 +42,7 @@ #include "mongo/db/storage/key_string.h" #include "mongo/db/storage/record_store.h" #include "mongo/rpc/object_check.h" +#include "mongo/util/log.h" namespace mongo { @@ -186,6 +187,60 @@ void RecordStoreValidateAdaptor::traverseIndex(const IndexAccessMethod* iam, *numTraversedKeys = numKeys; } +void RecordStoreValidateAdaptor::traverseRecordStore(RecordStore* recordStore, + ValidateCmdLevel level, + ValidateResults* results, + BSONObjBuilder* output) { + + long long nrecords = 0; + long long dataSizeTotal = 0; + long long nInvalid = 0; + + results->valid = true; + std::unique_ptr<SeekableRecordCursor> cursor = recordStore->getCursor(_opCtx, true); + int interruptInterval = 4096; + RecordId prevRecordId; + + while (auto record = cursor->next()) { + ++nrecords; + + if (!(nrecords % interruptInterval)) { + _opCtx->checkForInterrupt(); + } + + auto dataSize = record->data.size(); + dataSizeTotal += dataSize; + size_t validatedSize; + Status status = validate(record->id, record->data, &validatedSize); + + // Checks to ensure isInRecordIdOrder() is being used properly. + if (prevRecordId.isNormal()) { + invariant(prevRecordId < record->id); + } + + // While some storage engines, such as MMAPv1, may use padding, we still require + // that they return the unpadded record data. + if (!status.isOK() || validatedSize != static_cast<size_t>(dataSize)) { + if (results->valid) { + // Only log once. + results->errors.push_back("detected one or more invalid documents (see logs)"); + } + nInvalid++; + results->valid = false; + log() << "document at location: " << record->id << " is corrupted"; + } + + prevRecordId = record->id; + } + + if (results->valid) { + recordStore->updateStatsAfterRepair(_opCtx, nrecords, dataSizeTotal); + } + + output->append("nInvalidDocuments", nInvalid); + output->appendNumber("nrecords", nrecords); +} + void RecordStoreValidateAdaptor::validateIndexKeyCount(IndexDescriptor* idx, int64_t numRecs, ValidateResults& results) { diff --git a/src/mongo/db/catalog/private/record_store_validate_adaptor.h b/src/mongo/db/catalog/private/record_store_validate_adaptor.h index cccc4e06254..2cdb21ad429 100644 --- a/src/mongo/db/catalog/private/record_store_validate_adaptor.h +++ b/src/mongo/db/catalog/private/record_store_validate_adaptor.h @@ -76,6 +76,15 @@ public: int64_t* numTraversedKeys); /** + * Traverses the record store to retrieve every record and go through its document key + * set to keep track of the index consistency during a validation. + */ + void traverseRecordStore(RecordStore* recordStore, + ValidateCmdLevel level, + ValidateResults* results, + BSONObjBuilder* output); + + /** * Validate that the number of document keys matches the number of index keys. */ void validateIndexKeyCount(IndexDescriptor* idx, int64_t numRecs, ValidateResults& results); |