diff options
author | George Wangensteen <george.wangensteen@mongodb.com> | 2020-11-04 15:39:42 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-11-19 23:55:38 +0000 |
commit | 304316278656273caffdd461ead2ef02e2ac7743 (patch) | |
tree | bc277a6e06a1827eea38888cfddf8e784c9c827c /src/mongo/db/write_concern_options.cpp | |
parent | 5247cf436984268be6231d90c6d140259d43b83f (diff) | |
download | mongo-304316278656273caffdd461ead2ef02e2ac7743.tar.gz |
SERVER-51371 Strict IDL definition for WriteConcern
Diffstat (limited to 'src/mongo/db/write_concern_options.cpp')
-rw-r--r-- | src/mongo/db/write_concern_options.cpp | 74 |
1 files changed, 65 insertions, 9 deletions
diff --git a/src/mongo/db/write_concern_options.cpp b/src/mongo/db/write_concern_options.cpp index b25140c65cb..17e30eddff3 100644 --- a/src/mongo/db/write_concern_options.cpp +++ b/src/mongo/db/write_concern_options.cpp @@ -29,6 +29,8 @@ #include "mongo/platform/basic.h" +#include <type_traits> + #include "mongo/db/write_concern_options.h" #include "mongo/base/status.h" @@ -36,6 +38,7 @@ #include "mongo/bson/util/bson_extract.h" #include "mongo/db/field_parser.h" #include "mongo/db/repl/repl_set_config.h" +#include "mongo/idl/basic_types_gen.h" #include "mongo/util/str.h" namespace mongo { @@ -197,13 +200,11 @@ WriteConcernOptions WriteConcernOptions::deserializerForIDL(const BSONObj& obj) } StatusWith<WriteConcernOptions> WriteConcernOptions::extractWCFromCommand(const BSONObj& cmdObj) { - WriteConcernOptions writeConcern; - // Return the default write concern if no write concern is provided. We check for the existence // of the write concern field up front in order to avoid the expense of constructing an error // status in bsonExtractTypedField() below. if (!cmdObj.hasField(kWriteConcernField)) { - return writeConcern; + return WriteConcernOptions(); } BSONElement writeConcernElement; @@ -216,15 +217,70 @@ StatusWith<WriteConcernOptions> WriteConcernOptions::extractWCFromCommand(const BSONObj writeConcernObj = writeConcernElement.Obj(); // Empty write concern is interpreted to default. if (writeConcernObj.isEmpty()) { - return writeConcern; + return WriteConcernOptions(); + } + + // Ensure that the write concern document complies with the strict IDL definition, found in + // idl/basic_types.idl. + try { + auto writeConcernIdl = WriteConcernIdl::parse( + IDLParserErrorContext("WriteConcernOptions::extractWCFromCommand"), writeConcernObj); + // Convert the IDL parsed WriteConcern into a WriteConcernOptions object. + auto sw = convertFromIdl(writeConcernIdl); + if (!sw.isOK()) { + return sw.getStatus(); + } + auto writeConcernOptions = sw.getValue(); + writeConcernOptions.usedDefault = false; + return writeConcernOptions; + } catch (const DBException& ex) { + return ex.toStatus(); + } +} + +StatusWith<WriteConcernOptions> WriteConcernOptions::convertFromIdl( + const WriteConcernIdl& writeConcernIdl) { + WriteConcernOptions writeConcern; + auto parsedW = writeConcernIdl.getWriteConcernW(); + if (!parsedW.usedDefault()) { + writeConcern.usedDefaultW = false; + auto wVal = parsedW.getValue(); + if (auto wNum = stdx::get_if<std::int64_t>(&wVal)) { + if (*wNum < 0 || + *wNum > + static_cast<std::decay_t<decltype(*wNum)>>(repl::ReplSetConfig::kMaxMembers)) { + uasserted(ErrorCodes::FailedToParse, + str::stream() << "w has to be a non-negative number and not greater than " + << repl::ReplSetConfig::kMaxMembers); + } + writeConcern.wNumNodes = static_cast<decltype(writeConcern.wNumNodes)>(*wNum); + } else { + auto wMode = stdx::get_if<std::string>(&wVal); + invariant(wMode); + writeConcern.wNumNodes = 0; // Have to reset from default 1. + writeConcern.wMode = std::move(*wMode); + } + } + + auto j = writeConcernIdl.getJ(); + auto fsync = writeConcernIdl.getFsync(); + if (j && fsync && *j && *fsync) { + // If j and fsync are both set to true + return Status{ErrorCodes::FailedToParse, "fsync and j options cannot be used together"}; + } + if (j && *j) { + writeConcern.syncMode = SyncMode::JOURNAL; + } else if (fsync && *fsync) { + writeConcern.syncMode = SyncMode::FSYNC; + } else if (j) { + // j has been set to false + writeConcern.syncMode = SyncMode::NONE; } - auto sw = parse(writeConcernObj); - if (!sw.isOK()) { - return sw.getStatus(); + writeConcern.wTimeout = writeConcernIdl.getWtimeout(); + if (auto source = writeConcernIdl.getSource()) { + writeConcern._provenance = ReadWriteConcernProvenance(*source); } - writeConcern = sw.getValue(); - writeConcern.usedDefault = false; return writeConcern; } |