summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVesselina Ratcheva <vesselina.ratcheva@10gen.com>2018-06-15 17:03:24 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-04-04 16:31:29 +0000
commit0395f6fae741624906529958d091c8762e72b594 (patch)
treef80fff87a897bca161d07707db0fe4bf8c09890a
parent814b4e99722f87af7e6e7d9b15f68444b00f9f8d (diff)
downloadmongo-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.cpp36
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl.h17
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;