/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef THRIFT_ASYNC_TEVENTSERVER_H_ #define THRIFT_ASYNC_TEVENTSERVER_H_ 1 #include "thrift/lib/cpp/Thrift.h" #include "thrift/lib/cpp/server/TServer.h" #include "thrift/lib/cpp/async/TAsyncProcessor.h" #include "thrift/lib/cpp/transport/TTransportUtils.h" #include "thrift/lib/cpp/transport/TSSLSocket.h" #include "thrift/lib/cpp/protocol/THeaderProtocol.h" #include "thrift/lib/cpp/concurrency/Mutex.h" #include "thrift/lib/cpp/concurrency/ThreadLocal.h" #include "thrift/lib/cpp/async/TEventBase.h" #include "thrift/lib/cpp/async/TEventBaseManager.h" #include #include #include #include namespace apache { namespace thrift { namespace concurrency { class ThreadFactory; class ThreadManager; } namespace async { using apache::thrift::protocol::TDualProtocolFactory; // Forward declaration of classes class TAsyncServerSocket; class TEventConnection; class TEventWorker; /** This is a non-blocking event-based server for high performance that operates an I/O thread for each cpu core and uses callbacks for notification of processing or I/O operations. It does not use the TServerTransport framework, but rather has socket operations hardcoded for use with libevent and implements framing compatible with TFramedTransport. A single "listener" thread accepts connections and sends them to the server threads via a single socketpair(); the server threads are each responsible for allocating and pooling actual connection objects, avoiding the need for the locks required by a common pool. The original Thrift server was by Mark Slee . A non-blocking variant was produced which allowed for a large number of processing threads but restricted network I/O to a single thread -- suboptimal on a multi-core CPU. David Reiss and Mark Rabkin refactored this server into a callback-driven event-based configuration. Ed Hall elaborated on this to support network I/O on multiple threads (ideally one per CPU core). @author Mark Slee @author David Reiss @author Mark Rabkin @author Ed Hall */ class TEventServer : public apache::thrift::server::TServer { public: enum TransportType { FRAMED = 0, HEADER = 1, /*********** Deprecation Warning ******************* * * * The unframed transports are deprecated ! * * They should be used for legancy services only * * Also note: they only works with TBinaryProtocol * ***************************************************/ UNFRAMED_BINARY = 2 }; protected: //! Default max size of per-worker connection pool. static const uint32_t T_ASYNC_MAX_CONNECTION_POOL_SIZE = 64; /// Starting size of a TEventConnection's read buffer static const int T_ASYNC_READ_BUFFER_DEFAULT_SIZE = 1024; /// Starting size of a TEventConnection's write buffer static const int T_ASYNC_WRITE_BUFFER_DEFAULT_SIZE = 1024; /// Maximum size of read buffer allocated to idle connection (0 = unlimited) static const int T_ASYNC_IDLE_READ_BUFFER_LIMIT = 0; /// Maximum size of write buffer allocated to idle connection (0 = unlimited) static const int T_ASYNC_IDLE_WRITE_BUFFER_LIMIT = 0; /// # of calls before resizing oversized buffers (0 = check only on close) static const int T_ASYNC_RESIZE_BUFFER_EVERY_N = 0; //! Default number of worker threads (should be # of processor cores). static const int T_ASYNC_DEFAULT_WORKER_THREADS = 4; //! Maximum size of a frame we'll accept (default = 64MB) static const int T_ASYNC_DEFAULT_MAX_FRAME_SIZE = 67108864; static const uint32_t T_MAX_NUM_MESSAGES_IN_PIPE = 0xffffffff; /// Listen backlog static const int T_LISTEN_BACKLOG = 1024; //! Transport type static const TransportType T_ASYNC_DEFAULT_TRANSPORT_TYPE = FRAMED; private: struct WorkerInfo { boost::shared_ptr worker; boost::shared_ptr thread; }; //! Max size of per-worker connection pool (may be set). uint32_t maxConnectionPoolSize_; //! SSL context boost::shared_ptr sslContext_; //! Factory that creates connection processor objects. boost::shared_ptr asyncProcessorFactory_; //! Port to listen on uint16_t port_; //! Listen socket TAsyncServerSocket* socket_; //! The TEventBase currently driving serve(). NULL when not serving. TEventBase* serveEventBase_; //! Number of worker threads (may be set) (should be # of CPU cores) int nWorkers_; //! Milliseconds we'll wait for data to appear (0 = infinity) int timeout_; //! Manager of per-thread TEventBase objects. TEventBaseManager eventBaseManager_; //! Last worker chosen -- used to select workers in round-robin sequence. uint32_t workerChoice_; //! List of workers. typedef std::vector WorkerVector; WorkerVector workers_; //! Maximum number of bytes accepted in a frame. uint32_t maxFrameSize_; /// We initialize (and reinitialize) TEventConnection's read buffer to /// this size. size_t readBufferDefaultSize_; /// We initialize (and reinitialize) TEventConnection's write buffer to /// this size. size_t writeBufferDefaultSize_; /** * Max read buffer size for an idle TConnection. When we place an idle * TConnection into TEventWorker::connectionStack_ or on every * resizeBufferEveryN_ calls, we insure that its read buffer is <= to * this size; otherwise we replace it with a new one to insure that idle * connections don't hog memory. 0 disables this check. */ size_t idleReadBufferLimit_; /** * Max write buffer size for an idle connection. When we place an idle * TConnection into TEventWorker::connectionStack_ or on every * resizeBufferEveryN_ calls, we insure that its write buffer is <= to * this size; otherwise we replace it with a new one to insure that idle * connections don't hog memory. 0 disables this check. */ size_t idleWriteBufferLimit_; /** * Every N calls we check the buffer size limits on a connected * TEventConnection. 0 disables (i.e. the checks are only done when a * connection closes). */ int32_t resizeBufferEveryN_; /** * Call timeout in ms. When nonzero, limits the amount of time we allow * between the start of a call and the actual invokation of its processor. * The connection closes if it is exceeded. */ int32_t callTimeout_; /** * The thread manager used when we're in queuing mode. */ boost::shared_ptr threadManager_; /** * Thread local storage to track the current connection being processed */ concurrency::ThreadLocal > currentConnection_; /** * The time in milliseconds before an unperformed task expires -- * queuing mode only. (0 == infinite) */ uint64_t taskExpireTime_; /** * Set true if we are in queuing mode, false if not. */ bool queuingMode_; /** * The speed for adjusting connection accept rate. * 0 for disabling auto adjusting connection accept rate. */ double acceptRateAdjustSpeed_; /** * The maximum number of unprocessed messages which a NotificationPipe * can hold. */ uint32_t maxNumMsgsInPipe_; /** * The max number of active connections for each worker */ int32_t maxNumActiveConnectionsPerWorker_; /** * The transport type to use */ TransportType transportType_; void addWorker(concurrency::ThreadFactory* threadFactory); /** * No-op signal handler (for SIGPIPE) */ static void sigNoOp(int signo) { (void)signo; } /** * Set the current connection */ void setCurrentConnection(TEventConnection* conn) { assert(currentConnection_.get() == NULL); currentConnection_.set(conn); } /** * Clear the current connection */ void clearCurrentConnection() { currentConnection_.clear(); } // Allow TEventConnection and TEventTask to access setCurrentConnection() // and clearCurrentConnection(). Only these two private // methods are meant to be used by TEventConnection and TEventTask. friend class TEventConnection; friend class TEventTask; public: /** Construct an async Thrift server. You need to compile your thrift configuration with thrift_cpp_options = "cob_style" to get the required TAsyncProcessor class; this differs from the usual TProcessor object by adding a completion callback. TBinaryProtocol is assumed for both input and output with this constructor. @param processor the TAsyncProcessor object for this service @param port the TCP port number for this service @param nWorkers the number of worker threads -- should be the same as the number of CPU cores, though if a process has more than one TEventServer the cores can be split between them. */ template TEventServer(boost::shared_ptr processor, int port, int nWorkers = T_ASYNC_DEFAULT_WORKER_THREADS, THRIFT_OVERLOAD_IF(AsyncProcessor, TAsyncProcessor)) : apache::thrift::server::TServer(boost::shared_ptr()), maxConnectionPoolSize_(T_ASYNC_MAX_CONNECTION_POOL_SIZE), asyncProcessorFactory_(new TAsyncSingletonProcessorFactory(processor)), port_(port), socket_(NULL), serveEventBase_(NULL), nWorkers_(nWorkers), timeout_(0), eventBaseManager_(), workerChoice_(0), maxFrameSize_(T_ASYNC_DEFAULT_MAX_FRAME_SIZE), readBufferDefaultSize_(T_ASYNC_READ_BUFFER_DEFAULT_SIZE), writeBufferDefaultSize_(T_ASYNC_WRITE_BUFFER_DEFAULT_SIZE), idleReadBufferLimit_(T_ASYNC_IDLE_READ_BUFFER_LIMIT), idleWriteBufferLimit_(T_ASYNC_IDLE_WRITE_BUFFER_LIMIT), resizeBufferEveryN_(T_ASYNC_RESIZE_BUFFER_EVERY_N), callTimeout_(0), taskExpireTime_(0), queuingMode_(false), acceptRateAdjustSpeed_(0), maxNumMsgsInPipe_(T_MAX_NUM_MESSAGES_IN_PIPE), maxNumActiveConnectionsPerWorker_(0), transportType_(T_ASYNC_DEFAULT_TRANSPORT_TYPE) { processor->setAsyncServer(this); } /** Construct an async Thrift server for a particular TProtocol. See above; adds a "protocolFactory" parameter to replace the default TBinaryProtocol. @param processor the TAsyncProcessor object for this service @param protocolFactory the TProtocolFactory to use for input & output @param port the TCP port number for this service @param nWorkers the number of worker threads */ template TEventServer(boost::shared_ptr processor, boost::shared_ptr protocolFactory, int port, int nWorkers = T_ASYNC_DEFAULT_WORKER_THREADS, THRIFT_OVERLOAD_IF(AsyncProcessor, TAsyncProcessor)) : apache::thrift::server::TServer(boost::shared_ptr()), maxConnectionPoolSize_(T_ASYNC_MAX_CONNECTION_POOL_SIZE), asyncProcessorFactory_(new TAsyncSingletonProcessorFactory(processor)), port_(port), socket_(NULL), serveEventBase_(NULL), nWorkers_(nWorkers), timeout_(0), eventBaseManager_(), workerChoice_(0), maxFrameSize_(T_ASYNC_DEFAULT_MAX_FRAME_SIZE), readBufferDefaultSize_(T_ASYNC_READ_BUFFER_DEFAULT_SIZE), writeBufferDefaultSize_(T_ASYNC_WRITE_BUFFER_DEFAULT_SIZE), idleReadBufferLimit_(T_ASYNC_IDLE_READ_BUFFER_LIMIT), idleWriteBufferLimit_(T_ASYNC_IDLE_WRITE_BUFFER_LIMIT), resizeBufferEveryN_(T_ASYNC_RESIZE_BUFFER_EVERY_N), callTimeout_(0), taskExpireTime_(0), queuingMode_(false), acceptRateAdjustSpeed_(0), maxNumMsgsInPipe_(T_MAX_NUM_MESSAGES_IN_PIPE), maxNumActiveConnectionsPerWorker_(0), transportType_(T_ASYNC_DEFAULT_TRANSPORT_TYPE) { processor->setAsyncServer(this); setProtocolFactory(protocolFactory); } /** Construct an async Thrift server with different input & output TProtocol. See above; adds "inputProtocolFactory" and "outputProtocolFactory" parameters. @param processor the TAsyncProcessor object for this service @param inputProtocolFactory the TProtocolFactory to use for input @param outputProtocolFactory the TProtocolFactory to use for output @param port the TCP port number for this service @param nWorkers the number of worker threads @deprecated use TDuplex* ctor below */ template TEventServer(boost::shared_ptr processor, boost::shared_ptr inputProtocolFactory, boost::shared_ptr outputProtocolFactory, int port, int nWorkers = T_ASYNC_DEFAULT_WORKER_THREADS, THRIFT_OVERLOAD_IF(AsyncProcessor, TAsyncProcessor)) : apache::thrift::server::TServer(boost::shared_ptr()), maxConnectionPoolSize_(T_ASYNC_MAX_CONNECTION_POOL_SIZE), asyncProcessorFactory_(new TAsyncSingletonProcessorFactory(processor)), port_(port), socket_(NULL), serveEventBase_(NULL), nWorkers_(nWorkers), timeout_(0), eventBaseManager_(), workerChoice_(0), maxFrameSize_(T_ASYNC_DEFAULT_MAX_FRAME_SIZE), readBufferDefaultSize_(T_ASYNC_READ_BUFFER_DEFAULT_SIZE), writeBufferDefaultSize_(T_ASYNC_WRITE_BUFFER_DEFAULT_SIZE), idleReadBufferLimit_(T_ASYNC_IDLE_READ_BUFFER_LIMIT), idleWriteBufferLimit_(T_ASYNC_IDLE_WRITE_BUFFER_LIMIT), resizeBufferEveryN_(T_ASYNC_RESIZE_BUFFER_EVERY_N), callTimeout_(0), taskExpireTime_(0), queuingMode_(false), acceptRateAdjustSpeed_(0), maxNumMsgsInPipe_(T_MAX_NUM_MESSAGES_IN_PIPE), maxNumActiveConnectionsPerWorker_(0), transportType_(T_ASYNC_DEFAULT_TRANSPORT_TYPE) { processor->setAsyncServer(this); setDuplexProtocolFactory( boost::shared_ptr( new TDualProtocolFactory(inputProtocolFactory, outputProtocolFactory))); } /** Construct an async Thrift server with custom input & output TProtocol. See above; Replaces protocolFactory with duplexProtocolFactory parameters. @param processor the TAsyncProcessor object for this service @param duplexProtocolFactory the TProtocolFactory to use for input/output @param port the TCP port number for this service @param nWorkers the number of worker threads */ template TEventServer(boost::shared_ptr processor, boost::shared_ptr duplexProtocolFactory, int port, int nWorkers = T_ASYNC_DEFAULT_WORKER_THREADS, THRIFT_OVERLOAD_IF(AsyncProcessor, TAsyncProcessor)): apache::thrift::server::TServer(boost::shared_ptr()), maxConnectionPoolSize_(T_ASYNC_MAX_CONNECTION_POOL_SIZE), asyncProcessorFactory_(new TAsyncSingletonProcessorFactory(processor)), port_(port), socket_(NULL), serveEventBase_(NULL), nWorkers_(nWorkers), timeout_(0), eventBaseManager_(), workerChoice_(0), maxFrameSize_(T_ASYNC_DEFAULT_MAX_FRAME_SIZE), readBufferDefaultSize_(T_ASYNC_READ_BUFFER_DEFAULT_SIZE), writeBufferDefaultSize_(T_ASYNC_WRITE_BUFFER_DEFAULT_SIZE), idleReadBufferLimit_(T_ASYNC_IDLE_READ_BUFFER_LIMIT), idleWriteBufferLimit_(T_ASYNC_IDLE_WRITE_BUFFER_LIMIT), resizeBufferEveryN_(T_ASYNC_RESIZE_BUFFER_EVERY_N), callTimeout_(0), taskExpireTime_(0), queuingMode_(false), acceptRateAdjustSpeed_(0), maxNumMsgsInPipe_(T_MAX_NUM_MESSAGES_IN_PIPE), maxNumActiveConnectionsPerWorker_(0), transportType_(T_ASYNC_DEFAULT_TRANSPORT_TYPE) { processor->setAsyncServer(this); setDuplexProtocolFactory(duplexProtocolFactory); } /** Construct a task-queuing Thrift server for a particular TProtocol. Largely compatible with TNonblockingServer. @param processor the TProcessor object for this service @param protocolFactory the TProtocolFactory to use for input & output @param port the TCP port number for this service @param threadManager the thread manager we use for task queuing @param nWorkers the number of worker threads */ template TEventServer( boost::shared_ptr& processor, boost::shared_ptr& protocolFactory, int port, boost::shared_ptr const& threadManager = boost::shared_ptr(), int nWorkers = T_ASYNC_DEFAULT_WORKER_THREADS, THRIFT_OVERLOAD_IF(Processor, TProcessor)) : apache::thrift::server::TServer(processor), maxConnectionPoolSize_(T_ASYNC_MAX_CONNECTION_POOL_SIZE), port_(port), socket_(NULL), serveEventBase_(NULL), nWorkers_(nWorkers), timeout_(0), eventBaseManager_(), workerChoice_(0), maxFrameSize_(T_ASYNC_DEFAULT_MAX_FRAME_SIZE), readBufferDefaultSize_(T_ASYNC_READ_BUFFER_DEFAULT_SIZE), writeBufferDefaultSize_(T_ASYNC_WRITE_BUFFER_DEFAULT_SIZE), idleReadBufferLimit_(T_ASYNC_IDLE_READ_BUFFER_LIMIT), idleWriteBufferLimit_(T_ASYNC_IDLE_WRITE_BUFFER_LIMIT), resizeBufferEveryN_(T_ASYNC_RESIZE_BUFFER_EVERY_N), callTimeout_(0), taskExpireTime_(0), queuingMode_(true), acceptRateAdjustSpeed_(0), maxNumMsgsInPipe_(T_MAX_NUM_MESSAGES_IN_PIPE), maxNumActiveConnectionsPerWorker_(0), transportType_(T_ASYNC_DEFAULT_TRANSPORT_TYPE) { setProtocolFactory(protocolFactory); setThreadManager(threadManager); } /** Construct a task-queuing Thrift server for a particular TProtocol. Largely compatible with TNonblockingServer. @param processor the TProcessor object for this service @param protocolFactory the TProtocolFactory to use for input & output @param port the TCP port number for this service @param threadManager the thread manager we use for task queuing @param nWorkers the number of worker threads */ template TEventServer( boost::shared_ptr& processor, boost::shared_ptr& duplexProtocolFactory, int port, boost::shared_ptr const& threadManager = boost::shared_ptr(), int nWorkers = T_ASYNC_DEFAULT_WORKER_THREADS, THRIFT_OVERLOAD_IF(Processor, TProcessor)) : apache::thrift::server::TServer(processor), maxConnectionPoolSize_(T_ASYNC_MAX_CONNECTION_POOL_SIZE), port_(port), socket_(NULL), serveEventBase_(NULL), nWorkers_(nWorkers), timeout_(0), eventBaseManager_(), workerChoice_(0), maxFrameSize_(T_ASYNC_DEFAULT_MAX_FRAME_SIZE), readBufferDefaultSize_(T_ASYNC_READ_BUFFER_DEFAULT_SIZE), writeBufferDefaultSize_(T_ASYNC_WRITE_BUFFER_DEFAULT_SIZE), idleReadBufferLimit_(T_ASYNC_IDLE_READ_BUFFER_LIMIT), idleWriteBufferLimit_(T_ASYNC_IDLE_WRITE_BUFFER_LIMIT), resizeBufferEveryN_(T_ASYNC_RESIZE_BUFFER_EVERY_N), callTimeout_(0), taskExpireTime_(0), queuingMode_(true), acceptRateAdjustSpeed_(0), maxNumMsgsInPipe_(T_MAX_NUM_MESSAGES_IN_PIPE), maxNumActiveConnectionsPerWorker_(0), transportType_(T_ASYNC_DEFAULT_TRANSPORT_TYPE) { setDuplexProtocolFactory(duplexProtocolFactory); setThreadManager(threadManager); } virtual ~TEventServer() { } /** * */ void setSSLContext(boost::shared_ptr context) { sslContext_ = context; } boost::shared_ptr getSSLContext() const { return sslContext_; } /** * Use the provided socket rather than binding to port_. The caller must * call ::bind on this socket, but should not call ::listen. * * NOTE: TEventServe takes ownership of this 'socket' so if binding fails * we destroy this socket, while cleaning itself up. So, 'accept' better * work the first time :) */ void useExistingSocket(int socket); /** * Return the file descriptor associated with the listening socket */ int getListenSocket() const; /** * Get the TAsyncProcessorFactory object used by this server. * * @return a pointer to the processorFactory. */ boost::shared_ptr getAsyncProcessorFactory() const { return asyncProcessorFactory_; } /** * Set the TAsyncProcessor object used by this server. */ void setAsyncProcessorFactory(boost::shared_ptr pf) { asyncProcessorFactory_ = pf; } /** * Get the TEventBase used by the current thread. * This will be different between each worker and the listener. Use this * for any event monitoring within a processor and be careful NOT to * cache between connections (since they may be executed by different * workers). * * @return a pointer to the TEventBase. */ TEventBase* getEventBase() const { return eventBaseManager_.getEventBase(); } /** * Get the TEventServer's main event base. * * @return a pointer to the TEventBase. */ TEventBase* getServeEventBase() const { return serveEventBase_; } /** * Get the TEventBaseManager used by this server. * This can be used to find or create the TEventBase associated with * any given thread, including any new threads created by clients. * * @return a pointer to the TEventBaseManager. */ TEventBaseManager* getEventBaseManager() { return &eventBaseManager_; } const TEventBaseManager* getEventBaseManager() const { return &eventBaseManager_; } /** * Set the port to serve */ void setPort(uint16_t port) { port_ = port ; } /** *Set the maximum number of inactive connection objects pooled. * Since these objects consume memory, we need to limit how many we keep. * You can disable pooling altogether by setting this to zero. Note that * the actual maximum is nWorkers*size since each worker thread maintains * its own pool (to avoid the need for locks). * * @param size the maximum number of inactive connections to pool. */ void setMaxConnectionPoolSize(uint32_t size) { maxConnectionPoolSize_ = size; } /** Get the maximum number of inactive connection objects pooled. @return the maximum pool size. */ uint32_t getMaxConnectionPoolSize() const { return maxConnectionPoolSize_; } /** * Get the maximum number of unprocessed messages which a NotificationPipe * can hold. */ uint32_t getMaxNumMessagesInPipe() const { return maxNumMsgsInPipe_; } /** * Set the maximum number of unprocessed messages in NotificationPipe. * No new message will be sent to that NotificationPipe if there are more * than such number of unprocessed messages in that pipe. */ void setMaxNumMessagesInPipe(uint32_t num) { maxNumMsgsInPipe_ = num; } /** * Get the maxmum number of active connections each TAsyncWorker can have */ int32_t getMaxNumActiveConnectionsPerWorker() const { return maxNumActiveConnectionsPerWorker_; } /** * Set the maxmum number of active connections each TAsyncWorker can have. * Zero means unlimited */ void setMaxNumActiveConnectionsPerWorker(int32_t num) { maxNumActiveConnectionsPerWorker_ = num; } /** * Get the speed of adjusting connection accept rate. */ double getAcceptRateAdjustSpeed() const { return acceptRateAdjustSpeed_; } /** * Set the speed of adjusting connection accept rate. */ void setAcceptRateAdjustSpeed(double speed) { acceptRateAdjustSpeed_ = speed; } /** * Get the number of connections dropped by the TAsyncServerSocket */ void getNumDroppedConnections() const; /** Reset the maximum number of inactive connection objects to the default. */ void resetMaxConnectionPoolSize() { setMaxConnectionPoolSize(T_ASYNC_MAX_CONNECTION_POOL_SIZE); } /** Get maximum number of milliseconds we'll wait for data (0 = infinity). * * @return number of milliseconds, or 0 if no timeout set. */ int getRecvTimeout() const { return timeout_; } /** Set maximum number of milliseconds we'll wait for data (0 = infinity). * Note: existing connections are unaffected by this call. * * @param timeout number of milliseconds, or 0 to disable timeouts. */ void setRecvTimeout(int timeout) { timeout_ = timeout; } /** Set the maximum frame size server will accept. * * @param size the maximum size in bytes of a frame we'll accept. */ void setMaxFrameSize(uint32_t size) { maxFrameSize_ = size; } /** Get the maximum frame size server will accept. * * @return the maximum pool size. */ uint32_t getMaxFrameSize() const { return maxFrameSize_; } /** * Get the starting size of a TEventConnection object's read buffer. * * @return # bytes we init a TEventConnection object's read buffer to. */ size_t getReadBufferDefaultSize() const { return readBufferDefaultSize_; } /** * Set the starting size of a TEventConnection object's read buffer. * * @param size # bytes we init a TEventConnection object's read buffer to. */ void setReadBufferDefaultSize(size_t size) { readBufferDefaultSize_ = size; } /** * Get the starting size of a TEventConnection object's write buffer. * * @return # bytes we init a TEventConnection object's write buffer to. */ size_t getWriteBufferDefaultSize() const { return writeBufferDefaultSize_; } /** * Set the starting size of a TEventConnection object's write buffer. * * @param size # bytes we init a TEventConnection object's write buffer to. */ void setWriteBufferDefaultSize(size_t size) { writeBufferDefaultSize_ = size; } /** * Get the maximum size of read buffer allocated to idle TConnection objects. * * @return # bytes beyond which we will shrink buffers when idle. */ size_t getIdleReadBufferLimit() const { return idleReadBufferLimit_; } /** * Set the maximum size read buffer allocated to idle TEventConnection * objects. If a TEventConnection object is found (either on connection * close or between calls when resizeBufferEveryN_ is set) with more than * this much memory * allocated to its read buffer, we shrink it to this value. * * @param limit of bytes beyond which we will shrink buffers when checked. */ void setIdleReadBufferLimit(size_t limit) { idleReadBufferLimit_ = limit; } /** * Get the maximum size of write buffer allocated to idle TEventConnection * objects. * * @return # bytes beyond which we will reallocate buffers when checked. */ size_t getIdleWriteBufferLimit() const { return idleWriteBufferLimit_; } /** * Set the maximum size write buffer allocated to idle TEventConnection * objects. If a TEventConnection object is found (either on connection * close or between calls when resizeBufferEveryN_ is set) with more than * this much memory allocated to its write buffer, we destroy and construct * that buffer. * * @param limit of bytes beyond which we will shrink buffers when idle. */ void setIdleWriteBufferLimit(size_t limit) { idleWriteBufferLimit_ = limit; } /** * Get # of calls made between buffer size checks. 0 means disabled. * * @return # of calls between buffer size checks. */ int32_t getResizeBufferEveryN() const { return resizeBufferEveryN_; } /** * Check buffer sizes every "count" calls. This allows buffer limits * to be enforced for persistant connections with a controllable degree * of overhead. 0 disables checks except at connection close. * * @param count the number of calls between checks, or 0 to disable */ void setResizeBufferEveryN(int32_t count) { resizeBufferEveryN_ = count; } /** * Set a call timeout in milliseconds. * * When a worker's TEventBase starts taking longer than this amount of time * to process a single loop, start dropping connections to reduce loadj * * TODO: This should be renamed something other than "call timeout" * * @param milliseconds the call timeout (0 inhibits) */ void setCallTimeout(int32_t milliseconds) { callTimeout_ = milliseconds; } /** * Get the call timeout in milliseconds. 0 (default) disables. * * @return the call timeout in milliseconds */ int32_t getCallTimeout() const { return callTimeout_; } /** * Set Thread Manager (for queuing mode). * * @param threadManager a shared pointer to the thread manager */ void setThreadManager(boost::shared_ptr threadManager) { threadManager_ = threadManager; } /** * Get Thread Manager (for queuing mode). * * @return a shared pointer to the thread manager */ boost::shared_ptr getThreadManager() { return threadManager_; } /** * Get the task expire time (for queuing mode). * * @return task expire time */ int64_t getTaskExpireTime() const { return taskExpireTime_; } /** * Return whether we are in queuing mode or not. * * @return true if we are in queuing mode, false if not. */ bool queuingMode() const { return queuingMode_; } /** * Set the transport type to use * * @param transportType transport type */ void setTransportType(TransportType transportType) { /*********** Deprecation Warning ******************* * * * The unframed transports are deprecated ! * * They should be used for legancy services only * * Also note: they only works with TBinaryProtocol * ***************************************************/ if (transportType == UNFRAMED_BINARY && !dynamic_cast( getDuplexProtocolFactory()->getInputProtocolFactory().get())) { throw TLibraryException( "UnFramedTransport can only be used with TBinaryProtocol"); } else if (transportType == HEADER && !dynamic_cast( getDuplexProtocolFactory()->getInputProtocolFactory().get())) { throw TLibraryException( "HEADER transport can only be used with THeaderProtocol"); } transportType_ = transportType; } /** * Get the transport type to use * * @return transport type */ TransportType getTransportType() { return transportType_; } /** * Call this to complete initialization */ void setup(); /** * Kill the workers and wait for listeners to quit */ void cleanUp(); /** * One stop solution: * * starts worker threads, enters accept loop; when * the accept loop exits, shuts down and joins workers. */ void serve(); /** * Call this to stop the server, if started by serve() * * This causes the main serve() function to stop listening for new * connections, closes existing connections, shut down the worker threads, * and then return. */ void stop(); /** * Call this to stop listening on the server port. * * This causes the main serve() function to stop listening for new * connections while still allows the worker threads to process * existing connections. stop() still needs to be called to clear * up the worker threads. */ void stopListening(); /** * Terminate a given pending task. Callable by the thread manager or * from the server context. */ void expireClose( boost::shared_ptr task); /** * In task queue mode, drop a task from the head of the queue and shut * down the associated connection. */ bool drainPendingTask(); /** * Get the TConnectionContext for the connection currently being processed. * * This is intended to be invoked from within the TAsyncProcessor (or the * handler used by the TProcessor). * * @return Return a pointer to the TConnectionContext for the current * connection, or NULL if invoked outside of a call to * TAsyncProcessor::process(). The returned TConnectionContext * object is guaranteed to remain valid until the * TAsyncProcessor invokes its success or error callback. However, * getConnectionContext() may return NULL when invoked after * process() has returned. * * In other words, async handlers may continue using the * TConnectionContext object for the duration of the handler * processing. However, they must retrieve the TConnectionContext * inside the call to process() and cache it for later use if * they need it later. */ virtual server::TConnectionContext* getConnectionContext() const; // We use this to get the processor when in task queue mode using TServer::getProcessor; }; }}} // apache::thrift::async #endif // #ifndef THRIFT_ASYNC_TEVENTSERVER_H_