summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/core/read_after_optime.js2
-rw-r--r--jstests/noPassthrough/read_majority.js15
-rw-r--r--jstests/replsets/read_after_optime.js4
-rw-r--r--src/mongo/db/dbcommands.cpp6
-rw-r--r--src/mongo/db/query/SConscript2
-rw-r--r--src/mongo/db/query/lite_parsed_query.cpp6
-rw-r--r--src/mongo/db/repl/SConscript16
-rw-r--r--src/mongo/db/repl/read_after_optime_args.cpp114
-rw-r--r--src/mongo/db/repl/read_after_optime_args_test.cpp136
-rw-r--r--src/mongo/db/repl/read_concern_args.cpp127
-rw-r--r--src/mongo/db/repl/read_concern_args.h (renamed from src/mongo/db/repl/read_after_optime_args.h)23
-rw-r--r--src/mongo/db/repl/read_concern_args_test.cpp154
-rw-r--r--src/mongo/db/repl/read_concern_response.cpp (renamed from src/mongo/db/repl/read_after_optime_response.cpp)28
-rw-r--r--src/mongo/db/repl/read_concern_response.h (renamed from src/mongo/db/repl/read_after_optime_response.h)16
-rw-r--r--src/mongo/db/repl/read_concern_response_test.cpp (renamed from src/mongo/db/repl/read_after_optime_response_test.cpp)12
-rw-r--r--src/mongo/db/repl/replication_coordinator.h19
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl.cpp42
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl.h4
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl_test.cpp61
-rw-r--r--src/mongo/db/repl/replication_coordinator_mock.cpp10
-rw-r--r--src/mongo/db/repl/replication_coordinator_mock.h4
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, &timestamp);
-
- 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, &timestamp);
+
+ 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();