summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMindaugas Malinauskas <mindaugas.malinauskas@mongodb.com>2020-08-21 10:54:14 +0300
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-08-31 12:08:32 +0000
commitf5da4e4b7f7f04267bd92736ee9b16417e6d70ff (patch)
treef0ae8b67db601735b166dc1b592d21f4c92d7ad7 /src
parent1eb0308decd6709fe9d0df9212fa690cd20e03fd (diff)
downloadmongo-f5da4e4b7f7f04267bd92736ee9b16417e6d70ff.tar.gz
SERVER-49499 Upgrade/downgrade behavior and testing for generating document validation errors
Diffstat (limited to 'src')
-rw-r--r--src/mongo/base/error_codes.yml4
-rw-r--r--src/mongo/db/catalog/collection_impl.cpp20
-rw-r--r--src/mongo/db/commands/write_commands/write_commands.cpp5
-rw-r--r--src/mongo/db/matcher/doc_validation_error.cpp8
4 files changed, 30 insertions, 7 deletions
diff --git a/src/mongo/base/error_codes.yml b/src/mongo/base/error_codes.yml
index fe34bf4f7d8..676d675dc00 100644
--- a/src/mongo/base/error_codes.yml
+++ b/src/mongo/base/error_codes.yml
@@ -153,7 +153,9 @@ error_codes:
- {code: 120,name: OplogStartMissing}
# Error code 121 is only for the document validator on collections.
- {code: 121,name: DocumentValidationFailure,
- extra: 'doc_validation_error::DocumentValidationFailureInfo'}
+ extra: 'doc_validation_error::DocumentValidationFailureInfo',
+ # TODO SERVER-50524: Make extra info mandatory when 5.0 becomes last-lts.
+ extraIsOptional: True}
- {code: 122,name: OBSOLETE_ReadAfterOptimeTimeout}
- {code: 123,name: NotAReplicaSet}
- {code: 124,name: IncompatibleElectionProtocol}
diff --git a/src/mongo/db/catalog/collection_impl.cpp b/src/mongo/db/catalog/collection_impl.cpp
index 30520fe8a54..c113ce8e34c 100644
--- a/src/mongo/db/catalog/collection_impl.cpp
+++ b/src/mongo/db/catalog/collection_impl.cpp
@@ -65,6 +65,7 @@
#include "mongo/db/query/internal_plans.h"
#include "mongo/db/repl/oplog.h"
#include "mongo/db/repl/replication_coordinator.h"
+#include "mongo/db/server_options.h"
#include "mongo/db/service_context.h"
#include "mongo/db/storage/durable_catalog.h"
#include "mongo/db/storage/key_string.h"
@@ -400,7 +401,15 @@ Status CollectionImpl::checkValidation(OperationContext* opCtx, const BSONObj& d
if (validatorMatchExpr->matchesBSON(document))
return Status::OK();
- BSONObj generatedError = doc_validation_error::generateError(*validatorMatchExpr, document);
+ // TODO SERVER-50524: remove these FCV checks when 5.0 becomes last-lts in order to make sure
+ // that an upgrade from 4.4 directly to the 5.0 LTS version is supported.
+ const auto isFCVAtLeast47 = serverGlobalParams.featureCompatibility.isVersionInitialized() &&
+ serverGlobalParams.featureCompatibility.isGreaterThanOrEqualTo(
+ ServerGlobalParams::FeatureCompatibility::Version::kVersion47);
+ BSONObj generatedError;
+ if (isFCVAtLeast47) {
+ generatedError = doc_validation_error::generateError(*validatorMatchExpr, document);
+ }
if (_validationAction == ValidationAction::WARN) {
LOGV2_WARNING(20294,
@@ -411,8 +420,13 @@ Status CollectionImpl::checkValidation(OperationContext* opCtx, const BSONObj& d
return Status::OK();
}
- return {doc_validation_error::DocumentValidationFailureInfo(generatedError),
- "Document failed validation"};
+ static constexpr auto kValidationFailureErrorStr = "Document failed validation"_sd;
+ if (isFCVAtLeast47) {
+ return {doc_validation_error::DocumentValidationFailureInfo(generatedError),
+ kValidationFailureErrorStr};
+ } else {
+ return {ErrorCodes::DocumentValidationFailure, kValidationFailureErrorStr};
+ }
}
Collection::Validator CollectionImpl::parseValidator(
diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp
index 8c0d4e0549d..e79e9ce5581 100644
--- a/src/mongo/db/commands/write_commands/write_commands.cpp
+++ b/src/mongo/db/commands/write_commands/write_commands.cpp
@@ -154,8 +154,9 @@ void serializeReply(OperationContext* opCtx,
BSONObjBuilder errInfo(error.subobjStart("errInfo"));
staleInfo->serialize(&errInfo);
}
- } else if (auto docValidationError =
- status.extraInfo<doc_validation_error::DocumentValidationFailureInfo>()) {
+ } else if (ErrorCodes::DocumentValidationFailure == status.code() && status.extraInfo()) {
+ auto docValidationError =
+ status.extraInfo<doc_validation_error::DocumentValidationFailureInfo>();
error.append("code", static_cast<int>(ErrorCodes::DocumentValidationFailure));
error.append("errInfo", docValidationError->getDetails());
} else {
diff --git a/src/mongo/db/matcher/doc_validation_error.cpp b/src/mongo/db/matcher/doc_validation_error.cpp
index c5320f88bc5..bbc2f4eb1cb 100644
--- a/src/mongo/db/matcher/doc_validation_error.cpp
+++ b/src/mongo/db/matcher/doc_validation_error.cpp
@@ -974,6 +974,10 @@ bool hasErrorAnnotations(const MatchExpression& validatorExpr) {
} // namespace
std::shared_ptr<const ErrorExtraInfo> DocumentValidationFailureInfo::parse(const BSONObj& obj) {
+ if (!obj.hasField("errInfo"_sd)) {
+ // TODO SERVER-50524: remove this block when 5.0 becomes last-lts.
+ return nullptr;
+ }
auto errInfo = obj["errInfo"];
uassert(4878100,
"DocumentValidationFailureInfo must have a field 'errInfo' of type object",
@@ -993,7 +997,9 @@ BSONObj generateError(const MatchExpression& validatorExpr, const BSONObj& doc)
ValidationErrorInVisitor inVisitor{&context};
ValidationErrorPostVisitor postVisitor{&context};
// TODO SERVER-49446: Once all nodes have ErrorAnnotations, this check should be converted to an
- // invariant check that all nodes have an annotation.
+ // invariant check that all nodes have an annotation. Also add an invariant to the
+ // DocumentValidationFailureInfo constructor to check that it is initialized with a non-empty
+ // object.
if (!hasErrorAnnotations(validatorExpr)) {
return BSONObj();
}