Skip to content

Commit

Permalink
http: speed up shutdown
Browse files Browse the repository at this point in the history
Pardon a bit of iteration. This continues/fixes #6719.

`event_base_loopbreak` was not doing what I expected it to.
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.
  • Loading branch information
laanwj committed Nov 11, 2015
1 parent 3ac7060 commit 856be4f
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 12 deletions.
24 changes: 14 additions & 10 deletions src/httpserver.cpp
Expand Up @@ -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;
}

Expand All @@ -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();
}
Expand All @@ -480,6 +475,14 @@ 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
if (!threadHTTP.try_join_for(boost::chrono::milliseconds(2000))) {
event_base_loopbreak(eventBase);
threadHTTP.join();
}
}
if (eventHTTP) {
evhttp_free(eventHTTP);
eventHTTP = 0;
Expand All @@ -488,6 +491,7 @@ void StopHTTPServer()
event_base_free(eventBase);
eventBase = 0;
}
LogPrint("http", "Stopped HTTP server\n");
}

struct event_base* EventBase()
Expand Down
2 changes: 1 addition & 1 deletion src/httpserver.h
Expand Up @@ -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 */
Expand Down
2 changes: 1 addition & 1 deletion src/init.cpp
Expand Up @@ -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;
}
Expand Down

0 comments on commit 856be4f

Please sign in to comment.