summaryrefslogtreecommitdiff
path: root/src/mongo/db/catalog
diff options
context:
space:
mode:
authorLouis Williams <louis.williams@mongodb.com>2019-09-06 15:52:33 +0000
committerevergreen <evergreen@mongodb.com>2019-09-06 15:52:33 +0000
commita74a733800b410f89953e807a86231c522ba66c0 (patch)
tree766deb45f3d9e5eceb8b1e13e6aeaadd6e9574bf /src/mongo/db/catalog
parent3e6f3e9144e33790711b0b656bae85ed5015504b (diff)
downloadmongo-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.cpp53
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,