diff options
author | Louis Williams <louis.williams@mongodb.com> | 2019-09-06 15:52:33 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2019-09-06 15:52:33 +0000 |
commit | a74a733800b410f89953e807a86231c522ba66c0 (patch) | |
tree | 766deb45f3d9e5eceb8b1e13e6aeaadd6e9574bf /src/mongo/db/catalog | |
parent | 3e6f3e9144e33790711b0b656bae85ed5015504b (diff) | |
download | mongo-a74a733800b410f89953e807a86231c522ba66c0.tar.gz |
SERVER-43081 Validate should report when an index's 'multikeyPaths' are set but the 'multikey' flag is false
This also removes the invariant added by SERVER-43008 that performed the
same check in the catalog layer. It is not safe to invariant based on
durable data if it is known that data could be corrupt in an undefined
way (see SERVER-43074), so the safest option is to report a validation
error, which requires rebuilding the index to fix the problem.
Diffstat (limited to 'src/mongo/db/catalog')
-rw-r--r-- | src/mongo/db/catalog/collection_validation.cpp | 53 |
1 files changed, 52 insertions, 1 deletions
diff --git a/src/mongo/db/catalog/collection_validation.cpp b/src/mongo/db/catalog/collection_validation.cpp index b774da1301c..bfd16f5e1a2 100644 --- a/src/mongo/db/catalog/collection_validation.cpp +++ b/src/mongo/db/catalog/collection_validation.cpp @@ -33,6 +33,8 @@ #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" @@ -338,6 +340,35 @@ void addErrorIfUnequal(T stored, T cached, StringData name, ValidateResults* res } } +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, @@ -377,8 +408,28 @@ void _validateCatalogEntry(OperationContext* opCtx, 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, |