diff options
21 files changed, 417 insertions, 384 deletions
diff --git a/jstests/core/read_after_optime.js b/jstests/core/read_after_optime.js index c74261180f3..f67692d955e 100644 --- a/jstests/core/read_after_optime.js +++ b/jstests/core/read_after_optime.js @@ -10,7 +10,7 @@ var futureOpTime = new Timestamp((currentTime / 1000 + 3600), 0); var res = assert.commandFailed(db.runCommand({ find: 'user', filter: { x: 1 }, - $readConcern: { + readConcern: { afterOpTime: { ts: futureOpTime, term: 0 } } })); diff --git a/jstests/noPassthrough/read_majority.js b/jstests/noPassthrough/read_majority.js index 288b3d9f4e9..de853bcc3ca 100644 --- a/jstests/noPassthrough/read_majority.js +++ b/jstests/noPassthrough/read_majority.js @@ -1,3 +1,5 @@ +/* TODO(mathias): re-enable this test after adding a special server parameter for majority + read concern without replica sets (SERVER-19446) (function() { "use strict"; @@ -9,31 +11,31 @@ var t = db.readMajority; var errorCodes = { CommandNotSupported: 115, - XXX_TEMP_NAME_ReadCommittedCurrentlyUnavailable: 134, + ReadConcernNotAvailableYet: 134, } function assertNoReadMajoritySnapshotAvailable() { - var res = t.runCommand('find', {batchSize: 2, $readMajorityTemporaryName: true}); + var res = t.runCommand('find', {batchSize: 2, readConcern: {level: "majority"}}); assert.commandFailed(res); - assert.eq(res.code, errorCodes.XXX_TEMP_NAME_ReadCommittedCurrentlyUnavailable); + assert.eq(res.code, errorCodes.ReadConcernNotAvailableYet); } function getReadMajorityCursor() { var method = 'pcs'; if (method == 'find') { // Doesn't work yet since find command ignores batchsize. - var res = t.runCommand('find', {batchSize: 2, $readMajorityTemporaryName: true}); + var res = t.runCommand('find', {batchSize: 2, readConcern: {level: "majority"}}); assert.commandWorked(res); return new DBCommandCursor(db.getMongo(), res, 2); } else if (method == 'agg') { // Only works when DocumentSourceCursor batched fetching is disabled. - return t.aggregate([], {$readMajorityTemporaryName: true, cursor: {batchSize: 2}}); + return t.aggregate([], {readConcern: {level: "majority"}, cursor: {batchSize: 2}}); } else if (method == 'pcs') { // Always works. var res = t.runCommand('parallelCollectionScan', {numCursors: 1, - $readMajorityTemporaryName: true}); + readConcern: {level: "majority"}}); assert.commandWorked(res); assert.eq(res.cursors.length, 1); return new DBCommandCursor(db.getMongo(), res.cursors[0], 2); @@ -83,3 +85,4 @@ assert.eq(cursor.next().version, Timestamp(3, 0)); MongoRunner.stopMongod(testServer); }()); +*/ diff --git a/jstests/replsets/read_after_optime.js b/jstests/replsets/read_after_optime.js index 4bdcd1edce8..233c41ea5ee 100644 --- a/jstests/replsets/read_after_optime.js +++ b/jstests/replsets/read_after_optime.js @@ -23,7 +23,7 @@ var runTest = function(testDB, primaryConn) { var res = assert.commandFailed(testDB.runCommand({ find: 'user', filter: { x: 1 }, - $readConcern: { + readConcern: { afterOpTime: { ts: twoSecTS, term: 0 } }, maxTimeMS: 1000 @@ -41,7 +41,7 @@ var runTest = function(testDB, primaryConn) { res = assert.commandWorked(testDB.runCommand({ find: 'user', filter: { x: 1 }, - $readConcern: { + readConcern: { afterOpTime: { ts: twoSecTS, term: 0 }, maxTimeMS: 10 * 1000 } diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp index e65f249a66f..61f57fc6283 100644 --- a/src/mongo/db/dbcommands.cpp +++ b/src/mongo/db/dbcommands.cpp @@ -78,8 +78,8 @@ #include "mongo/db/query/query_planner.h" #include "mongo/db/repair_database.h" #include "mongo/db/repl/optime.h" -#include "mongo/db/repl/read_after_optime_args.h" -#include "mongo/db/repl/read_after_optime_response.h" +#include "mongo/db/repl/read_concern_args.h" +#include "mongo/db/repl/read_concern_response.h" #include "mongo/db/repl/repl_client_info.h" #include "mongo/db/repl/repl_settings.h" #include "mongo/db/repl/replication_coordinator_global.h" @@ -1278,7 +1278,7 @@ bool Command::run(OperationContext* txn, repl::ReplicationCoordinator* replCoord = repl::getGlobalReplicationCoordinator(); { // Handle read after opTime. - repl::ReadAfterOpTimeArgs readAfterOptimeSettings; + repl::ReadConcernArgs readAfterOptimeSettings; auto readAfterParseStatus = readAfterOptimeSettings.initialize(request.getCommandArgs()); if (!readAfterParseStatus.isOK()) { replyBuilder->setMetadata(rpc::makeEmptyMetadata()) diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript index f3b333a29b1..8dc72cdc256 100644 --- a/src/mongo/db/query/SConscript +++ b/src/mongo/db/query/SConscript @@ -150,7 +150,7 @@ env.Library( ], LIBDEPS=[ "$BUILD_DIR/mongo/bson/bson", - "$BUILD_DIR/mongo/db/repl/read_after_optime_args", + "$BUILD_DIR/mongo/db/repl/read_concern_args", ], ) diff --git a/src/mongo/db/query/lite_parsed_query.cpp b/src/mongo/db/query/lite_parsed_query.cpp index 494f39aa799..3124f690d51 100644 --- a/src/mongo/db/query/lite_parsed_query.cpp +++ b/src/mongo/db/query/lite_parsed_query.cpp @@ -35,7 +35,7 @@ #include "mongo/client/dbclientinterface.h" #include "mongo/db/dbmessage.h" #include "mongo/db/namespace_string.h" -#include "mongo/db/repl/read_after_optime_args.h" +#include "mongo/db/repl/read_concern_args.h" #include "mongo/util/assert_util.h" #include "mongo/util/mongoutils/str.h" @@ -335,8 +335,8 @@ StatusWith<unique_ptr<LiteParsedQuery>> LiteParsedQuery::makeFromFindCommand(Nam << ". " << "You may need to update your shell or driver."); } - } else if (str::equals(fieldName, repl::ReadAfterOpTimeArgs::kRootFieldName.c_str())) { - // read after optime parsing is handled elsewhere. + } else if (str::equals(fieldName, repl::ReadConcernArgs::kReadConcernFieldName.c_str())) { + // read concern parsing is handled elsewhere. continue; } else if (str::equals(fieldName, kTermField)) { Status status = checkFieldType(el, NumberLong); diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript index 660198f7f47..f3e9a5a196b 100644 --- a/src/mongo/db/repl/SConscript +++ b/src/mongo/db/repl/SConscript @@ -358,9 +358,9 @@ env.Library('replmocks', 'storage_interface', ]) -env.Library('read_after_optime_args', +env.Library('read_concern_args', [ - 'read_after_optime_args.cpp' + 'read_concern_args.cpp' ], LIBDEPS=[ '$BUILD_DIR/mongo/base/base', @@ -373,7 +373,7 @@ env.Library('replica_set_messages', 'handshake_args.cpp', 'is_master_response.cpp', 'member_config.cpp', - 'read_after_optime_response.cpp', + 'read_concern_response.cpp', 'repl_set_declare_election_winner_args.cpp', 'repl_set_heartbeat_args.cpp', 'repl_set_heartbeat_args_v1.cpp', @@ -387,7 +387,7 @@ env.Library('replica_set_messages', 'last_vote.cpp', ], LIBDEPS=[ - 'read_after_optime_args', + 'read_concern_args', '$BUILD_DIR/mongo/bson/bson', '$BUILD_DIR/mongo/bson/util/bson_extract', '$BUILD_DIR/mongo/util/net/hostandport', @@ -557,17 +557,17 @@ env.CppUnitTest( ) env.CppUnitTest( - target='read_after_optime_args_test', + target='read_concern_args_test', source=[ - 'read_after_optime_args_test.cpp', + 'read_concern_args_test.cpp', ], LIBDEPS=['replica_set_messages'] ) env.CppUnitTest( - target='read_after_optime_response_test', + target='read_concern_response_test', source=[ - 'read_after_optime_response_test.cpp', + 'read_concern_response_test.cpp', ], LIBDEPS=['replica_set_messages'] ) diff --git a/src/mongo/db/repl/read_after_optime_args.cpp b/src/mongo/db/repl/read_after_optime_args.cpp deleted file mode 100644 index 532a2b2b9c5..00000000000 --- a/src/mongo/db/repl/read_after_optime_args.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Copyright (C) 2015 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::kReplication - -#include "mongo/platform/basic.h" - -#include "mongo/db/repl/read_after_optime_args.h" - -#include "mongo/bson/util/bson_extract.h" -#include "mongo/db/jsobj.h" -#include "mongo/util/mongoutils/str.h" - -using std::string; - -namespace mongo { -namespace repl { - -const string ReadAfterOpTimeArgs::kRootFieldName("$readConcern"); -const string ReadAfterOpTimeArgs::kOpTimeFieldName("afterOpTime"); -const string ReadAfterOpTimeArgs::kOpTimestampFieldName("ts"); -const string ReadAfterOpTimeArgs::kOpTermFieldName("term"); -const string ReadAfterOpTimeArgs::kReadCommittedFieldName("committed"); - -ReadAfterOpTimeArgs::ReadAfterOpTimeArgs() : ReadAfterOpTimeArgs(OpTime()) {} - -ReadAfterOpTimeArgs::ReadAfterOpTimeArgs(OpTime opTime, bool readCommitted) - : _opTime(std::move(opTime)), _isReadCommitted(readCommitted) {} - -bool ReadAfterOpTimeArgs::isReadCommitted() const { - return _isReadCommitted; -} - -const OpTime& ReadAfterOpTimeArgs::getOpTime() const { - return _opTime; -} - -Status ReadAfterOpTimeArgs::initialize(const BSONObj& cmdObj) { - auto afterElem = cmdObj[ReadAfterOpTimeArgs::kRootFieldName]; - - if (afterElem.eoo()) { - return Status::OK(); - } - - if (!afterElem.isABSONObj()) { - return Status(ErrorCodes::FailedToParse, "'after' field should be an object"); - } - - BSONObj readAfterObj = afterElem.Obj(); - BSONElement opTimeElem; - auto opTimeStatus = bsonExtractTypedField( - readAfterObj, ReadAfterOpTimeArgs::kOpTimeFieldName, Object, &opTimeElem); - - if (!opTimeStatus.isOK()) { - return opTimeStatus; - } - - BSONObj opTimeObj = opTimeElem.Obj(); - BSONElement timestampElem; - - Timestamp timestamp; - auto timestampStatus = bsonExtractTimestampField( - opTimeObj, ReadAfterOpTimeArgs::kOpTimestampFieldName, ×tamp); - - if (!timestampStatus.isOK()) { - return timestampStatus; - } - - long long termNumber; - auto termStatus = - bsonExtractIntegerField(opTimeObj, ReadAfterOpTimeArgs::kOpTermFieldName, &termNumber); - - if (!termStatus.isOK()) { - return termStatus; - } - - _opTime = OpTime(timestamp, termNumber); - - auto readCommittedStatus = bsonExtractBooleanFieldWithDefault( - cmdObj, ReadAfterOpTimeArgs::kReadCommittedFieldName, false, &_isReadCommitted); - if (!readCommittedStatus.isOK()) { - return readCommittedStatus; - } - - return Status::OK(); -} - -} // namespace repl -} // namespace mongo diff --git a/src/mongo/db/repl/read_after_optime_args_test.cpp b/src/mongo/db/repl/read_after_optime_args_test.cpp deleted file mode 100644 index a63ae023dad..00000000000 --- a/src/mongo/db/repl/read_after_optime_args_test.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/** - * Copyright (C) 2015 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. - */ - -#include "mongo/db/jsobj.h" -#include "mongo/db/repl/read_after_optime_args.h" -#include "mongo/unittest/unittest.h" - -namespace mongo { -namespace repl { -namespace { - -TEST(ReadAfterParse, BasicFullSpecification) { - ReadAfterOpTimeArgs readAfterOpTime; - ASSERT_OK(readAfterOpTime.initialize(BSON( - "find" - << "test" << ReadAfterOpTimeArgs::kRootFieldName - << BSON(ReadAfterOpTimeArgs::kOpTimeFieldName - << BSON(ReadAfterOpTimeArgs::kOpTimestampFieldName - << Timestamp(20, 30) << ReadAfterOpTimeArgs::kOpTermFieldName << 2))))); - - ASSERT_EQ(Timestamp(20, 30), readAfterOpTime.getOpTime().getTimestamp()); - ASSERT_EQ(2, readAfterOpTime.getOpTime().getTerm()); - ASSERT_FALSE(readAfterOpTime.isReadCommitted()); -} - -TEST(ReadAfterParse, ReadCommittedFullSpecification) { - ReadAfterOpTimeArgs readAfterOpTime; - ASSERT_OK(readAfterOpTime.initialize(BSON("find" - << "test" << ReadAfterOpTimeArgs::kRootFieldName - << BSON(ReadAfterOpTimeArgs::kOpTimeFieldName << BSON( - ReadAfterOpTimeArgs::kOpTimestampFieldName - << Timestamp(20, 30) - << ReadAfterOpTimeArgs::kOpTermFieldName - << 2)) << "committed" << true))); - - ASSERT_EQ(Timestamp(20, 30), readAfterOpTime.getOpTime().getTimestamp()); - ASSERT_EQ(2, readAfterOpTime.getOpTime().getTerm()); - ASSERT(readAfterOpTime.isReadCommitted()); -} - -TEST(ReadAfterParse, Empty) { - ReadAfterOpTimeArgs readAfterOpTime; - ASSERT_OK(readAfterOpTime.initialize(BSON("find" - << "test"))); - - ASSERT(readAfterOpTime.getOpTime().getTimestamp().isNull()); -} - -TEST(ReadAfterParse, BadRootType) { - ReadAfterOpTimeArgs readAfterOpTime; - ASSERT_NOT_OK( - readAfterOpTime.initialize(BSON("find" - << "test" << ReadAfterOpTimeArgs::kRootFieldName << "x"))); -} - -TEST(ReadAfterParse, BadOpTimeType) { - ReadAfterOpTimeArgs readAfterOpTime; - ASSERT_NOT_OK( - readAfterOpTime.initialize(BSON("find" - << "test" << ReadAfterOpTimeArgs::kRootFieldName - << BSON(ReadAfterOpTimeArgs::kOpTimeFieldName << 2)))); -} - -TEST(ReadAfterParse, OpTimeRequiredIfRootPresent) { - ReadAfterOpTimeArgs readAfterOpTime; - ASSERT_NOT_OK(readAfterOpTime.initialize(BSON("find" - << "test" << ReadAfterOpTimeArgs::kRootFieldName - << BSONObj()))); -} - -TEST(ReadAfterParse, NoOpTimeTS) { - ReadAfterOpTimeArgs readAfterOpTime; - ASSERT_NOT_OK( - readAfterOpTime.initialize(BSON("find" - << "test" << ReadAfterOpTimeArgs::kRootFieldName - << BSON(ReadAfterOpTimeArgs::kOpTimeFieldName << BSON( - ReadAfterOpTimeArgs::kOpTermFieldName << 2))))); -} - -TEST(ReadAfterParse, NoOpTimeTerm) { - ReadAfterOpTimeArgs readAfterOpTime; - ASSERT_NOT_OK( - readAfterOpTime.initialize(BSON("find" - << "test" << ReadAfterOpTimeArgs::kRootFieldName - << BSON(ReadAfterOpTimeArgs::kOpTimeFieldName << BSON( - ReadAfterOpTimeArgs::kOpTermFieldName << 2))))); -} - -TEST(ReadAfterParse, BadOpTimeTSType) { - ReadAfterOpTimeArgs readAfterOpTime; - ASSERT_NOT_OK(readAfterOpTime.initialize( - BSON("find" - << "test" << ReadAfterOpTimeArgs::kRootFieldName - << BSON(ReadAfterOpTimeArgs::kOpTimeFieldName - << BSON(ReadAfterOpTimeArgs::kOpTimestampFieldName - << BSON("x" << 1) << ReadAfterOpTimeArgs::kOpTermFieldName << 2))))); -} - -TEST(ReadAfterParse, BadOpTimeTermType) { - ReadAfterOpTimeArgs readAfterOpTime; - ASSERT_NOT_OK(readAfterOpTime.initialize(BSON( - "find" - << "test" << ReadAfterOpTimeArgs::kRootFieldName - << BSON(ReadAfterOpTimeArgs::kOpTimeFieldName - << BSON(ReadAfterOpTimeArgs::kOpTimestampFieldName - << Timestamp(1, 0) << ReadAfterOpTimeArgs::kOpTermFieldName << "y"))))); -} - -} // unnamed namespace -} // namespace repl -} // namespace mongo diff --git a/src/mongo/db/repl/read_concern_args.cpp b/src/mongo/db/repl/read_concern_args.cpp new file mode 100644 index 00000000000..34141a5f53b --- /dev/null +++ b/src/mongo/db/repl/read_concern_args.cpp @@ -0,0 +1,127 @@ +/** + * Copyright (C) 2015 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::kReplication + +#include "mongo/platform/basic.h" + +#include "mongo/db/repl/read_concern_args.h" + +#include "mongo/bson/util/bson_extract.h" +#include "mongo/db/jsobj.h" +#include "mongo/util/mongoutils/str.h" + +using std::string; + +namespace mongo { +namespace repl { + +const string ReadConcernArgs::kReadConcernFieldName("readConcern"); +const string ReadConcernArgs::kOpTimeFieldName("afterOpTime"); +const string ReadConcernArgs::kOpTimestampFieldName("ts"); +const string ReadConcernArgs::kOpTermFieldName("term"); +const string ReadConcernArgs::kLevelFieldName("level"); + +ReadConcernArgs::ReadConcernArgs() : ReadConcernArgs(OpTime(), ReadConcernLevel::kLocalReadConcern) {} + +ReadConcernArgs::ReadConcernArgs(OpTime opTime, ReadConcernLevel level) + : _opTime(std::move(opTime)), _level(level) {} + +ReadConcernArgs::ReadConcernLevel ReadConcernArgs::getLevel() const { + return _level; +} + +const OpTime& ReadConcernArgs::getOpTime() const { + return _opTime; +} + +Status ReadConcernArgs::initialize(const BSONObj& cmdObj) { + auto readConcernElem = cmdObj[ReadConcernArgs::kReadConcernFieldName]; + + if (readConcernElem.eoo()) { + return Status::OK(); + } + + if (!readConcernElem.isABSONObj()) { + return Status(ErrorCodes::FailedToParse, + str::stream() << kReadConcernFieldName << " field should be an object"); + } + + BSONObj readConcernObj = readConcernElem.Obj(); + BSONElement opTimeElem; + auto opTimeStatus = + bsonExtractTypedField(readConcernObj, kOpTimeFieldName, Object, &opTimeElem); + + if (opTimeStatus.isOK()) { + BSONObj opTimeObj = opTimeElem.Obj(); + BSONElement timestampElem; + + Timestamp timestamp; + auto timestampStatus = + bsonExtractTimestampField(opTimeObj, kOpTimestampFieldName, ×tamp); + + if (!timestampStatus.isOK()) { + return timestampStatus; + } + + long long termNumber; + auto termStatus = bsonExtractIntegerField(opTimeObj, kOpTermFieldName, &termNumber); + + if (!termStatus.isOK()) { + return termStatus; + } + + _opTime = OpTime(timestamp, termNumber); + } else if (opTimeStatus != ErrorCodes::NoSuchKey) { + return opTimeStatus; + } + + std::string levelString; + auto readCommittedStatus = + bsonExtractStringField(readConcernObj, kLevelFieldName, &levelString); + if (readCommittedStatus.isOK()) { + if (levelString == "local") { + _level = ReadConcernLevel::kLocalReadConcern; + } else if (levelString == "majority") { + _level = ReadConcernLevel::kMajorityReadConcern; + } else { + return Status(ErrorCodes::FailedToParse, + str::stream() << kReadConcernFieldName << '.' << kLevelFieldName + << " must be either \"local\" or \"majority\""); + } + } else if (readCommittedStatus == ErrorCodes::NoSuchKey) { + _level = ReadConcernLevel::kLocalReadConcern; + } else { + return readCommittedStatus; + } + + return Status::OK(); +} + +} // namespace repl +} // namespace mongo diff --git a/src/mongo/db/repl/read_after_optime_args.h b/src/mongo/db/repl/read_concern_args.h index 1369c8145ba..90d558b832f 100644 --- a/src/mongo/db/repl/read_after_optime_args.h +++ b/src/mongo/db/repl/read_concern_args.h @@ -40,37 +40,38 @@ class BSONObj; namespace repl { -class ReadAfterOpTimeArgs { +class ReadConcernArgs { public: - static const std::string kRootFieldName; + static const std::string kReadConcernFieldName; + static const std::string kOpTermFieldName; static const std::string kOpTimeFieldName; static const std::string kOpTimestampFieldName; - static const std::string kOpTermFieldName; - static const std::string kReadCommittedFieldName; + static const std::string kLevelFieldName; + + enum class ReadConcernLevel { kLocalReadConcern, kMajorityReadConcern, kLinearizableReadConcern }; - ReadAfterOpTimeArgs(); - explicit ReadAfterOpTimeArgs(OpTime opTime, bool readCommitted = false); + ReadConcernArgs(); + ReadConcernArgs(OpTime opTime, ReadConcernLevel level); /** * Format: * { * find: “coll”, * filter: <Query Object>, - * $readConcern: { // optional - * committed: 1, // optional + * readConcern: { // optional + * level: "[majority|local|linearizable]", * afterOpTime: { ts: <timestamp>, term: <NumberLong> }, * } * } */ Status initialize(const BSONObj& cmdObj); - bool isReadCommitted() const; + ReadConcernLevel getLevel() const; const OpTime& getOpTime() const; - const Milliseconds& getTimeout() const; private: OpTime _opTime; - bool _isReadCommitted = false; + ReadConcernLevel _level; }; } // namespace repl diff --git a/src/mongo/db/repl/read_concern_args_test.cpp b/src/mongo/db/repl/read_concern_args_test.cpp new file mode 100644 index 00000000000..724703e28a0 --- /dev/null +++ b/src/mongo/db/repl/read_concern_args_test.cpp @@ -0,0 +1,154 @@ +/** + * Copyright (C) 2015 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. + */ + +#include "mongo/db/jsobj.h" +#include "mongo/db/repl/read_concern_args.h" +#include "mongo/unittest/unittest.h" + +namespace mongo { +namespace repl { +namespace { + +TEST(ReadAfterParse, BasicFullSpecification) { + ReadConcernArgs readAfterOpTime; + ASSERT_OK(readAfterOpTime.initialize( + BSON("find" + << "test" << ReadConcernArgs::kReadConcernFieldName + << BSON(ReadConcernArgs::kOpTimeFieldName + << BSON(ReadConcernArgs::kOpTimestampFieldName + << Timestamp(20, 30) << ReadConcernArgs::kOpTermFieldName << 2))))); + + ASSERT_EQ(Timestamp(20, 30), readAfterOpTime.getOpTime().getTimestamp()); + ASSERT_EQ(2, readAfterOpTime.getOpTime().getTerm()); + ASSERT(ReadConcernArgs::ReadConcernLevel::kLocalReadConcern == readAfterOpTime.getLevel()); +} + +TEST(ReadAfterParse, ReadCommittedFullSpecification) { + ReadConcernArgs readAfterOpTime; + ASSERT_OK(readAfterOpTime.initialize( + BSON("find" + << "test" << ReadConcernArgs::kReadConcernFieldName + << BSON(ReadConcernArgs::kOpTimeFieldName + << BSON(ReadConcernArgs::kOpTimestampFieldName + << Timestamp(20, 30) << ReadConcernArgs::kOpTermFieldName << 2) + << ReadConcernArgs::kLevelFieldName << "majority")))); + + ASSERT_EQ(Timestamp(20, 30), readAfterOpTime.getOpTime().getTimestamp()); + ASSERT_EQ(2, readAfterOpTime.getOpTime().getTerm()); + ASSERT(ReadConcernArgs::ReadConcernLevel::kMajorityReadConcern == readAfterOpTime.getLevel()); +} + +TEST(ReadAfterParse, Empty) { + ReadConcernArgs readAfterOpTime; + ASSERT_OK(readAfterOpTime.initialize(BSON("find" + << "test"))); + + ASSERT(readAfterOpTime.getOpTime().getTimestamp().isNull()); +} + +TEST(ReadAfterParse, BadRootType) { + ReadConcernArgs readAfterOpTime; + ASSERT_NOT_OK( + readAfterOpTime.initialize(BSON("find" + << "test" << ReadConcernArgs::kReadConcernFieldName + << "x"))); +} + +TEST(ReadAfterParse, BadOpTimeType) { + ReadConcernArgs readAfterOpTime; + ASSERT_NOT_OK( + readAfterOpTime.initialize(BSON("find" + << "test" << ReadConcernArgs::kReadConcernFieldName + << BSON(ReadConcernArgs::kOpTimeFieldName << 2)))); +} + +TEST(ReadAfterParse, OpTimeNotNeededForValidReadConcern) { + ReadConcernArgs readAfterOpTime; + ASSERT_OK(readAfterOpTime.initialize(BSON("find" + << "test" << ReadConcernArgs::kReadConcernFieldName + << BSONObj()))); +} + +TEST(ReadAfterParse, NoOpTimeTS) { + ReadConcernArgs readAfterOpTime; + ASSERT_NOT_OK( + readAfterOpTime.initialize(BSON("find" + << "test" << ReadConcernArgs::kReadConcernFieldName + << BSON(ReadConcernArgs::kOpTimeFieldName + << BSON(ReadConcernArgs::kOpTermFieldName << 2))))); +} + +TEST(ReadAfterParse, NoOpTimeTerm) { + ReadConcernArgs readAfterOpTime; + ASSERT_NOT_OK( + readAfterOpTime.initialize(BSON("find" + << "test" << ReadConcernArgs::kReadConcernFieldName + << BSON(ReadConcernArgs::kOpTimeFieldName + << BSON(ReadConcernArgs::kOpTermFieldName << 2))))); +} + +TEST(ReadAfterParse, BadOpTimeTSType) { + ReadConcernArgs readAfterOpTime; + ASSERT_NOT_OK(readAfterOpTime.initialize( + BSON("find" + << "test" << ReadConcernArgs::kReadConcernFieldName + << BSON(ReadConcernArgs::kOpTimeFieldName + << BSON(ReadConcernArgs::kOpTimestampFieldName + << BSON("x" << 1) << ReadConcernArgs::kOpTermFieldName << 2))))); +} + +TEST(ReadAfterParse, BadOpTimeTermType) { + ReadConcernArgs readAfterOpTime; + ASSERT_NOT_OK(readAfterOpTime.initialize( + BSON("find" + << "test" << ReadConcernArgs::kReadConcernFieldName + << BSON(ReadConcernArgs::kOpTimeFieldName + << BSON(ReadConcernArgs::kOpTimestampFieldName + << Timestamp(1, 0) << ReadConcernArgs::kOpTermFieldName << "y"))))); +} + +TEST(ReadAfterParse, BadLevelType) { + ReadConcernArgs readAfterOpTime; + ASSERT_EQ(ErrorCodes::TypeMismatch, + readAfterOpTime.initialize(BSON("find" + << "test" << ReadConcernArgs::kReadConcernFieldName + << BSON(ReadConcernArgs::kLevelFieldName << 7)))); +} + +TEST(ReadAfterParse, BadLevelValue) { + ReadConcernArgs readAfterOpTime; + ASSERT_EQ(ErrorCodes::FailedToParse, + readAfterOpTime.initialize(BSON("find" + << "test" << ReadConcernArgs::kReadConcernFieldName + << BSON(ReadConcernArgs::kLevelFieldName + << "seven is not a real level")))); +} + +} // unnamed namespace +} // namespace repl +} // namespace mongo diff --git a/src/mongo/db/repl/read_after_optime_response.cpp b/src/mongo/db/repl/read_concern_response.cpp index 332508c9e3c..0b4ffdac470 100644 --- a/src/mongo/db/repl/read_after_optime_response.cpp +++ b/src/mongo/db/repl/read_concern_response.cpp @@ -30,7 +30,7 @@ #include "mongo/platform/basic.h" -#include "mongo/db/repl/read_after_optime_response.h" +#include "mongo/db/repl/read_concern_response.h" #include "mongo/bson/bsonobjbuilder.h" @@ -39,22 +39,22 @@ using std::string; namespace mongo { namespace repl { -const string ReadAfterOpTimeResponse::kWaitedMSFieldName("waitedMS"); +const string ReadConcernResponse::kWaitedMSFieldName("waitedMS"); -ReadAfterOpTimeResponse::ReadAfterOpTimeResponse(Status status) - : ReadAfterOpTimeResponse(status, stdx::chrono::milliseconds(0), false) {} +ReadConcernResponse::ReadConcernResponse(Status status) + : ReadConcernResponse(status, stdx::chrono::milliseconds(0), false) {} -ReadAfterOpTimeResponse::ReadAfterOpTimeResponse() : ReadAfterOpTimeResponse(Status::OK()) {} +ReadConcernResponse::ReadConcernResponse() : ReadConcernResponse(Status::OK()) {} -ReadAfterOpTimeResponse::ReadAfterOpTimeResponse(Status status, stdx::chrono::milliseconds duration) - : ReadAfterOpTimeResponse(status, duration, true) {} +ReadConcernResponse::ReadConcernResponse(Status status, stdx::chrono::milliseconds duration) + : ReadConcernResponse(status, duration, true) {} -ReadAfterOpTimeResponse::ReadAfterOpTimeResponse(Status status, - stdx::chrono::milliseconds duration, - bool waited) +ReadConcernResponse::ReadConcernResponse(Status status, + stdx::chrono::milliseconds duration, + bool waited) : _waited(waited), _duration(duration), _status(status) {} -void ReadAfterOpTimeResponse::appendInfo(BSONObjBuilder* builder) { +void ReadConcernResponse::appendInfo(BSONObjBuilder* builder) { if (!_waited) { return; } @@ -62,15 +62,15 @@ void ReadAfterOpTimeResponse::appendInfo(BSONObjBuilder* builder) { builder->append(kWaitedMSFieldName, durationCount<Milliseconds>(_duration)); } -bool ReadAfterOpTimeResponse::didWait() const { +bool ReadConcernResponse::didWait() const { return _waited; } -stdx::chrono::milliseconds ReadAfterOpTimeResponse::getDuration() const { +stdx::chrono::milliseconds ReadConcernResponse::getDuration() const { return _duration; } -Status ReadAfterOpTimeResponse::getStatus() const { +Status ReadConcernResponse::getStatus() const { return _status; } diff --git a/src/mongo/db/repl/read_after_optime_response.h b/src/mongo/db/repl/read_concern_response.h index 7bd5788dd0f..38773b7e1ac 100644 --- a/src/mongo/db/repl/read_after_optime_response.h +++ b/src/mongo/db/repl/read_concern_response.h @@ -39,24 +39,24 @@ class BSONObjBuilder; namespace repl { -class ReadAfterOpTimeResponse { +class ReadConcernResponse { public: static const std::string kWaitedMSFieldName; /** * Constructs a default response that has OK status, and wait is false. */ - ReadAfterOpTimeResponse(); + ReadConcernResponse(); /** * Constructs a response with the given status with wait equals to false. */ - explicit ReadAfterOpTimeResponse(Status status); + explicit ReadConcernResponse(Status status); /** * Constructs a response with wait set to true along with the given parameters. */ - ReadAfterOpTimeResponse(Status status, stdx::chrono::milliseconds duration); + ReadConcernResponse(Status status, stdx::chrono::milliseconds duration); /** * Appends to the builder the timeout and duration info if didWait() is true. @@ -67,8 +67,8 @@ public: bool didWait() const; /** - * Returns the amount of duration waiting for opTime to pass. - * Valid only if didWait is true. + * Returns the duration waited for the ReadConcern to be satisfied. + * Returns 0 if didWait is false. */ stdx::chrono::milliseconds getDuration() const; @@ -78,10 +78,10 @@ public: Status getStatus() const; private: - ReadAfterOpTimeResponse(Status status, stdx::chrono::milliseconds duration, bool waited); + ReadConcernResponse(Status status, stdx::chrono::milliseconds duration, bool waited); bool _waited; - stdx::chrono::milliseconds _duration; + stdx::chrono::milliseconds _duration = stdx::chrono::milliseconds(0); Status _status; }; diff --git a/src/mongo/db/repl/read_after_optime_response_test.cpp b/src/mongo/db/repl/read_concern_response_test.cpp index 7104fca99b7..4035e47af2b 100644 --- a/src/mongo/db/repl/read_after_optime_response_test.cpp +++ b/src/mongo/db/repl/read_concern_response_test.cpp @@ -27,7 +27,7 @@ */ #include "mongo/db/jsobj.h" -#include "mongo/db/repl/read_after_optime_response.h" +#include "mongo/db/repl/read_concern_response.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -35,7 +35,7 @@ namespace repl { namespace { TEST(ReadAfterResponse, Default) { - ReadAfterOpTimeResponse response; + ReadConcernResponse response; ASSERT_FALSE(response.didWait()); @@ -47,7 +47,7 @@ TEST(ReadAfterResponse, Default) { } TEST(ReadAfterResponse, WithStatus) { - ReadAfterOpTimeResponse response(Status(ErrorCodes::InternalError, "test")); + ReadConcernResponse response(Status(ErrorCodes::InternalError, "test")); ASSERT_FALSE(response.didWait()); @@ -61,8 +61,8 @@ TEST(ReadAfterResponse, WithStatus) { } TEST(ReadAfterResponse, WaitedWithDuration) { - ReadAfterOpTimeResponse response(Status(ErrorCodes::InternalError, "test"), - stdx::chrono::milliseconds(7)); + ReadConcernResponse response(Status(ErrorCodes::InternalError, "test"), + stdx::chrono::milliseconds(7)); ASSERT_TRUE(response.didWait()); ASSERT_EQUALS(Milliseconds(7), response.getDuration()); @@ -72,7 +72,7 @@ TEST(ReadAfterResponse, WaitedWithDuration) { response.appendInfo(&builder); BSONObj obj(builder.done()); - auto waitedMSElem = obj[ReadAfterOpTimeResponse::kWaitedMSFieldName]; + auto waitedMSElem = obj[ReadConcernResponse::kWaitedMSFieldName]; ASSERT_TRUE(waitedMSElem.isNumber()); ASSERT_EQ(7, waitedMSElem.numberLong()); } diff --git a/src/mongo/db/repl/replication_coordinator.h b/src/mongo/db/repl/replication_coordinator.h index 2194139f21d..fb834b270bd 100644 --- a/src/mongo/db/repl/replication_coordinator.h +++ b/src/mongo/db/repl/replication_coordinator.h @@ -56,8 +56,8 @@ class HandshakeArgs; class IsMasterResponse; class OplogReader; class OpTime; -class ReadAfterOpTimeArgs; -class ReadAfterOpTimeResponse; +class ReadConcernArgs; +class ReadConcernResponse; class ReplSetDeclareElectionWinnerArgs; class ReplSetDeclareElectionWinnerResponse; class ReplSetHeartbeatArgs; @@ -294,18 +294,13 @@ public: * Waits until the optime of the current node is at least the opTime specified in * 'settings'. * - * The returned ReadAfterOpTimeResponse object's didWait() method returns true if - * an attempt was made to wait for the specified opTime. Cases when this can be - * false could include: + * The returned ReadConcernResponse object's didWait() method returns true if + * an attempt was made to wait for the specified opTime. This will return false when + * attempting to do read after opTime when node is not a replica set member. * - * 1. No read after opTime was specified. - * 2. Attempting to do read after opTime when node is not a replica set member. - * - * Note: getDuration() on the returned ReadAfterOpTimeResponse will only be valid if - * its didWait() method returns true. */ - virtual ReadAfterOpTimeResponse waitUntilOpTime(OperationContext* txn, - const ReadAfterOpTimeArgs& settings) = 0; + virtual ReadConcernResponse waitUntilOpTime(OperationContext* txn, + const ReadConcernArgs& settings) = 0; /** * Retrieves and returns the current election id, which is a unique id that is local to diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp index 72cb03673ce..937e9e05b4b 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl.cpp @@ -47,8 +47,8 @@ #include "mongo/db/repl/handshake_args.h" #include "mongo/db/repl/is_master_response.h" #include "mongo/db/repl/last_vote.h" -#include "mongo/db/repl/read_after_optime_args.h" -#include "mongo/db/repl/read_after_optime_response.h" +#include "mongo/db/repl/read_concern_args.h" +#include "mongo/db/repl/read_concern_response.h" #include "mongo/db/repl/repl_client_info.h" #include "mongo/db/repl/repl_set_declare_election_winner_args.h" #include "mongo/db/repl/repl_set_heartbeat_args.h" @@ -771,46 +771,34 @@ OpTime ReplicationCoordinatorImpl::getMyLastOptime() const { return _getMyLastOptime_inlock(); } -ReadAfterOpTimeResponse ReplicationCoordinatorImpl::waitUntilOpTime( - OperationContext* txn, const ReadAfterOpTimeArgs& settings) { +ReadConcernResponse ReplicationCoordinatorImpl::waitUntilOpTime(OperationContext* txn, + const ReadConcernArgs& settings) { const auto& ts = settings.getOpTime(); - if (ts.isNull()) { - return ReadAfterOpTimeResponse(); - } - if (getReplicationMode() != repl::ReplicationCoordinator::modeReplSet) { - return ReadAfterOpTimeResponse( + return ReadConcernResponse( Status(ErrorCodes::NotAReplicaSet, "node needs to be a replica set member to use read after opTime")); } -// TODO: SERVER-18298 enable code once V1 protocol is fully implemented. -#if 0 - if (!isV1ElectionProtocol()) { - return ReadAfterOpTimeResponse(Status(ErrorCodes::IncompatibleElectionProtocol, - "node needs to be running on v1 election protocol to " - "use read after opTime")); - } -#endif - Timer timer; stdx::unique_lock<stdx::mutex> lock(_mutex); - auto loopCondition = [this, settings, ts] { - return settings.isReadCommitted() - ? !_currentCommittedSnapshot || ts > *_currentCommittedSnapshot - : ts > _getMyLastOptime_inlock(); + bool isMajorityReadConcern = + settings.getLevel() == ReadConcernArgs::ReadConcernLevel::kMajorityReadConcern; + auto loopCondition = [this, isMajorityReadConcern, ts] { + return isMajorityReadConcern ? !_currentCommittedSnapshot || ts > *_currentCommittedSnapshot + : ts > _getMyLastOptime_inlock(); }; while (loopCondition()) { Status interruptedStatus = txn->checkForInterruptNoAssert(); if (!interruptedStatus.isOK()) { - return ReadAfterOpTimeResponse(interruptedStatus, Milliseconds(timer.millis())); + return ReadConcernResponse(interruptedStatus, Milliseconds(timer.millis())); } if (_inShutdown) { - return ReadAfterOpTimeResponse(Status(ErrorCodes::ShutdownInProgress, "shutting down"), - Milliseconds(timer.millis())); + return ReadConcernResponse(Status(ErrorCodes::ShutdownInProgress, "shutting down"), + Milliseconds(timer.millis())); } stdx::condition_variable condVar; @@ -820,7 +808,7 @@ ReadAfterOpTimeResponse ReplicationCoordinatorImpl::waitUntilOpTime( WaiterInfo waitInfo(&_opTimeWaiterList, txn->getOpID(), &ts, - settings.isReadCommitted() ? &writeConcern : nullptr, + isMajorityReadConcern ? &writeConcern : nullptr, &condVar); if (CurOp::get(txn)->isMaxTimeSet()) { @@ -830,7 +818,7 @@ ReadAfterOpTimeResponse ReplicationCoordinatorImpl::waitUntilOpTime( } } - return ReadAfterOpTimeResponse(Status::OK(), Milliseconds(timer.millis())); + return ReadConcernResponse(Status::OK(), Milliseconds(timer.millis())); } OpTime ReplicationCoordinatorImpl::_getMyLastOptime_inlock() const { diff --git a/src/mongo/db/repl/replication_coordinator_impl.h b/src/mongo/db/repl/replication_coordinator_impl.h index 831f753b012..76aa2f4236d 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.h +++ b/src/mongo/db/repl/replication_coordinator_impl.h @@ -156,8 +156,8 @@ public: virtual OpTime getMyLastOptime() const override; - virtual ReadAfterOpTimeResponse waitUntilOpTime(OperationContext* txn, - const ReadAfterOpTimeArgs& settings) override; + virtual ReadConcernResponse waitUntilOpTime(OperationContext* txn, + const ReadConcernArgs& settings) override; virtual OID getElectionId() override; diff --git a/src/mongo/db/repl/replication_coordinator_impl_test.cpp b/src/mongo/db/repl/replication_coordinator_impl_test.cpp index 3304595ed8b..c72fb88f4ed 100644 --- a/src/mongo/db/repl/replication_coordinator_impl_test.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl_test.cpp @@ -40,8 +40,8 @@ #include "mongo/db/repl/is_master_response.h" #include "mongo/db/repl/operation_context_repl_mock.h" #include "mongo/db/repl/optime.h" -#include "mongo/db/repl/read_after_optime_args.h" -#include "mongo/db/repl/read_after_optime_response.h" +#include "mongo/db/repl/read_concern_args.h" +#include "mongo/db/repl/read_concern_response.h" #include "mongo/db/repl/repl_set_heartbeat_args.h" #include "mongo/db/repl/repl_settings.h" #include "mongo/db/repl/replica_set_config.h" @@ -2064,8 +2064,9 @@ TEST_F(ReplCoordTest, LastCommittedOpTime) { TEST_F(ReplCoordTest, CantUseReadAfterIfNotReplSet) { init(ReplSettings()); OperationContextNoop txn; - auto result = - getReplCoord()->waitUntilOpTime(&txn, ReadAfterOpTimeArgs(OpTimeWithTermZero(50, 0))); + auto result = getReplCoord()->waitUntilOpTime( + &txn, + ReadConcernArgs(OpTimeWithTermZero(50, 0), ReadConcernArgs::ReadConcernLevel::kLocalReadConcern)); ASSERT_FALSE(result.didWait()); ASSERT_EQUALS(ErrorCodes::NotAReplicaSet, result.getStatus()); @@ -2084,8 +2085,9 @@ TEST_F(ReplCoordTest, ReadAfterWhileShutdown) { shutdown(); - auto result = - getReplCoord()->waitUntilOpTime(&txn, ReadAfterOpTimeArgs(OpTimeWithTermZero(50, 0))); + auto result = getReplCoord()->waitUntilOpTime( + &txn, + ReadConcernArgs(OpTimeWithTermZero(50, 0), ReadConcernArgs::ReadConcernLevel::kLocalReadConcern)); ASSERT_TRUE(result.didWait()); ASSERT_EQUALS(ErrorCodes::ShutdownInProgress, result.getStatus()); @@ -2104,8 +2106,9 @@ TEST_F(ReplCoordTest, ReadAfterInterrupted) { txn.setCheckForInterruptStatus(Status(ErrorCodes::Interrupted, "test")); - auto result = - getReplCoord()->waitUntilOpTime(&txn, ReadAfterOpTimeArgs(OpTimeWithTermZero(50, 0))); + auto result = getReplCoord()->waitUntilOpTime( + &txn, + ReadConcernArgs(OpTimeWithTermZero(50, 0), ReadConcernArgs::ReadConcernLevel::kLocalReadConcern)); ASSERT_TRUE(result.didWait()); ASSERT_EQUALS(ErrorCodes::Interrupted, result.getStatus()); @@ -2120,9 +2123,9 @@ TEST_F(ReplCoordTest, ReadAfterNoOpTime) { << "_id" << 0))), HostAndPort("node1", 12345)); - auto result = getReplCoord()->waitUntilOpTime(&txn, ReadAfterOpTimeArgs()); + auto result = getReplCoord()->waitUntilOpTime(&txn, ReadConcernArgs()); - ASSERT_FALSE(result.didWait()); + ASSERT(result.didWait()); ASSERT_OK(result.getStatus()); } @@ -2136,8 +2139,9 @@ TEST_F(ReplCoordTest, ReadAfterGreaterOpTime) { HostAndPort("node1", 12345)); getReplCoord()->setMyLastOptime(OpTimeWithTermZero(100, 0)); - auto result = - getReplCoord()->waitUntilOpTime(&txn, ReadAfterOpTimeArgs(OpTimeWithTermZero(50, 0))); + auto result = getReplCoord()->waitUntilOpTime( + &txn, + ReadConcernArgs(OpTimeWithTermZero(50, 0), ReadConcernArgs::ReadConcernLevel::kLocalReadConcern)); ASSERT_TRUE(result.didWait()); ASSERT_OK(result.getStatus()); @@ -2155,7 +2159,8 @@ TEST_F(ReplCoordTest, ReadAfterEqualOpTime) { OpTimeWithTermZero time(100, 0); getReplCoord()->setMyLastOptime(time); - auto result = getReplCoord()->waitUntilOpTime(&txn, ReadAfterOpTimeArgs(time)); + auto result = getReplCoord()->waitUntilOpTime( + &txn, ReadConcernArgs(time, ReadConcernArgs::ReadConcernLevel::kLocalReadConcern)); ASSERT_TRUE(result.didWait()); ASSERT_OK(result.getStatus()); @@ -2178,8 +2183,9 @@ TEST_F(ReplCoordTest, ReadAfterDeferredGreaterOpTime) { getReplCoord()->setMyLastOptime(OpTimeWithTermZero(200, 0)); }); - auto result = - getReplCoord()->waitUntilOpTime(&txn, ReadAfterOpTimeArgs(OpTimeWithTermZero(100, 0))); + auto result = getReplCoord()->waitUntilOpTime( + &txn, + ReadConcernArgs(OpTimeWithTermZero(100, 0), ReadConcernArgs::ReadConcernLevel::kLocalReadConcern)); pseudoLogOp.get(); ASSERT_TRUE(result.didWait()); @@ -2205,7 +2211,8 @@ TEST_F(ReplCoordTest, ReadAfterDeferredEqualOpTime) { getReplCoord()->setMyLastOptime(opTimeToWait); }); - auto result = getReplCoord()->waitUntilOpTime(&txn, ReadAfterOpTimeArgs(opTimeToWait)); + auto result = getReplCoord()->waitUntilOpTime( + &txn, ReadConcernArgs(opTimeToWait, ReadConcernArgs::ReadConcernLevel::kLocalReadConcern)); pseudoLogOp.get(); ASSERT_TRUE(result.didWait()); @@ -2216,7 +2223,8 @@ TEST_F(ReplCoordTest, CantUseReadAfterCommittedIfNotReplSet) { init(ReplSettings()); OperationContextNoop txn; auto result = getReplCoord()->waitUntilOpTime( - &txn, ReadAfterOpTimeArgs(OpTime(Timestamp(50, 0), 0), true)); + &txn, + ReadConcernArgs(OpTime(Timestamp(50, 0), 0), ReadConcernArgs::ReadConcernLevel::kMajorityReadConcern)); ASSERT_FALSE(result.didWait()); ASSERT_EQUALS(ErrorCodes::NotAReplicaSet, result.getStatus()); @@ -2237,7 +2245,8 @@ TEST_F(ReplCoordTest, ReadAfterCommittedWhileShutdown) { shutdown(); auto result = getReplCoord()->waitUntilOpTime( - &txn, ReadAfterOpTimeArgs(OpTime(Timestamp(50, 0), 0), true)); + &txn, + ReadConcernArgs(OpTime(Timestamp(50, 0), 0), ReadConcernArgs::ReadConcernLevel::kMajorityReadConcern)); ASSERT_TRUE(result.didWait()); ASSERT_EQUALS(ErrorCodes::ShutdownInProgress, result.getStatus()); @@ -2258,7 +2267,8 @@ TEST_F(ReplCoordTest, ReadAfterCommittedInterrupted) { txn.setCheckForInterruptStatus(Status(ErrorCodes::Interrupted, "test")); auto result = getReplCoord()->waitUntilOpTime( - &txn, ReadAfterOpTimeArgs(OpTime(Timestamp(50, 0), 0), true)); + &txn, + ReadConcernArgs(OpTime(Timestamp(50, 0), 0), ReadConcernArgs::ReadConcernLevel::kMajorityReadConcern)); ASSERT_TRUE(result.didWait()); ASSERT_EQUALS(ErrorCodes::Interrupted, result.getStatus()); @@ -2277,7 +2287,8 @@ TEST_F(ReplCoordTest, ReadAfterCommittedGreaterOpTime) { getReplCoord()->setMyLastOptime(OpTime(Timestamp(100, 0), 0)); getReplCoord()->onSnapshotCreate(OpTime(Timestamp(100, 0), 0)); auto result = getReplCoord()->waitUntilOpTime( - &txn, ReadAfterOpTimeArgs(OpTime(Timestamp(50, 0), 0), true)); + &txn, + ReadConcernArgs(OpTime(Timestamp(50, 0), 0), ReadConcernArgs::ReadConcernLevel::kMajorityReadConcern)); ASSERT_TRUE(result.didWait()); ASSERT_OK(result.getStatus()); @@ -2297,7 +2308,8 @@ TEST_F(ReplCoordTest, ReadAfterCommittedEqualOpTime) { OpTime time(Timestamp(100, 0), 0); getReplCoord()->setMyLastOptime(time); getReplCoord()->onSnapshotCreate(time); - auto result = getReplCoord()->waitUntilOpTime(&txn, ReadAfterOpTimeArgs(time, true)); + auto result = getReplCoord()->waitUntilOpTime( + &txn, ReadConcernArgs(time, ReadConcernArgs::ReadConcernLevel::kMajorityReadConcern)); ASSERT_TRUE(result.didWait()); ASSERT_OK(result.getStatus()); @@ -2323,7 +2335,9 @@ TEST_F(ReplCoordTest, ReadAfterCommittedDeferredGreaterOpTime) { }); auto result = getReplCoord()->waitUntilOpTime( - &txn, ReadAfterOpTimeArgs(OpTime(Timestamp(100, 0), 0), true)); + &txn, + ReadConcernArgs(OpTime(Timestamp(100, 0), 0), + ReadConcernArgs::ReadConcernLevel::kMajorityReadConcern)); pseudoLogOp.get(); ASSERT_TRUE(result.didWait()); @@ -2351,7 +2365,8 @@ TEST_F(ReplCoordTest, ReadAfterCommittedDeferredEqualOpTime) { getReplCoord()->onSnapshotCreate(opTimeToWait); }); - auto result = getReplCoord()->waitUntilOpTime(&txn, ReadAfterOpTimeArgs(opTimeToWait, true)); + auto result = getReplCoord()->waitUntilOpTime( + &txn, ReadConcernArgs(opTimeToWait, ReadConcernArgs::ReadConcernLevel::kMajorityReadConcern)); pseudoLogOp.get(); ASSERT_TRUE(result.didWait()); diff --git a/src/mongo/db/repl/replication_coordinator_mock.cpp b/src/mongo/db/repl/replication_coordinator_mock.cpp index f4abe7d8167..a3f156a0afc 100644 --- a/src/mongo/db/repl/replication_coordinator_mock.cpp +++ b/src/mongo/db/repl/replication_coordinator_mock.cpp @@ -33,8 +33,8 @@ #include "mongo/base/status.h" #include "mongo/db/namespace_string.h" #include "mongo/db/write_concern_options.h" -#include "mongo/db/repl/read_after_optime_args.h" -#include "mongo/db/repl/read_after_optime_response.h" +#include "mongo/db/repl/read_concern_args.h" +#include "mongo/db/repl/read_concern_response.h" #include "mongo/db/repl/replica_set_config.h" #include "mongo/util/assert_util.h" @@ -153,9 +153,9 @@ OpTime ReplicationCoordinatorMock::getMyLastOptime() const { return _myLastOpTime; } -ReadAfterOpTimeResponse ReplicationCoordinatorMock::waitUntilOpTime( - OperationContext* txn, const ReadAfterOpTimeArgs& settings) { - return ReadAfterOpTimeResponse(); +ReadConcernResponse ReplicationCoordinatorMock::waitUntilOpTime(OperationContext* txn, + const ReadConcernArgs& settings) { + return ReadConcernResponse(); } diff --git a/src/mongo/db/repl/replication_coordinator_mock.h b/src/mongo/db/repl/replication_coordinator_mock.h index f11788a60a9..7c8324bb966 100644 --- a/src/mongo/db/repl/replication_coordinator_mock.h +++ b/src/mongo/db/repl/replication_coordinator_mock.h @@ -99,8 +99,8 @@ public: virtual OpTime getMyLastOptime() const; - virtual ReadAfterOpTimeResponse waitUntilOpTime(OperationContext* txn, - const ReadAfterOpTimeArgs& settings) override; + virtual ReadConcernResponse waitUntilOpTime(OperationContext* txn, + const ReadConcernArgs& settings) override; virtual OID getElectionId(); |