diff options
author | Henrik Edin <henrik.edin@mongodb.com> | 2022-08-08 20:38:33 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-09-08 14:45:19 +0000 |
commit | 0f496dfbfb76cf797833058c5b81d6910557896a (patch) | |
tree | 2b9d829ae022e9b04a8403c2df13ef431c1dbc12 | |
parent | 3375460229a466b04863bbd8f0ab6d9f4199b868 (diff) | |
download | mongo-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.js | 6 | ||||
-rw-r--r-- | src/mongo/db/storage/snapshot_helper.cpp | 15 |
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; |