/** * Apply the read concern from the cursor to this operation. */ void applyCursorReadConcern(OperationContext* opCtx, repl::ReadConcernArgs rcArgs) { const auto replicationMode = repl::ReplicationCoordinator::get(opCtx)->getReplicationMode(); // Select the appropriate read source. if (replicationMode == repl::ReplicationCoordinator::modeReplSet && rcArgs.getLevel() == repl::ReadConcernLevel::kMajorityReadConcern) { switch (rcArgs.getMajorityReadMechanism()) { case repl::ReadConcernArgs::MajorityReadMechanism::kMajoritySnapshot: { // Make sure we read from the majority snapshot. opCtx->recoveryUnit()->setTimestampReadSource( RecoveryUnit::ReadSource::kMajorityCommitted); uassertStatusOK(opCtx->recoveryUnit()->obtainMajorityCommittedSnapshot()); break; } case repl::ReadConcernArgs::MajorityReadMechanism::kSpeculative: { // Mark the operation as speculative and select the correct read source. repl::SpeculativeMajorityReadInfo::get(opCtx).setIsSpeculativeRead(); opCtx->recoveryUnit()->setTimestampReadSource(RecoveryUnit::ReadSource::kNoOverlap); break; } } } // For cursor commands that take locks internally, the read concern on the // OperationContext may affect the timestamp read source selected by the storage engine. // We place the cursor read concern onto the OperationContext so the lock acquisition // respects the cursor's read concern. { stdx::lock_guard<Client> lk(*opCtx->getClient()); repl::ReadConcernArgs::get(opCtx) = rcArgs; } }
Status waitForReadConcern(OperationContext* txn, const repl::ReadConcernArgs& readConcernArgs) { repl::ReplicationCoordinator* const replCoord = repl::ReplicationCoordinator::get(txn); if (readConcernArgs.getLevel() == repl::ReadConcernLevel::kLinearizableReadConcern) { if (replCoord->getReplicationMode() != repl::ReplicationCoordinator::modeReplSet) { // For master/slave and standalone nodes, Linearizable Read is not supported. return {ErrorCodes::NotAReplicaSet, "node needs to be a replica set member to use read concern"}; } // Replica sets running pv0 do not support linearizable read concern until further testing // is completed (SERVER-27025). if (!replCoord->isV1ElectionProtocol()) { return { ErrorCodes::IncompatibleElectionProtocol, "Replica sets running protocol version 0 do not support readConcern: linearizable"}; } if (!readConcernArgs.getOpTime().isNull()) { return {ErrorCodes::FailedToParse, "afterOpTime not compatible with linearizable read concern"}; } if (!replCoord->getMemberState().primary()) { return {ErrorCodes::NotMaster, "cannot satisfy linearizable read concern on non-primary node"}; } } // Skip waiting for the OpTime when testing snapshot behavior if (!testingSnapshotBehaviorInIsolation && !readConcernArgs.isEmpty()) { Status status = replCoord->waitUntilOpTimeForRead(txn, readConcernArgs); if (!status.isOK()) { return status; } } if ((replCoord->getReplicationMode() == repl::ReplicationCoordinator::Mode::modeReplSet || testingSnapshotBehaviorInIsolation) && readConcernArgs.getLevel() == repl::ReadConcernLevel::kMajorityReadConcern) { // ReadConcern Majority is not supported in ProtocolVersion 0. if (!testingSnapshotBehaviorInIsolation && !replCoord->isV1ElectionProtocol()) { return {ErrorCodes::ReadConcernMajorityNotEnabled, str::stream() << "Replica sets running protocol version 0 do not support " "readConcern: majority"}; } const int debugLevel = serverGlobalParams.clusterRole == ClusterRole::ConfigServer ? 1 : 2; LOG(debugLevel) << "Waiting for 'committed' snapshot to be available for reading: " << readConcernArgs; Status status = txn->recoveryUnit()->setReadFromMajorityCommittedSnapshot(); // Wait until a snapshot is available. while (status == ErrorCodes::ReadConcernMajorityNotAvailableYet) { LOG(debugLevel) << "Snapshot not available yet."; replCoord->waitUntilSnapshotCommitted(txn, SnapshotName::min()); status = txn->recoveryUnit()->setReadFromMajorityCommittedSnapshot(); } if (!status.isOK()) { return status; } LOG(debugLevel) << "Using 'committed' snapshot: " << CurOp::get(txn)->query(); } return Status::OK(); }