diff --git a/hphp/runtime/base/server/http_server.cpp b/hphp/runtime/base/server/http_server.cpp index 42577ddb2..3757474ad 100644 --- a/hphp/runtime/base/server/http_server.cpp +++ b/hphp/runtime/base/server/http_server.cpp @@ -33,10 +33,12 @@ #include "hphp/runtime/base/program_functions.h" #include "hphp/runtime/debugger/debugger.h" #include "hphp/util/db_conn.h" +#include "hphp/util/ssl_init.h" #include "hphp/runtime/ext/ext_apc.h" + +#include #include #include -#include "hphp/util/ssl_init.h" namespace HPHP { /////////////////////////////////////////////////////////////////////////////// @@ -75,44 +77,43 @@ HttpServer::HttpServer(void *sslCTX /* = NULL */) : kNumProcessors; if (RuntimeOption::ServerPortFd != -1 || RuntimeOption::SSLPortFd != -1) { - LibEventServerWithFd* server = - (new TypedServer - (RuntimeOption::ServerIP, RuntimeOption::ServerPort, - startingThreadCount, - RuntimeOption::RequestTimeoutSeconds)); - maybeEnableThrottle(server); - server->setServerSocketFd(RuntimeOption::ServerPortFd); - server->setSSLSocketFd(RuntimeOption::SSLPortFd); - m_pageServer = ServerPtr(server); - } else if (RuntimeOption::TakeoverFilename.empty()) { - auto const server = new TypedServer - (RuntimeOption::ServerIP, RuntimeOption::ServerPort, + auto const server = boost::make_shared( + RuntimeOption::ServerIP, RuntimeOption::ServerPort, startingThreadCount, RuntimeOption::RequestTimeoutSeconds); - maybeEnableThrottle(server); - m_pageServer = ServerPtr(server); - } else { - LibEventServerWithTakeover* server = - (new TypedServer - (RuntimeOption::ServerIP, RuntimeOption::ServerPort, + maybeEnableThrottle(server.get()); + server->setServerSocketFd(RuntimeOption::ServerPortFd); + server->setSSLSocketFd(RuntimeOption::SSLPortFd); + m_pageServer = server; + } else if (RuntimeOption::TakeoverFilename.empty()) { + auto const server = boost::make_shared( + RuntimeOption::ServerIP, RuntimeOption::ServerPort, startingThreadCount, - RuntimeOption::RequestTimeoutSeconds)); - maybeEnableThrottle(server); + RuntimeOption::RequestTimeoutSeconds); + maybeEnableThrottle(server.get()); + m_pageServer = server; + } else { + auto const server = boost::make_shared( + RuntimeOption::ServerIP, RuntimeOption::ServerPort, + startingThreadCount, + RuntimeOption::RequestTimeoutSeconds); + maybeEnableThrottle(server.get()); server->setTransferFilename(RuntimeOption::TakeoverFilename); server->addTakeoverListener(this); - m_pageServer = ServerPtr(server); + m_pageServer = server; } + m_pageServer->setRequestHandlerFactory(); if (RuntimeOption::EnableSSL && m_sslCTX) { assert(SSLInit::IsInited()); m_pageServer->enableSSL(m_sslCTX, RuntimeOption::SSLPort); } - m_adminServer = ServerPtr - (new TypedServer - (RuntimeOption::ServerIP, RuntimeOption::AdminServerPort, + m_adminServer = boost::make_shared( + RuntimeOption::ServerIP, RuntimeOption::AdminServerPort, RuntimeOption::AdminThreadCount, - RuntimeOption::RequestTimeoutSeconds)); + RuntimeOption::RequestTimeoutSeconds); + m_adminServer->setRequestHandlerFactory(); for (unsigned int i = 0; i < RuntimeOption::SatelliteServerInfos.size(); i++) { diff --git a/hphp/runtime/base/server/libevent_server.cpp b/hphp/runtime/base/server/libevent_server.cpp index ecbedd19f..6c39b4ff1 100644 --- a/hphp/runtime/base/server/libevent_server.cpp +++ b/hphp/runtime/base/server/libevent_server.cpp @@ -16,8 +16,6 @@ #include "hphp/runtime/base/server/libevent_server.h" -#include - #include "hphp/runtime/base/runtime_option.h" #include "hphp/runtime/base/memory/memory_manager.h" #include "hphp/runtime/base/server/server_stats.h" @@ -78,7 +76,7 @@ void LibEventJob::stopTimer() { /////////////////////////////////////////////////////////////////////////////// // LibEventWorker -LibEventWorker::LibEventWorker() : m_handler(nullptr) { +LibEventWorker::LibEventWorker() { } LibEventWorker::~LibEventWorker() { @@ -92,11 +90,6 @@ void LibEventWorker::doJob(LibEventJobPtr job) { server->bumpReqCount(); - if (m_handler == nullptr || server->supportReset()) { - m_handler = server->createRequestHandler(); - assert(m_handler); - } - LibEventTransport transport(server, request, m_id); #ifdef _EVENT_USE_OPENSSL if (evhttp_is_connection_ssl(job->request->evcon)) { @@ -144,12 +137,14 @@ void LibEventWorker::onThreadEnter() { if (RuntimeOption::EnableDebugger) { Eval::Debugger::RegisterThread(); } + m_handler = server->createRequestHandler(); } void LibEventWorker::onThreadExit() { assert(m_opaque); LibEventServer *server = (LibEventServer*)m_opaque; - server->onThreadExit(m_handler); + server->onThreadExit(); + m_handler.reset(); } /////////////////////////////////////////////////////////////////////////////// @@ -401,7 +396,7 @@ void LibEventServer::onThreadEnter() { (&ThreadInfo::s_threadInfo->m_reqInjectionData); } -void LibEventServer::onThreadExit(RequestHandler *handler) { +void LibEventServer::onThreadExit() { m_timeoutThreadData.removeRequestThread (&ThreadInfo::s_threadInfo->m_reqInjectionData); } diff --git a/hphp/runtime/base/server/libevent_server.h b/hphp/runtime/base/server/libevent_server.h index 8c6048294..14f988287 100644 --- a/hphp/runtime/base/server/libevent_server.h +++ b/hphp/runtime/base/server/libevent_server.h @@ -34,7 +34,7 @@ namespace HPHP { DECLARE_BOOST_TYPES(LibEventJob); class LibEventJob { public: - LibEventJob(evhttp_request *req); + explicit LibEventJob(evhttp_request *req); const timespec &getStartTimer() const { return start;} void stopTimer(); @@ -68,7 +68,7 @@ struct LibEventWorker virtual void onThreadExit(); private: - RequestHandler *m_handler; + std::unique_ptr m_handler; }; /** @@ -152,7 +152,7 @@ public: int getLibEventConnectionCount(); void onThreadEnter(); - virtual void onThreadExit(RequestHandler *handler); + void onThreadExit(); /** * Request handler called by evhttp library. @@ -176,9 +176,6 @@ public: */ virtual bool enableSSL(void *sslCTX, int port); - // Whether the server may reset the request handler, e.g., the RPC server. - virtual bool supportReset() { return false; } - protected: virtual int getAcceptSocket(); virtual int getAcceptSocketSSL(); diff --git a/hphp/runtime/base/server/rpc_request_handler.cpp b/hphp/runtime/base/server/rpc_request_handler.cpp index f9eec8eb4..4b0df4cc7 100644 --- a/hphp/runtime/base/server/rpc_request_handler.cpp +++ b/hphp/runtime/base/server/rpc_request_handler.cpp @@ -33,8 +33,18 @@ namespace HPHP { /////////////////////////////////////////////////////////////////////////////// RPCRequestHandler::RPCRequestHandler(bool info /* = true */) - : m_count(0), m_reset(false), - m_returnEncodeType(Json) { + : m_requestsSinceReset(0), + m_reset(false), + m_logResets(info), + m_returnEncodeType(Json) { + initState(); +} + +RPCRequestHandler::~RPCRequestHandler() { + cleanupState(); +} + +void RPCRequestHandler::initState() { hphp_session_init(); bool isServer = RuntimeOption::ServerExecutionMode(); if (isServer) { @@ -45,25 +55,36 @@ RPCRequestHandler::RPCRequestHandler(bool info /* = true */) m_context = g_context.getNoCheck(); m_context->obSetImplicitFlush(true); } - m_created = time(0); + m_lastReset = time(0); Logger::ResetRequestCount(); - if (info) { - Logger::Info("creating new RPC request handler"); + if (m_logResets) { + Logger::Info("initializing RPC request handler"); } + + m_reset = false; + m_requestsSinceReset = 0; } -RPCRequestHandler::~RPCRequestHandler() { +void RPCRequestHandler::cleanupState() { hphp_context_exit(m_context, false); hphp_session_exit(); } bool RPCRequestHandler::needReset() const { - if (m_reset || m_serverInfo->alwaysReset()) return true; - return (time(0) - m_created) > m_serverInfo->getMaxDuration(); + return (m_reset || + m_serverInfo->alwaysReset() || + ((time(0) - m_lastReset) > m_serverInfo->getMaxDuration()) || + (m_requestsSinceReset >= m_serverInfo->getMaxRequest())); } void RPCRequestHandler::handleRequest(Transport *transport) { + if (needReset()) { + cleanupState(); + initState(); + } + ++m_requestsSinceReset; + ExecutionProfiler ep(ThreadInfo::RuntimeFunctions); Logger::OnNewRequest(); @@ -110,8 +131,9 @@ void RPCRequestHandler::handleRequest(Transport *transport) { } // return encoding type + ReturnEncodeType returnEncodeType = m_returnEncodeType; if (transport->getParam("return") == "serialize") { - setReturnEncodeType(Serialize); + returnEncodeType = Serialize; } // resolve virtual host @@ -143,7 +165,7 @@ void RPCRequestHandler::handleRequest(Transport *transport) { // record request for debugging purpose std::string tmpfile = HttpProtocol::RecordRequest(transport); - bool ret = executePHPFunction(transport, sourceRootInfo); + bool ret = executePHPFunction(transport, sourceRootInfo, returnEncodeType); HttpRequestHandler::GetAccessLog().log(transport, vhost); /* * HPHP logs may need to access data in ServerStats, so we have to @@ -159,7 +181,8 @@ static const StaticString s_HPHP_RPC("HPHP_RPC"); bool RPCRequestHandler::executePHPFunction(Transport *transport, - SourceRootInfo &sourceRootInfo) { + SourceRootInfo &sourceRootInfo, + ReturnEncodeType returnEncodeType) { // reset timeout counter ThreadInfo::s_threadInfo->m_reqInjectionData.started = time(0); @@ -271,11 +294,11 @@ bool RPCRequestHandler::executePHPFunction(Transport *transport, String response; switch (output) { case 0: { - assert(m_returnEncodeType == Json || - m_returnEncodeType == Serialize); + assert(returnEncodeType == Json || + returnEncodeType == Serialize); try { - response = (m_returnEncodeType == Json) ? f_json_encode(funcRet) - : f_serialize(funcRet); + response = (returnEncodeType == Json) ? f_json_encode(funcRet) + : f_serialize(funcRet); } catch (...) { serializeFailed = true; } diff --git a/hphp/runtime/base/server/rpc_request_handler.h b/hphp/runtime/base/server/rpc_request_handler.h index bebfe2f57..21a3ac284 100644 --- a/hphp/runtime/base/server/rpc_request_handler.h +++ b/hphp/runtime/base/server/rpc_request_handler.h @@ -35,7 +35,7 @@ public: Serialize = 2, }; - RPCRequestHandler(bool info = true); + explicit RPCRequestHandler(bool info = true); virtual ~RPCRequestHandler(); void setServerInfo(SatelliteServerInfoPtr info) { m_serverInfo = info;} @@ -44,30 +44,29 @@ public: virtual void handleRequest(Transport *transport); /** - * Count how many requests have been processed on this handler. + * Force a reset before the next request. */ - int incRequest() { return ++m_count;} - - /** - * Whether state has been dirtied. - */ - bool needReset() const; void setReset() { m_reset = true; } - time_t getCreationTime() const { return m_created; } + time_t getLastResetTime() const { return m_lastReset; } void setReturnEncodeType(ReturnEncodeType et) { m_returnEncodeType = et; } - ReturnEncodeType getReturnEncodeType() { return m_returnEncodeType; } + ReturnEncodeType getReturnEncodeType() const { return m_returnEncodeType; } private: ExecutionContext *m_context; SatelliteServerInfoPtr m_serverInfo; - int m_count; + int m_requestsSinceReset; bool m_reset; + bool m_logResets; ReturnEncodeType m_returnEncodeType; - time_t m_created; + time_t m_lastReset; + void initState(); + void cleanupState(); + bool needReset() const; bool executePHPFunction(Transport *transport, - SourceRootInfo &sourceRootInfo); + SourceRootInfo &sourceRootInfo, + ReturnEncodeType returnEncodeType); std::string getSourceFilename(const std::string &path, SourceRootInfo &sourceRootInfo); diff --git a/hphp/runtime/base/server/satellite_server.cpp b/hphp/runtime/base/server/satellite_server.cpp index 2461286e9..821bed607 100644 --- a/hphp/runtime/base/server/satellite_server.cpp +++ b/hphp/runtime/base/server/satellite_server.cpp @@ -22,7 +22,11 @@ #include "hphp/runtime/base/runtime_option.h" #include "hphp/runtime/base/preg.h" #include "hphp/util/util.h" +#include "folly/Memory.h" +#include + +using folly::make_unique; using std::set; namespace HPHP { @@ -100,10 +104,10 @@ private: class InternalPageServer : public SatelliteServer { public: explicit InternalPageServer(SatelliteServerInfoPtr info) { - InternalPageServerImplPtr server - (new TypedServer - (RuntimeOption::ServerIP, info->getPort(), info->getThreadCount(), - info->getTimeoutSeconds())); + auto const server = boost::make_shared( + RuntimeOption::ServerIP, info->getPort(), info->getThreadCount(), + info->getTimeoutSeconds()); + server->setRequestHandlerFactory(); server->create(info->getURLs()); m_server = server; } @@ -125,10 +129,10 @@ private: class DanglingPageServer : public SatelliteServer { public: explicit DanglingPageServer(SatelliteServerInfoPtr info) { - m_server = ServerPtr - (new TypedServer - (RuntimeOption::ServerIP, info->getPort(), info->getThreadCount(), - info->getTimeoutSeconds())); + m_server = boost::make_shared( + RuntimeOption::ServerIP, info->getPort(), info->getThreadCount(), + info->getTimeoutSeconds()); + m_server->setRequestHandlerFactory(); } virtual void start() { @@ -145,48 +149,17 @@ private: /////////////////////////////////////////////////////////////////////////////// // RPCServer: LibEventServer + RPCRequestHandler -static IMPLEMENT_THREAD_LOCAL(RPCRequestHandler, s_rpc_request_handler); - -class RPCServerImpl : public LibEventServer { -public: - RPCServerImpl(const std::string &address, SatelliteServerInfoPtr info) - : LibEventServer(address, info->getPort(), info->getThreadCount(), - info->getTimeoutSeconds()), - m_serverInfo(info) { - } - - virtual RequestHandler *createRequestHandler() { - if (s_rpc_request_handler.isNull()) { - s_rpc_request_handler->setServerInfo(m_serverInfo); - return s_rpc_request_handler.get(); - } - if (s_rpc_request_handler->needReset() || - s_rpc_request_handler->incRequest() > m_serverInfo->getMaxRequest()) { - s_rpc_request_handler.destroy(); - s_rpc_request_handler->setServerInfo(m_serverInfo); - s_rpc_request_handler->incRequest(); - } - return s_rpc_request_handler.get(); - } - - virtual void releaseRequestHandler(RequestHandler *handler) { - // do nothing - } - - virtual void onThreadExit(RequestHandler *handler) { - s_rpc_request_handler.destroy(); - } - - virtual bool supportReset() { return true; } - -private: - SatelliteServerInfoPtr m_serverInfo; -}; - class RPCServer : public SatelliteServer { public: explicit RPCServer(SatelliteServerInfoPtr info) { - m_server = ServerPtr(new RPCServerImpl(RuntimeOption::ServerIP, info)); + m_server = boost::make_shared( + RuntimeOption::ServerIP, info->getPort(), info->getThreadCount(), + info->getTimeoutSeconds()); + m_server->setRequestHandlerFactory([info] { + auto handler = make_unique(); + handler->setServerInfo(info); + return handler; + }); } virtual void start() { diff --git a/hphp/runtime/base/server/server.h b/hphp/runtime/base/server/server.h index f5239e8ae..5a1cb63fb 100644 --- a/hphp/runtime/base/server/server.h +++ b/hphp/runtime/base/server/server.h @@ -21,6 +21,8 @@ #include "hphp/util/exception.h" #include "hphp/util/lock.h" +#include + /** * (1) For people who want to quickly come up with an HTTP server handling * their specific requests, we really want to minimize writing an HTTP @@ -35,8 +37,8 @@ * * Then, run a server like this, * - * ServerPtr server(new TypedServer - * ("127.0.0.1", 80, 20)); + * ServerPtr server = make_shared("127.0.0.1", 80, 20); + * server->setRequestHandlerFactory(); * Server::InstallStopSignalHandlers(server); * server->start(); * @@ -83,6 +85,8 @@ public: virtual void handleRequest(Transport *transport) = 0; }; +typedef std::function()> RequestHandlerFactory; + /** * Base class of an HTTP server. Defining minimal interface an HTTP server * needs to implement. @@ -113,6 +117,24 @@ public: */ Server(const std::string &address, int port, int threadCount); + /** + * Set the RequestHandlerFactory that this server will use. + * This must be called before start(). + */ + void setRequestHandlerFactory(RequestHandlerFactory f) { + m_handlerFactory = f; + } + /** + * Helper function to set the RequestHandlerFactory to a + * GenericRequestHandlerFactory for the specified handler type. + */ + template + void setRequestHandlerFactory() { + setRequestHandlerFactory([] { + return std::unique_ptr(new TRequestHandler()); + }); + } + /** * Informational. */ @@ -163,11 +185,11 @@ public: virtual int getLibEventConnectionCount() = 0; /** - * This is for TypedServer to specialize a worker class to use. + * Create a new RequestHandler. */ - virtual RequestHandler *createRequestHandler() = 0; - virtual void releaseRequestHandler(RequestHandler *handler) = 0; - virtual void onThreadExit(RequestHandler *handler) {} + std::unique_ptr createRequestHandler() { + return m_handlerFactory(); + } /** * Overwrite for URL blocking. @@ -185,38 +207,12 @@ protected: int m_port; int m_threadCount; mutable Mutex m_mutex; + RequestHandlerFactory m_handlerFactory; private: RunStatus m_status; }; -/** - * Binding different types together to form a concrete HTTP server that we - * can run. By conforming to their owns interfaces, RequestHandler and - * Server classes should be able to get mixed up and continue to work. - */ -template -class TypedServer : public TServer { -public: - TypedServer(const std::string &address, int port, int threadCount, - int timeoutSeconds) - : TServer(address, port, threadCount, timeoutSeconds) { - } - - virtual RequestHandler *createRequestHandler() { - return new TRequestHandler(); - } - - virtual void releaseRequestHandler(RequestHandler *handler) { - delete handler; - } - - virtual void onThreadExit(RequestHandler *handler) { - TServer::onThreadExit(handler); - delete handler; - } -}; - /** * All exceptions Server throws should derive from this base class. */ @@ -236,14 +232,14 @@ public: class InvalidUrlException : public ServerException { public: - InvalidUrlException(const char *part) + explicit InvalidUrlException(const char *part) : ServerException("Invalid URL: %s", part) { } }; class InvalidMethodException : public ServerException { public: - InvalidMethodException(const char *msg) + explicit InvalidMethodException(const char *msg) : ServerException("Invalid method: %s", msg) { } }; diff --git a/hphp/runtime/base/server/xbox_server.cpp b/hphp/runtime/base/server/xbox_server.cpp index 32ba3c90a..4ac632166 100644 --- a/hphp/runtime/base/server/xbox_server.cpp +++ b/hphp/runtime/base/server/xbox_server.cpp @@ -183,7 +183,6 @@ private: if (RuntimeOption::XboxServerLogInfo) XboxRequestHandler::Info = true; s_xbox_request_handler->setServerInfo(*s_xbox_server_info); s_xbox_request_handler->setReturnEncodeType(RPCRequestHandler::Serialize); - s_xbox_request_handler->incRequest(); return s_xbox_request_handler.get(); } diff --git a/hphp/runtime/ext/ext_server.cpp b/hphp/runtime/ext/ext_server.cpp index e421665b0..9a36610bf 100644 --- a/hphp/runtime/ext/ext_server.cpp +++ b/hphp/runtime/ext/ext_server.cpp @@ -241,7 +241,7 @@ void f_xbox_schedule_thread_reset() { int64_t f_xbox_get_thread_time() { RPCRequestHandler *handler = XboxServer::GetRequestHandler(); if (handler) { - return time(NULL) - handler->getCreationTime(); + return time(nullptr) - handler->getLastResetTime(); } throw Exception("Not an xbox worker!"); } diff --git a/hphp/test/test_ext_curl.cpp b/hphp/test/test_ext_curl.cpp index b78c41924..792840f12 100644 --- a/hphp/test/test_ext_curl.cpp +++ b/hphp/test/test_ext_curl.cpp @@ -20,6 +20,8 @@ #include "hphp/runtime/ext/ext_zlib.h" #include "hphp/runtime/base/server/libevent_server.h" +#include + #define PORT_MIN 7100 #define PORT_MAX 7120 @@ -53,8 +55,9 @@ static std::string get_request_uri() { static ServerPtr runServer() { for (s_server_port = PORT_MIN; s_server_port <= PORT_MAX; s_server_port++) { try { - ServerPtr server(new TypedServer - ("127.0.0.1", s_server_port, 4, -1)); + ServerPtr server = boost::make_shared( + "127.0.0.1", s_server_port, 4, -1); + server->setRequestHandlerFactory(); server->start(); return server; diff --git a/hphp/test/test_server.cpp b/hphp/test/test_server.cpp index 0ef0b9a60..883d11314 100644 --- a/hphp/test/test_server.cpp +++ b/hphp/test/test_server.cpp @@ -29,6 +29,8 @@ #include "hphp/runtime/base/util/http_client.h" #include "hphp/runtime/base/runtime_option.h" +#include + using namespace HPHP; #define PORT_MIN 7300 @@ -186,8 +188,9 @@ public: static int find_server_port(int port_min, int port_max) { for (int port = port_min; ; port++) { try { - ServerPtr server(new TypedServer - ("127.0.0.1", port, 50, -1)); + ServerPtr server = boost::make_shared( + "127.0.0.1", port, 50, -1); + server->setRequestHandlerFactory(); server->start(); server->stop(); server->waitForEnd(); @@ -563,8 +566,9 @@ bool TestServer::TestHttpClient() { ServerPtr server; for (s_server_port = PORT_MIN; s_server_port <= PORT_MAX; s_server_port++) { try { - server = ServerPtr(new TypedServer - ("127.0.0.1", s_server_port, 50, -1)); + server = boost::make_shared( + "127.0.0.1", s_server_port, 50, -1); + server->setRequestHandlerFactory(); server->start(); break; } catch (const FailedToListenException& e) {