package util; import java.util.concurrent.TimeUnit; import org.apache.thrift.TProcessorFactory; import org.apache.thrift.protocol.TProtocolFactory; import org.apache.thrift.server.THsHaServer; import org.apache.thrift.server.TNonblockingServer; import org.apache.thrift.server.TThreadPoolServer; import org.apache.thrift.server.TThreadedSelectorServer; import org.apache.thrift.server.TThreadedSelectorServer.Args.AcceptPolicy; import org.apache.thrift.transport.TFramedTransport; import org.apache.thrift.transport.TNonblockingServerSocket; import org.apache.thrift.transport.TNonblockingServerTransport; import org.apache.thrift.transport.TServerSocket; import org.apache.thrift.transport.TServerTransport; import org.apache.thrift.transport.TTransportException; import org.apache.thrift.transport.TTransportFactory; /** * ThriftServer utility class. * * @author ThanhNB * @since 0.1.0 */ public class ThriftServerUtils { public final static int DEFAULT_CLIENT_TIMEOUT_MS = 10000; public final static int DEFAULT_MAX_FRAMESIZE = 1024 * 1024; public final static int DEFAULT_TOTAL_MAX_READ_BUFFERSIZE = 16 * 1024 * 1024; public final static int DEFAULT_NUM_SELECTOR_THREADS = 4; public final static int DEFAULT_NUM_WORKER_THREADS; static { DEFAULT_NUM_WORKER_THREADS = Math.max(2, Runtime.getRuntime().availableProcessors()); } /** * Creates a {@link TThreadPoolServer} server. * * <ul> * <li>1 dedicated thread for accepting connections</li> * <li>Once a connection is accepted, it gets scheduled to be processed by a * worker thread. The worker thread is tied to the specific client * connection until it's closed. Once the connection is closed, the worker * thread goes back to the thread pool.</li> * </ul> * * @param processorFactory * @param protocolFactory * @param port * port number on which the Thrift server will listen * @param clientTimeoutMillisecs * @param maxFrameSize * max size (in bytes) of a transport frame, supply {@code <=0} * value to let the method choose a default {@code maxFrameSize} * value (which is 1Mb) * @param maxWorkerThreads * max number of worker threads, supply {@code <=0} value to let * the method choose a default {@code maxWorkerThreads} value * (which is * {@code Math.max(2, Runtime.getRuntime().availableProcessors())} * ) * @return * @throws TTransportException */ public static TThreadPoolServer createThreadPoolServer(TProcessorFactory processorFactory, TProtocolFactory protocolFactory, int port, int clientTimeoutMillisecs, int maxFrameSize, int maxWorkerThreads) throws TTransportException { if (clientTimeoutMillisecs <= 0) { clientTimeoutMillisecs = DEFAULT_CLIENT_TIMEOUT_MS; } if (maxFrameSize <= 0) { maxFrameSize = DEFAULT_MAX_FRAMESIZE; } if (maxWorkerThreads <= 0) { maxWorkerThreads = DEFAULT_NUM_WORKER_THREADS; } TServerTransport transport = new TServerSocket(port, clientTimeoutMillisecs); TTransportFactory transportFactory = new TFramedTransport.Factory(maxFrameSize); TThreadPoolServer.Args args = new TThreadPoolServer.Args(transport) .processorFactory(processorFactory).protocolFactory(protocolFactory) .transportFactory(transportFactory).minWorkerThreads(1) .maxWorkerThreads(maxWorkerThreads); TThreadPoolServer server = new TThreadPoolServer(args); return server; } /** * Creates a {@link TNonblockingServer} server. * * <p> * Non-blocking Thrift server that uses {@code java.nio.channels.Selector} * to handle multiple clients. However, messages are processed by the same * thread that calls {@code select()}. * </p> * * @param processorFactory * @param protocolFactory * @param port * port number on which the Thrift server will listen * @param clientTimeoutMillisecs * @param maxFrameSize * max size (in bytes) of a transport frame, supply {@code <=0} * value to let the method choose a default {@code maxFrameSize} * value (which is 1Mb) * @param maxReadBufferSize * max size (in bytes) of read buffer, supply {@code <=0} value * to let the method choose a default {@code maxReadBufferSize} * value (which is 16Mb) * @return * @throws TTransportException */ public static TNonblockingServer createNonBlockingServer(TProcessorFactory processorFactory, TProtocolFactory protocolFactory, int port, int clientTimeoutMillisecs, int maxFrameSize, long maxReadBufferSize) throws TTransportException { if (clientTimeoutMillisecs <= 0) { clientTimeoutMillisecs = DEFAULT_CLIENT_TIMEOUT_MS; } if (maxFrameSize <= 0) { maxFrameSize = DEFAULT_MAX_FRAMESIZE; } if (maxReadBufferSize <= 0) { maxReadBufferSize = DEFAULT_TOTAL_MAX_READ_BUFFERSIZE; } TNonblockingServerTransport transport = new TNonblockingServerSocket(port, clientTimeoutMillisecs); TTransportFactory transportFactory = new TFramedTransport.Factory(maxFrameSize); TNonblockingServer.Args args = new TNonblockingServer.Args(transport) .processorFactory(processorFactory).protocolFactory(protocolFactory) .transportFactory(transportFactory); args.maxReadBufferBytes = maxReadBufferSize; TNonblockingServer server = new TNonblockingServer(args); return server; } /** * Creates a {@link THsHaServer} server. * * <p> * Similar to {@link TNonblockingServer} but a separate pool of worker * threads is used to handle message processing. * </p> * * @param processorFactory * @param protocolFactory * @param port * port number on which the Thrift server will listen * @param clientTimeoutMillisecs * @param maxFrameSize * max size (in bytes) of a transport frame, supply {@code <=0} * value to let the method choose a default {@code maxFrameSize} * value (which is 1Mb) * @param maxReadBufferSize * max size (in bytes) of read buffer, supply {@code <=0} value * to let the method choose a default {@code maxReadBufferSize} * value (which is 16Mb) * @param numWorkerThreads * number of worker threads, supply {@code <=0} value to let the * method choose a default {@code numWorkerThreads} value (which * is * {@code Math.max(2, Runtime.getRuntime().availableProcessors())} * ) * @return * @throws TTransportException */ public static THsHaServer createHaHsServer(TProcessorFactory processorFactory, TProtocolFactory protocolFactory, int port, int clientTimeoutMillisecs, int maxFrameSize, long maxReadBufferSize, int numWorkerThreads) throws TTransportException { if (clientTimeoutMillisecs <= 0) { clientTimeoutMillisecs = DEFAULT_CLIENT_TIMEOUT_MS; } if (maxFrameSize <= 0) { maxFrameSize = DEFAULT_MAX_FRAMESIZE; } if (maxReadBufferSize <= 0) { maxReadBufferSize = DEFAULT_TOTAL_MAX_READ_BUFFERSIZE; } if (numWorkerThreads <= 0) { numWorkerThreads = DEFAULT_NUM_WORKER_THREADS; } TNonblockingServerTransport transport = new TNonblockingServerSocket(port, clientTimeoutMillisecs); TTransportFactory transportFactory = new TFramedTransport.Factory(maxFrameSize); THsHaServer.Args args = new THsHaServer.Args(transport).processorFactory(processorFactory) .protocolFactory(protocolFactory).transportFactory(transportFactory) .workerThreads(numWorkerThreads).stopTimeoutVal(60) .stopTimeoutUnit(TimeUnit.SECONDS); args.maxReadBufferBytes = maxReadBufferSize; THsHaServer server = new THsHaServer(args); return server; } /** * Creates a {@link TThreadedSelectorServer} server. * * <p> * Similar to {@link THsHaServer} but its use 2 thread pools: one for * handling network I/O (e.g. accepting client connections), one for * handling message such like {@link THsHaServer}. * </p> * * @param processorFactory * @param protocolFactory * @param port * port number on which the Thrift server will listen * @param clientTimeoutMillisecs * @param maxFrameSize * max size (in bytes) of a transport frame, supply {@code <=0} * value to let the method choose a default {@code maxFrameSize} * value (which is 1Mb) * @param maxReadBufferSize * max size (in bytes) of read buffer, supply {@code <=0} value * to let the method choose a default {@code maxReadBufferSize} * value (which is 16Mb) * @param numSelectorThreads * number of selector threads, supply {@code <=0} value to let * the method choose a default {@code numSelectorThreads} value * (which is {@code 2} ) * @param numWorkerThreads * number of worker threads, supply {@code <=0} value to let the * method choose a default {@code numWorkerThreads} value (which * is * {@code Math.max(2, Runtime.getRuntime().availableProcessors())} * ) * @return * @throws TTransportException */ public static TThreadedSelectorServer createThreadedSelectorServer( TProcessorFactory processorFactory, TProtocolFactory protocolFactory, int port, int clientTimeoutMillisecs, int maxFrameSize, long maxReadBufferSize, int numSelectorThreads, int numWorkerThreads) throws TTransportException { if (clientTimeoutMillisecs <= 0) { clientTimeoutMillisecs = DEFAULT_CLIENT_TIMEOUT_MS; } if (maxFrameSize <= 0) { maxFrameSize = DEFAULT_MAX_FRAMESIZE; } if (maxReadBufferSize <= 0) { maxReadBufferSize = DEFAULT_TOTAL_MAX_READ_BUFFERSIZE; } if (numSelectorThreads <= 0) { numSelectorThreads = DEFAULT_NUM_SELECTOR_THREADS; } if (numWorkerThreads <= 0) { numWorkerThreads = DEFAULT_NUM_WORKER_THREADS; } TNonblockingServerTransport transport = new TNonblockingServerSocket(port, clientTimeoutMillisecs); TTransportFactory transportFactory = new TFramedTransport.Factory(maxFrameSize); TThreadedSelectorServer.Args args = new TThreadedSelectorServer.Args(transport) .processorFactory(processorFactory).protocolFactory(protocolFactory) .transportFactory(transportFactory).workerThreads(numWorkerThreads) .acceptPolicy(AcceptPolicy.FAIR_ACCEPT).acceptQueueSizePerThread(100000) .selectorThreads(numSelectorThreads); args.maxReadBufferBytes = maxReadBufferSize; TThreadedSelectorServer server = new TThreadedSelectorServer(args); return server; } }