diff options
author | Gregory Wlodarek <gregory.wlodarek@mongodb.com> | 2017-08-01 08:58:21 -0400 |
---|---|---|
committer | Gregory Wlodarek <gregory.wlodarek@mongodb.com> | 2017-08-01 08:58:21 -0400 |
commit | 49f9a6b840d3a56fc1947290d9f5834e6ea370a7 (patch) | |
tree | d2f54f63dc16be707e5be7ef731055f275bca838 /src/mongo | |
parent | 7cad8ba246755794c31b237531fedb09c0baa534 (diff) | |
download | mongo-49f9a6b840d3a56fc1947290d9f5834e6ea370a7.tar.gz |
SERVER-30350 Move the RecordStoreValidateAdaptor into its own file from CollectionImpl
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/catalog/SConscript | 3 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_impl.cpp | 240 | ||||
-rw-r--r-- | src/mongo/db/storage/SConscript | 13 | ||||
-rw-r--r-- | src/mongo/db/storage/record_store_validate_adaptor.cpp | 242 | ||||
-rw-r--r-- | src/mongo/db/storage/record_store_validate_adaptor.h | 114 |
5 files changed, 373 insertions, 239 deletions
diff --git a/src/mongo/db/catalog/SConscript b/src/mongo/db/catalog/SConscript index 7a410ab6404..ccefcaaf8a8 100644 --- a/src/mongo/db/catalog/SConscript +++ b/src/mongo/db/catalog/SConscript @@ -227,6 +227,9 @@ env.Library( '$BUILD_DIR/mongo/db/s/balancer', '$BUILD_DIR/mongo/db/views/views_mongod', ], + LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/storage/record_store_validate_adaptor', + ], ) env.Library( diff --git a/src/mongo/db/catalog/collection_impl.cpp b/src/mongo/db/catalog/collection_impl.cpp index 46ecf9ff961..7523fac70d6 100644 --- a/src/mongo/db/catalog/collection_impl.cpp +++ b/src/mongo/db/catalog/collection_impl.cpp @@ -28,8 +28,6 @@ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kStorage -#include <third_party/murmurhash3/MurmurHash3.h> - #include "mongo/platform/basic.h" #include "mongo/db/catalog/collection_impl.h" @@ -66,6 +64,7 @@ #include "mongo/db/storage/mmap_v1/mmap_v1_options.h" #include "mongo/db/storage/record_fetcher.h" #include "mongo/db/storage/record_store.h" +#include "mongo/db/storage/record_store_validate_adaptor.h" #include "mongo/db/update/update_driver.h" #include "mongo/db/auth/user_document_parser.h" // XXX-ANDY @@ -163,8 +162,6 @@ using std::vector; using logger::LogComponent; -static const int IndexKeyMaxSize = 1024; // this goes away with SERVER-3372 - CollectionImpl::CollectionImpl(Collection* _this_init, OperationContext* opCtx, StringData fullNS, @@ -1004,243 +1001,8 @@ const CollatorInterface* CollectionImpl::getDefaultCollator() const { namespace { -static const uint32_t kKeyCountTableSize = 1U << 22; - -using IndexKeyCountTable = std::array<uint64_t, kKeyCountTableSize>; using ValidateResultsMap = std::map<std::string, ValidateResults>; -class RecordStoreValidateAdaptor : public ValidateAdaptor { -public: - RecordStoreValidateAdaptor(OperationContext* opCtx, - ValidateCmdLevel level, - IndexCatalog* ic, - ValidateResultsMap* irm) - : _opCtx(opCtx), _level(level), _indexCatalog(ic), _indexNsResultsMap(irm) { - _ikc = stdx::make_unique<IndexKeyCountTable>(); - } - - virtual Status validate(const RecordId& recordId, const RecordData& record, size_t* dataSize) { - BSONObj recordBson = record.toBson(); - - const Status status = validateBSON( - recordBson.objdata(), recordBson.objsize(), Validator<BSONObj>::enabledBSONVersion()); - if (status.isOK()) { - *dataSize = recordBson.objsize(); - } else { - return status; - } - - if (!_indexCatalog->haveAnyIndexes()) { - return status; - } - - IndexCatalog::IndexIterator i = _indexCatalog->getIndexIterator(_opCtx, false); - - while (i.more()) { - const IndexDescriptor* descriptor = i.next(); - const string indexNs = descriptor->indexNamespace(); - ValidateResults curRecordResults; - - const IndexAccessMethod* iam = _indexCatalog->getIndex(descriptor); - - if (descriptor->isPartial()) { - const IndexCatalogEntry* ice = _indexCatalog->getEntry(descriptor); - if (!ice->getFilterExpression()->matchesBSON(recordBson)) { - (*_indexNsResultsMap)[indexNs] = curRecordResults; - continue; - } - } - - BSONObjSet documentKeySet = SimpleBSONObjComparator::kInstance.makeBSONObjSet(); - // There's no need to compute the prefixes of the indexed fields that cause the - // index to be multikey when validating the index keys. - MultikeyPaths* multikeyPaths = nullptr; - iam->getKeys(recordBson, - IndexAccessMethod::GetKeysMode::kEnforceConstraints, - &documentKeySet, - multikeyPaths); - - if (!descriptor->isMultikey(_opCtx) && documentKeySet.size() > 1) { - string msg = str::stream() << "Index " << descriptor->indexName() - << " is not multi-key but has more than one" - << " key in document " << recordId; - curRecordResults.errors.push_back(msg); - curRecordResults.valid = false; - } - - uint32_t indexNsHash; - const auto& pattern = descriptor->keyPattern(); - const Ordering ord = Ordering::make(pattern); - MurmurHash3_x86_32(indexNs.c_str(), indexNs.size(), 0, &indexNsHash); - - for (const auto& key : documentKeySet) { - if (key.objsize() >= IndexKeyMaxSize) { - // Index keys >= 1024 bytes are not indexed. - _longKeys[indexNs]++; - continue; - } - - // We want to use the latest version of KeyString here. - KeyString ks(KeyString::kLatestVersion, key, ord, recordId); - uint32_t indexEntryHash = hashIndexEntry(ks, indexNsHash); - - if ((*_ikc)[indexEntryHash] == 0) { - _indexKeyCountTableNumEntries++; - } - (*_ikc)[indexEntryHash]++; - } - (*_indexNsResultsMap)[indexNs] = curRecordResults; - } - return status; - } - - bool tooManyIndexEntries() const { - return _indexKeyCountTableNumEntries != 0; - } - - bool tooFewIndexEntries() const { - return _hasDocWithoutIndexEntry; - } - - /** - * Traverse the index to validate the entries and cache index keys for later use. - */ - void traverseIndex(const IndexAccessMethod* iam, - const IndexDescriptor* descriptor, - ValidateResults* results, - int64_t* numTraversedKeys) { - auto indexNs = descriptor->indexNamespace(); - int64_t numKeys = 0; - - uint32_t indexNsHash; - MurmurHash3_x86_32(indexNs.c_str(), indexNs.size(), 0, &indexNsHash); - - const auto& key = descriptor->keyPattern(); - const Ordering ord = Ordering::make(key); - KeyString::Version version = KeyString::kLatestVersion; - std::unique_ptr<KeyString> prevIndexKeyString = nullptr; - bool isFirstEntry = true; - - std::unique_ptr<SortedDataInterface::Cursor> cursor = iam->newCursor(_opCtx, 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()) { - - // We want to use the latest version of KeyString here. - std::unique_ptr<KeyString> indexKeyString = - stdx::make_unique<KeyString>(version, indexEntry->key, ord, indexEntry->loc); - // Ensure that the index entries are in increasing or decreasing order. - if (!isFirstEntry && *indexKeyString < *prevIndexKeyString) { - if (results->valid) { - results->errors.push_back( - "one or more indexes are not in strictly ascending or descending " - "order"); - } - results->valid = false; - } - - // Cache the index keys to cross-validate with documents later. - uint32_t keyHash = hashIndexEntry(*indexKeyString, indexNsHash); - uint64_t& indexEntryCount = (*_ikc)[keyHash]; - if (indexEntryCount != 0) { - indexEntryCount--; - dassert(indexEntryCount >= 0); - if (indexEntryCount == 0) { - _indexKeyCountTableNumEntries--; - } - } else { - _hasDocWithoutIndexEntry = true; - results->valid = false; - } - numKeys++; - - isFirstEntry = false; - prevIndexKeyString.swap(indexKeyString); - } - - _keyCounts[indexNs] = numKeys; - *numTraversedKeys = numKeys; - } - - void validateIndexKeyCount(IndexDescriptor* idx, int64_t numRecs, ValidateResults& results) { - const string indexNs = idx->indexNamespace(); - int64_t numIndexedKeys = _keyCounts[indexNs]; - int64_t numLongKeys = _longKeys[indexNs]; - auto totalKeys = numLongKeys + numIndexedKeys; - - bool hasTooFewKeys = false; - bool noErrorOnTooFewKeys = !failIndexKeyTooLong.load() && (_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 (noErrorOnTooFewKeys && (numIndexedKeys < numRecs)) { - results.warnings.push_back(msg); - } else { - results.errors.push_back(msg); - results.valid = false; - } - } - - if (results.valid && !idx->isMultikey(_opCtx) && 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; - } - // 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 (noErrorOnTooFewKeys) { - results.warnings.push_back(msg); - } else { - results.errors.push_back(msg); - results.valid = false; - } - } - - 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); - } - } - -private: - std::map<string, int64_t> _longKeys; - std::map<string, int64_t> _keyCounts; - std::unique_ptr<IndexKeyCountTable> _ikc; - - uint32_t _indexKeyCountTableNumEntries = 0; - bool _hasDocWithoutIndexEntry = false; - - OperationContext* _opCtx; // Not owned. - ValidateCmdLevel _level; - IndexCatalog* _indexCatalog; // Not owned. - ValidateResultsMap* _indexNsResultsMap; // Not owned. - - uint32_t hashIndexEntry(KeyString& ks, uint32_t hash) { - MurmurHash3_x86_32(ks.getTypeBits().getBuffer(), ks.getTypeBits().getSize(), hash, &hash); - MurmurHash3_x86_32(ks.getBuffer(), ks.getSize(), hash, &hash); - return hash % kKeyCountTableSize; - } -}; -} // namespace - -namespace { void _validateRecordStore(OperationContext* opCtx, RecordStore* recordStore, ValidateCmdLevel level, diff --git a/src/mongo/db/storage/SConscript b/src/mongo/db/storage/SConscript index 46c00c785e5..508e21a1ea0 100644 --- a/src/mongo/db/storage/SConscript +++ b/src/mongo/db/storage/SConscript @@ -164,6 +164,19 @@ env.Library( ) env.Library( + target='record_store_validate_adaptor', + source=[ + 'record_store_validate_adaptor.cpp', + ], + LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/catalog/index_catalog', + '$BUILD_DIR/mongo/db/index/index_descriptor', + '$BUILD_DIR/mongo/db/index/index_access_methods', + '$BUILD_DIR/mongo/db/service_context', + ], + ) + +env.Library( target='storage_engine_lock_file', source=[ 'storage_engine_lock_file_${TARGET_OS_FAMILY}.cpp', diff --git a/src/mongo/db/storage/record_store_validate_adaptor.cpp b/src/mongo/db/storage/record_store_validate_adaptor.cpp new file mode 100644 index 00000000000..f4f7745c04d --- /dev/null +++ b/src/mongo/db/storage/record_store_validate_adaptor.cpp @@ -0,0 +1,242 @@ +/*- + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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 <third_party/murmurhash3/MurmurHash3.h> + +#include "mongo/bson/bsonobj.h" +#include "mongo/db/catalog/index_catalog.h" +#include "mongo/db/index/index_access_method.h" +#include "mongo/db/index/index_descriptor.h" +#include "mongo/db/operation_context.h" +#include "mongo/db/storage/key_string.h" +#include "mongo/db/storage/record_store.h" +#include "mongo/db/storage/record_store_validate_adaptor.h" +#include "mongo/rpc/object_check.h" + +namespace mongo { + +namespace { +uint32_t hashIndexEntry(KeyString& ks, uint32_t hash) { + MurmurHash3_x86_32(ks.getTypeBits().getBuffer(), ks.getTypeBits().getSize(), hash, &hash); + MurmurHash3_x86_32(ks.getBuffer(), ks.getSize(), hash, &hash); + return hash % kKeyCountTableSize; +} +} + +Status RecordStoreValidateAdaptor::validate(const RecordId& recordId, + const RecordData& record, + size_t* dataSize) { + BSONObj recordBson = record.toBson(); + + const Status status = validateBSON( + recordBson.objdata(), recordBson.objsize(), Validator<BSONObj>::enabledBSONVersion()); + if (status.isOK()) { + *dataSize = recordBson.objsize(); + } else { + return status; + } + + if (!_indexCatalog->haveAnyIndexes()) { + return status; + } + + IndexCatalog::IndexIterator i = _indexCatalog->getIndexIterator(_opCtx, false); + + while (i.more()) { + const IndexDescriptor* descriptor = i.next(); + const std::string indexNs = descriptor->indexNamespace(); + ValidateResults curRecordResults; + + const IndexAccessMethod* iam = _indexCatalog->getIndex(descriptor); + + if (descriptor->isPartial()) { + const IndexCatalogEntry* ice = _indexCatalog->getEntry(descriptor); + if (!ice->getFilterExpression()->matchesBSON(recordBson)) { + (*_indexNsResultsMap)[indexNs] = curRecordResults; + continue; + } + } + + BSONObjSet documentKeySet = SimpleBSONObjComparator::kInstance.makeBSONObjSet(); + // There's no need to compute the prefixes of the indexed fields that cause the + // index to be multikey when validating the index keys. + MultikeyPaths* multikeyPaths = nullptr; + iam->getKeys(recordBson, + IndexAccessMethod::GetKeysMode::kEnforceConstraints, + &documentKeySet, + multikeyPaths); + + if (!descriptor->isMultikey(_opCtx) && documentKeySet.size() > 1) { + std::string msg = str::stream() << "Index " << descriptor->indexName() + << " is not multi-key but has more than one" + << " key in document " << recordId; + curRecordResults.errors.push_back(msg); + curRecordResults.valid = false; + } + + uint32_t indexNsHash; + const auto& pattern = descriptor->keyPattern(); + const Ordering ord = Ordering::make(pattern); + MurmurHash3_x86_32(indexNs.c_str(), indexNs.size(), 0, &indexNsHash); + + for (const auto& key : documentKeySet) { + if (key.objsize() >= IndexKeyMaxSize) { + // Index keys >= 1024 bytes are not indexed. + _longKeys[indexNs]++; + continue; + } + + // We want to use the latest version of KeyString here. + KeyString ks(KeyString::kLatestVersion, key, ord, recordId); + uint32_t indexEntryHash = hashIndexEntry(ks, indexNsHash); + + if ((*_ikc)[indexEntryHash] == 0) { + _indexKeyCountTableNumEntries++; + } + (*_ikc)[indexEntryHash]++; + } + (*_indexNsResultsMap)[indexNs] = curRecordResults; + } + return status; +} + +void RecordStoreValidateAdaptor::traverseIndex(const IndexAccessMethod* iam, + const IndexDescriptor* descriptor, + ValidateResults* results, + int64_t* numTraversedKeys) { + auto indexNs = descriptor->indexNamespace(); + int64_t numKeys = 0; + + uint32_t indexNsHash; + MurmurHash3_x86_32(indexNs.c_str(), indexNs.size(), 0, &indexNsHash); + + const auto& key = descriptor->keyPattern(); + const Ordering ord = Ordering::make(key); + KeyString::Version version = KeyString::kLatestVersion; + std::unique_ptr<KeyString> prevIndexKeyString = nullptr; + bool isFirstEntry = true; + + std::unique_ptr<SortedDataInterface::Cursor> cursor = iam->newCursor(_opCtx, 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()) { + + // We want to use the latest version of KeyString here. + std::unique_ptr<KeyString> indexKeyString = + stdx::make_unique<KeyString>(version, indexEntry->key, ord, indexEntry->loc); + // Ensure that the index entries are in increasing or decreasing order. + if (!isFirstEntry && *indexKeyString < *prevIndexKeyString) { + if (results->valid) { + results->errors.push_back( + "one or more indexes are not in strictly ascending or descending " + "order"); + } + results->valid = false; + } + + // Cache the index keys to cross-validate with documents later. + uint32_t keyHash = hashIndexEntry(*indexKeyString, indexNsHash); + uint64_t& indexEntryCount = (*_ikc)[keyHash]; + if (indexEntryCount != 0) { + indexEntryCount--; + dassert(indexEntryCount >= 0); + if (indexEntryCount == 0) { + _indexKeyCountTableNumEntries--; + } + } else { + _hasDocWithoutIndexEntry = true; + results->valid = false; + } + numKeys++; + + isFirstEntry = false; + prevIndexKeyString.swap(indexKeyString); + } + + _keyCounts[indexNs] = numKeys; + *numTraversedKeys = numKeys; +} + +void RecordStoreValidateAdaptor::validateIndexKeyCount(IndexDescriptor* idx, + int64_t numRecs, + ValidateResults& results) { + const std::string indexNs = idx->indexNamespace(); + int64_t numIndexedKeys = _keyCounts[indexNs]; + int64_t numLongKeys = _longKeys[indexNs]; + auto totalKeys = numLongKeys + numIndexedKeys; + + bool hasTooFewKeys = false; + bool noErrorOnTooFewKeys = !failIndexKeyTooLong.load() && (_level != kValidateFull); + + if (idx->isIdIndex() && totalKeys != numRecs) { + hasTooFewKeys = totalKeys < numRecs ? true : hasTooFewKeys; + std::string msg = str::stream() << "number of _id index entries (" << numIndexedKeys + << ") does not match the number of documents in the index (" + << numRecs - numLongKeys << ")"; + if (noErrorOnTooFewKeys && (numIndexedKeys < numRecs)) { + results.warnings.push_back(msg); + } else { + results.errors.push_back(msg); + results.valid = false; + } + } + + if (results.valid && !idx->isMultikey(_opCtx) && totalKeys > numRecs) { + std::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; + } + // 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; + std::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 (noErrorOnTooFewKeys) { + results.warnings.push_back(msg); + } else { + results.errors.push_back(msg); + results.valid = false; + } + } + + if ((_level != kValidateFull) && hasTooFewKeys) { + std::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); + } +} +} // namespace diff --git a/src/mongo/db/storage/record_store_validate_adaptor.h b/src/mongo/db/storage/record_store_validate_adaptor.h new file mode 100644 index 00000000000..cccc4e06254 --- /dev/null +++ b/src/mongo/db/storage/record_store_validate_adaptor.h @@ -0,0 +1,114 @@ +/*- + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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. + */ + +#pragma once + +#include "mongo/db/catalog/index_catalog.h" +#include "mongo/db/index/index_access_method.h" +#include "mongo/db/index/index_descriptor.h" +#include "mongo/db/operation_context.h" +#include "mongo/db/storage/record_store.h" + +namespace mongo { + +namespace { +const uint32_t kKeyCountTableSize = 1U << 22; + +using IndexKeyCountTable = std::array<uint64_t, kKeyCountTableSize>; +using ValidateResultsMap = std::map<std::string, ValidateResults>; +} + +/** + * The record store validate adaptor is used to keep track of the index consistency during + * a validation that's running. + */ +class RecordStoreValidateAdaptor : public ValidateAdaptor { +public: + RecordStoreValidateAdaptor(OperationContext* opCtx, + ValidateCmdLevel level, + IndexCatalog* ic, + ValidateResultsMap* irm) + + : _ikc(stdx::make_unique<IndexKeyCountTable>()), + _opCtx(opCtx), + _level(level), + _indexCatalog(ic), + _indexNsResultsMap(irm) {} + + /** + * Validates the BSON object and traverses through its key set to keep track of the + * index consistency. + */ + virtual Status validate(const RecordId& recordId, const RecordData& record, size_t* dataSize); + + /** + * Traverses the index getting index entriess to validate them and keep track of the index keys + * for index consistency. + */ + void traverseIndex(const IndexAccessMethod* iam, + const IndexDescriptor* descriptor, + ValidateResults* results, + int64_t* numTraversedKeys); + + /** + * Validate that the number of document keys matches the number of index keys. + */ + void validateIndexKeyCount(IndexDescriptor* idx, int64_t numRecs, ValidateResults& results); + + /** + * Returns true if there are too many index entries, otherwise return false. + */ + bool tooManyIndexEntries() const { + return _indexKeyCountTableNumEntries != 0; + } + + /** + * Returns true if there are too few index entries, which happens when a document doesn't have + * and index entry, otherwise return false. + */ + bool tooFewIndexEntries() const { + return _hasDocWithoutIndexEntry; + } + + +private: + std::map<std::string, int64_t> _longKeys; + std::map<std::string, int64_t> _keyCounts; + std::unique_ptr<IndexKeyCountTable> _ikc; + + uint32_t _indexKeyCountTableNumEntries = 0; + bool _hasDocWithoutIndexEntry = false; + + const int IndexKeyMaxSize = 1024; // this goes away with SERVER-3372 + + OperationContext* _opCtx; // Not owned. + ValidateCmdLevel _level; + IndexCatalog* _indexCatalog; // Not owned. + ValidateResultsMap* _indexNsResultsMap; // Not owned. +}; +} // namespace |