diff options
author | Vesselina Ratcheva <vesselina.ratcheva@10gen.com> | 2018-06-15 17:03:24 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-04-04 16:31:29 +0000 |
commit | 0395f6fae741624906529958d091c8762e72b594 (patch) | |
tree | f80fff87a897bca161d07707db0fe4bf8c09890a | |
parent | 814b4e99722f87af7e6e7d9b15f68444b00f9f8d (diff) | |
download | mongo-0395f6fae741624906529958d091c8762e72b594.tar.gz |
SERVER-35058 Defer removing ReplicationCoordinator ThreadWaiters to their WaiterGuards
(cherry picked from commit 9df6cbae9c20bdce759deb806e5175b7fc83d007)
-rw-r--r-- | src/mongo/db/repl/replication_coordinator_impl.cpp | 36 | ||||
-rw-r--r-- | src/mongo/db/repl/replication_coordinator_impl.h | 17 |
2 files changed, 34 insertions, 19 deletions
diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp index fdc10af2565..4fd3dce522a 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl.cpp @@ -233,16 +233,26 @@ void ReplicationCoordinatorImpl::WaiterList::add_inlock(WaiterType waiter) { _list.push_back(waiter); } -void ReplicationCoordinatorImpl::WaiterList::signalAndRemoveIf_inlock( +void ReplicationCoordinatorImpl::WaiterList::signalIf_inlock( stdx::function<bool(WaiterType)> func) { - // Only advance iterator when the element doesn't match. for (auto it = _list.begin(); it != _list.end();) { if (!func(*it)) { + // This element doesn't match, so we advance the iterator to the next one. ++it; continue; } + if (!(*it)->runs_once()) { + (*it)->notify_inlock(); + // Keep the waiter on the list and let the guard remove it instead. Advance the + // iterator since we are skipping the removal. + ++it; + continue; + } + + // Remove the waiter from the list if it was only meant to be notified once. WaiterType waiter = std::move(*it); + if (it == std::prev(_list.end())) { // Iterator will be invalid after erasing the last element, so set it to the // next one (i.e. end()). @@ -252,19 +262,15 @@ void ReplicationCoordinatorImpl::WaiterList::signalAndRemoveIf_inlock( std::swap(*it, _list.back()); _list.pop_back(); } - // It's important to call notify() after the waiter has been removed from the list // since notify() might remove the waiter itself. waiter->notify_inlock(); } } -void ReplicationCoordinatorImpl::WaiterList::signalAndRemoveAll_inlock() { - std::vector<WaiterType> list = std::move(_list); - // Call notify() after removing the waiters from the list. - for (auto& waiter : list) { - waiter->notify_inlock(); - } + +void ReplicationCoordinatorImpl::WaiterList::signalAll_inlock() { + this->signalIf_inlock([](Waiter* waiter) { return true; }); } bool ReplicationCoordinatorImpl::WaiterList::remove_inlock(WaiterType waiter) { @@ -829,8 +835,8 @@ void ReplicationCoordinatorImpl::shutdown(OperationContext* opCtx) { lk.lock(); fassert(18823, _rsConfigState != kConfigStartingUp); } - _replicationWaiterList.signalAndRemoveAll_inlock(); - _opTimeWaiterList.signalAndRemoveAll_inlock(); + _replicationWaiterList.signalAll_inlock(); + _opTimeWaiterList.signalAll_inlock(); _currentCommittedSnapshotCond.notify_all(); _initialSyncer.swap(initialSyncerCopy); _stepDownWaiters.notify_all(); @@ -1181,7 +1187,7 @@ void ReplicationCoordinatorImpl::_setMyLastAppliedOpTime_inlock(const OpTime& op } // Signal anyone waiting on optime changes. - _opTimeWaiterList.signalAndRemoveIf_inlock( + _opTimeWaiterList.signalIf_inlock( [opTime](Waiter* waiter) { return waiter->opTime <= opTime; }); @@ -2704,9 +2710,9 @@ ReplicationCoordinatorImpl::_updateMemberStateFromTopologyCoordinator_inlock( PostMemberStateUpdateAction result; if (_memberState.primary() || newState.removed() || newState.rollback()) { // Wake up any threads blocked in awaitReplication, close connections, etc. - _replicationWaiterList.signalAndRemoveAll_inlock(); + _replicationWaiterList.signalAll_inlock(); // Wake up the optime waiter that is waiting for primary catch-up to finish. - _opTimeWaiterList.signalAndRemoveAll_inlock(); + _opTimeWaiterList.signalAll_inlock(); // If there are any pending stepdown command requests wake them up. _stepDownWaiters.notify_all(); @@ -3186,7 +3192,7 @@ ReplicationCoordinatorImpl::_setCurrentRSConfig_inlock(OperationContext* opCtx, } void ReplicationCoordinatorImpl::_wakeReadyWaiters_inlock() { - _replicationWaiterList.signalAndRemoveIf_inlock([this](Waiter* waiter) { + _replicationWaiterList.signalIf_inlock([this](Waiter* waiter) { return _doneWaitingForReplication_inlock( waiter->opTime, Timestamp(), *waiter->writeConcern); }); diff --git a/src/mongo/db/repl/replication_coordinator_impl.h b/src/mongo/db/repl/replication_coordinator_impl.h index cd690f6d4df..95586556653 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.h +++ b/src/mongo/db/repl/replication_coordinator_impl.h @@ -476,6 +476,9 @@ private: BSONObj toBSON() const; std::string toString() const; + // Controls whether or not this Waiter should stay on the WaiterList upon notification. + virtual bool runs_once() const = 0; + // It is invalid to call notify_inlock() unless holding ReplicationCoordinatorImpl::_mutex. virtual void notify_inlock() = 0; @@ -492,6 +495,9 @@ private: const WriteConcernOptions* _writeConcern, stdx::condition_variable* _condVar); void notify_inlock() override; + bool runs_once() const override { + return false; + } stdx::condition_variable* condVar = nullptr; }; @@ -505,6 +511,9 @@ private: CallbackWaiter(OpTime _opTime, FinishFunc _finishCallback); void notify_inlock() override; + bool runs_once() const override { + return true; + } // The callback that will be called when this waiter is notified. FinishFunc finishCallback = nullptr; @@ -520,10 +529,10 @@ private: void add_inlock(WaiterType waiter); // Returns whether waiter is found and removed. bool remove_inlock(WaiterType waiter); - // Signals and removes all waiters that satisfy the condition. - void signalAndRemoveIf_inlock(stdx::function<bool(WaiterType)> fun); - // Signals and removes all waiters from the list. - void signalAndRemoveAll_inlock(); + // Signals all waiters that satisfy the condition. + void signalIf_inlock(stdx::function<bool(WaiterType)> fun); + // Signals all waiters from the list. + void signalAll_inlock(); private: std::vector<WaiterType> _list; |