Status ReplicationCoordinatorImpl::setLastOptime(OperationContext* txn, const OID& rid, const OpTime& ts) { boost::lock_guard<boost::mutex> lk(_mutex); OpTime& slaveOpTime = _slaveInfoMap[rid].opTime; if (slaveOpTime < ts) { slaveOpTime = ts; // TODO(spencer): update write concern tags if we're a replSet // Wake up any threads waiting for replication that now have their replication // check satisfied for (std::vector<WaiterInfo*>::iterator it = _replicationWaiterList.begin(); it != _replicationWaiterList.end(); ++it) { WaiterInfo* info = *it; if (_opReplicatedEnough_inlock(*info->opTime, *info->writeConcern)) { info->condVar->notify_all(); } } } if (_getReplicationMode_inlock() == modeReplSet && !_getCurrentMemberState_inlock().primary()) { // pass along if we are not primary _externalState->forwardSlaveProgress(); } return Status::OK(); }
ReplicationCoordinator::StatusAndDuration ReplicationCoordinatorImpl::awaitReplication( const OperationContext* txn, const OpTime& opId, const WriteConcernOptions& writeConcern) { // TODO(spencer): handle killop if (writeConcern.wNumNodes <= 1 && writeConcern.wMode.empty()) { // no desired replication check return StatusAndDuration(Status::OK(), Milliseconds(0)); } Timer timer; boost::unique_lock<boost::mutex> lk(_mutex); const Mode replMode = _getReplicationMode_inlock(); if (replMode == modeNone || serverGlobalParams.configsvr) { // no replication check needed (validated above) return StatusAndDuration(Status::OK(), Milliseconds(0)); } if (writeConcern.wMode == "majority" && replMode == modeMasterSlave) { // with master/slave, majority is equivalent to w=1 return StatusAndDuration(Status::OK(), Milliseconds(0)); } boost::condition_variable condVar; // Must hold _mutex before constructing waitInfo as it will modify _replicationWaiterList WaiterInfo waitInfo(&_replicationWaiterList, &opId, &writeConcern, &condVar); while (!_opReplicatedEnough_inlock(opId, writeConcern)) { const int elapsed = timer.millis(); if (writeConcern.wTimeout != WriteConcernOptions::kNoTimeout && elapsed > writeConcern.wTimeout) { return StatusAndDuration(Status(ErrorCodes::ExceededTimeLimit, "waiting for replication timed out"), Milliseconds(elapsed)); } if (_inShutdown) { return StatusAndDuration(Status(ErrorCodes::ShutdownInProgress, "Replication is being shut down"), Milliseconds(elapsed)); } try { if (writeConcern.wTimeout == WriteConcernOptions::kNoTimeout) { condVar.wait(lk); } else { condVar.timed_wait(lk, Milliseconds(writeConcern.wTimeout - elapsed)); } } catch (const boost::thread_interrupted&) {} } return StatusAndDuration(Status::OK(), Milliseconds(timer.millis())); }
Status ReplicationCoordinatorImpl::setLastOptime(const OID& rid, const OpTime& ts) { // TODO(spencer): update slave tracking thread for local.slaves // TODO(spencer): pass info upstream if we're not primary boost::lock_guard<boost::mutex> lk(_mutex); OpTime& slaveOpTime = _slaveOpTimeMap[rid]; if (slaveOpTime < ts) { slaveOpTime = ts; // TODO(spencer): update write concern tags if we're a replSet // Wake up any threads waiting for replication that now have their replication // check satisfied for (std::vector<WaiterInfo*>::iterator it = _replicationWaiterList.begin(); it != _replicationWaiterList.end(); ++it) { WaiterInfo* info = *it; if (_opReplicatedEnough_inlock(*info->opTime, *info->writeConcern)) { info->condVar->notify_all(); } } } return Status::OK(); }