mirror of
https://github.com/znc/znc.git
synced 2026-08-07 09:22:55 +02:00
Fix a busy loop with the connection queue
If connecting to a server failed without needing any time for DNS, the connect timer would busy loop over the networks, because a network re-inserted itself into the queue and the timer would try the network again. Fix this by moving the connection queue to a separate instance of std::list when the timer fires. From then on, we just iterate through that list while networks which want to try again add themselves to the "real" connection queue instead. We only have to make sure that any networks that are left in the old connection queue after the timer is done get prepended to the "real" connection queue. Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
+19
-13
@@ -1827,27 +1827,33 @@ public:
|
||||
|
||||
protected:
|
||||
virtual void RunJob() {
|
||||
list<CIRCNetwork*>& ConnectionQueue = CZNC::Get().GetConnectionQueue();
|
||||
list<CIRCNetwork*> ConnectionQueue;
|
||||
list<CIRCNetwork*>& RealConnectionQueue = CZNC::Get().GetConnectionQueue();
|
||||
|
||||
/* We store the end of the queue, so CIRCNetwork::Connect() can add
|
||||
* itself back to the queue and we wont end up in an infinite loop. */
|
||||
list<CIRCNetwork*>::iterator end = ConnectionQueue.end();
|
||||
list<CIRCNetwork*>::iterator it;
|
||||
// Problem: If a network can't connect right now because e.g. it
|
||||
// is throttled, it will re-insert itself into the connection
|
||||
// queue. However, we must only give each network a single
|
||||
// chance during this timer run.
|
||||
//
|
||||
// Solution: We move the connection queue to our local list at
|
||||
// the beginning and work from that.
|
||||
ConnectionQueue.swap(RealConnectionQueue);
|
||||
|
||||
for (it = ConnectionQueue.begin(); it != end;) {
|
||||
CIRCNetwork *pNetwork = *it;
|
||||
|
||||
/* We must erase the network from the queue before we try to connect
|
||||
* because it may try to add the network to the queue (which would
|
||||
* fail if we were already in the queue) */
|
||||
it = ConnectionQueue.erase(it);
|
||||
while (!ConnectionQueue.empty()) {
|
||||
CIRCNetwork *pNetwork = ConnectionQueue.front();
|
||||
ConnectionQueue.pop_front();
|
||||
|
||||
if (pNetwork->Connect()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ConnectionQueue.empty()) {
|
||||
/* Now re-insert anything that is left in our local list into
|
||||
* the real connection queue.
|
||||
*/
|
||||
RealConnectionQueue.splice(RealConnectionQueue.begin(), ConnectionQueue);
|
||||
|
||||
if (RealConnectionQueue.empty()) {
|
||||
DEBUG("ConnectQueueTimer done");
|
||||
CZNC::Get().DisableConnectQueue();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user