summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenrik Edin <henrik.edin@mongodb.com>2022-08-08 20:38:33 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-09-08 14:45:19 +0000
commit0f496dfbfb76cf797833058c5b81d6910557896a (patch)
tree2b9d829ae022e9b04a8403c2df13ef431c1dbc12
parent3375460229a466b04863bbd8f0ab6d9f4199b868 (diff)
downloadmongo-0f496dfbfb76cf797833058c5b81d6910557896a.tar.gz
SERVER-67402 Fix race where linearizable read concern may read during primary catchup
(cherry picked from commit f62d857f440e1340c7338d81c128d0682305f777)
-rw-r--r--jstests/replsets/stepup_with_linearizable_read.js6
-rw-r--r--src/mongo/db/storage/snapshot_helper.cpp15
2 files changed, 13 insertions, 8 deletions
diff --git a/jstests/replsets/stepup_with_linearizable_read.js b/jstests/replsets/stepup_with_linearizable_read.js
index abbc2753252..4d3942c8fcf 100644
--- a/jstests/replsets/stepup_with_linearizable_read.js
+++ b/jstests/replsets/stepup_with_linearizable_read.js
@@ -31,12 +31,12 @@ var sendLinearizableReadOnFailpoint = function() {
jsTestLog('Sending in linearizable read in secondary thread');
- // In lock free reads this will timeout as we cannot perform the necessary write after the
- // read. Without lock free reads we timeout because we can't acquire the RSTL.
+ // In lock free reads this will error with NotWritablePrimary. Without lock free reads we
+ // timeout because we can't acquire the RSTL.
assert.commandFailedWithCode(
coll.runCommand(
{'find': 'foo', readConcern: {level: "linearizable"}, maxTimeMS: 10000}),
- ErrorCodes.MaxTimeMSExpired);
+ [ErrorCodes.NotWritablePrimary, ErrorCodes.MaxTimeMSExpired]);
} finally {
// Turn off fail point so we can cleanup.
assert.commandWorked(db.getMongo().adminCommand(
diff --git a/src/mongo/db/storage/snapshot_helper.cpp b/src/mongo/db/storage/snapshot_helper.cpp
index f4502834964..89419856849 100644
--- a/src/mongo/db/storage/snapshot_helper.cpp
+++ b/src/mongo/db/storage/snapshot_helper.cpp
@@ -117,13 +117,18 @@ bool shouldReadAtLastApplied(OperationContext* opCtx,
}
// Linearizable read concern should never be read at lastApplied, they must always read from
- // latest and are only allowed on primaries.
+ // latest and are only allowed on primaries. We are either a primary not accepting writes or
+ // secondary at this point, neither which can satisfy the noop write after the read. However, if
+ // we manage to transition to a writable primary when we do the noop write we may have read data
+ // during oplog application with kNoTimestamp which should be an error. In both cases it is OK
+ // to error with NotWritablePrimary here and we do not need to do any further checks after
+ // acquiring the snapshot because state transitions causes the repl term to increment and we
+ // can't transition directly from primary to primary catchup without a repl term increase
+ // happening.
if (repl::ReadConcernArgs::get(opCtx).getLevel() ==
repl::ReadConcernLevel::kLinearizableReadConcern) {
- if (reason) {
- *reason = "linearizable read concern";
- }
- return false;
+ uasserted(ErrorCodes::NotWritablePrimary,
+ "cannot satisfy linearizable read concern on non-primary node");
}
return true;