mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-10 20:03:34 -03:00
http: speed up shutdown
This continues/fixes #6719. `event_base_loopbreak` was not doing what I expected it to, at least in libevent 2.0.21. What I expected was that it sets a timeout, given that no other pending events it would exit in N seconds. However, what it does was delay the event loop exit with 10 seconds, even if nothing is pending. Solve it in a different way: give the event loop thread time to exit out of itself, and if it doesn't, send loopbreak. This speeds up the RPC tests a lot, each exit incurred a 10 second overhead, with this change there should be no shutdown overhead in the common case and up to two seconds if the event loop is blocking. As a bonus this breaks dependency on boost::thread_group, as the HTTP server minds its own offspring.
This commit is contained in:
parent
3ac7060934
commit
a264c32e33
3 changed files with 22 additions and 12 deletions
|
@ -438,15 +438,17 @@ bool InitHTTPServer()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool StartHTTPServer(boost::thread_group& threadGroup)
|
||||
boost::thread threadHTTP;
|
||||
|
||||
bool StartHTTPServer()
|
||||
{
|
||||
LogPrint("http", "Starting HTTP server\n");
|
||||
int rpcThreads = std::max((long)GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
|
||||
LogPrintf("HTTP: starting %d worker threads\n", rpcThreads);
|
||||
threadGroup.create_thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP));
|
||||
threadHTTP = boost::thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP));
|
||||
|
||||
for (int i = 0; i < rpcThreads; i++)
|
||||
threadGroup.create_thread(boost::bind(&HTTPWorkQueueRun, workQueue));
|
||||
boost::thread(boost::bind(&HTTPWorkQueueRun, workQueue));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -461,13 +463,6 @@ void InterruptHTTPServer()
|
|||
// Reject requests on current connections
|
||||
evhttp_set_gencb(eventHTTP, http_reject_request_cb, NULL);
|
||||
}
|
||||
if (eventBase) {
|
||||
// Force-exit event loop after predefined time
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 10;
|
||||
tv.tv_usec = 0;
|
||||
event_base_loopexit(eventBase, &tv);
|
||||
}
|
||||
if (workQueue)
|
||||
workQueue->Interrupt();
|
||||
}
|
||||
|
@ -480,6 +475,20 @@ void StopHTTPServer()
|
|||
workQueue->WaitExit();
|
||||
delete workQueue;
|
||||
}
|
||||
if (eventBase) {
|
||||
LogPrint("http", "Waiting for HTTP event thread to exit\n");
|
||||
// Give event loop a few seconds to exit (to send back last RPC responses), then break it
|
||||
// Before this was solved with event_base_loopexit, but that didn't work as expected in
|
||||
// at least libevent 2.0.21 and always introduced a delay. In libevent
|
||||
// master that appears to be solved, so in the future that solution
|
||||
// could be used again (if desirable).
|
||||
// (see discussion in https://github.com/bitcoin/bitcoin/pull/6990)
|
||||
if (!threadHTTP.try_join_for(boost::chrono::milliseconds(2000))) {
|
||||
LogPrintf("HTTP event loop did not exit within allotted time, sending loopbreak\n");
|
||||
event_base_loopbreak(eventBase);
|
||||
threadHTTP.join();
|
||||
}
|
||||
}
|
||||
if (eventHTTP) {
|
||||
evhttp_free(eventHTTP);
|
||||
eventHTTP = 0;
|
||||
|
@ -488,6 +497,7 @@ void StopHTTPServer()
|
|||
event_base_free(eventBase);
|
||||
eventBase = 0;
|
||||
}
|
||||
LogPrint("http", "Stopped HTTP server\n");
|
||||
}
|
||||
|
||||
struct event_base* EventBase()
|
||||
|
|
|
@ -28,7 +28,7 @@ bool InitHTTPServer();
|
|||
* This is separate from InitHTTPServer to give users race-condition-free time
|
||||
* to register their handlers between InitHTTPServer and StartHTTPServer.
|
||||
*/
|
||||
bool StartHTTPServer(boost::thread_group& threadGroup);
|
||||
bool StartHTTPServer();
|
||||
/** Interrupt HTTP server threads */
|
||||
void InterruptHTTPServer();
|
||||
/** Stop HTTP server */
|
||||
|
|
|
@ -661,7 +661,7 @@ bool AppInitServers(boost::thread_group& threadGroup)
|
|||
return false;
|
||||
if (GetBoolArg("-rest", false) && !StartREST())
|
||||
return false;
|
||||
if (!StartHTTPServer(threadGroup))
|
||||
if (!StartHTTPServer())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue