com.googlecode.protobuf.pro.duplex.execute.NonInterruptingThreadPoolCallExecutor Maven / Gradle / Ivy
/**
* Copyright 2010-2014 Peter Klauser
*
* Licensed 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.
*/
package com.googlecode.protobuf.pro.duplex.execute;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.protobuf.Message;
import com.google.protobuf.RpcCallback;
import com.googlecode.protobuf.pro.duplex.util.RenamingThreadFactoryProxy;
/**
* A ThreadPoolCallExecutor uses a pool of threads to handle the running of server side RPC calls.
* This executor provides a cancellation facility where a running RPC call can be interrupted before
* it finishes, because a RPC cancel which comes logically after the RPC call can be processed.
*
* Thread separation between IO-Layer threads and threads calling the RPC methods is only needed if
* the RPC method call is going to make an RPC call back to the SAME client who the call is servicing.
* If other threads than the IO-Layer threads are calling the server's RPC clients, then the
* {@link SameThreadExecutor} is sufficient.
*
* It is necessary to use separate threads to handle server RPC calls than the threads which serve
* the RPC client calls, in order to avoid deadlock on the single Netty Channel.
*
* You can choose bounds for number of Threads to service the calls, and the BlockingQueue size and
* implementation through the choice of constructors. {@link java.util.concurrent.ThreadPoolExecutor}
* discusses the choices here in detail.
*
* By default we use {@link java.util.concurrent.ArrayBlockingQueue} to begin to throttle inbound calls
* without building up a significant backlog ( introducing latency ). The ArrayBlockingQueue gives less
* "Server Overload" issues due to thread scheduling situations ( thread not yet reading from queue when
* the RPC inbound call is entered ).
*
* Alternatively use {@link java.util.concurrent.SynchronousQueue} to avoid building up a backlog of queued
* requests. If a RPC call comes in where a Thread is not ready to handle, you will receive
* a "Server Overload" error.
*
* TODO find out the queue type which is linked and not blocking unlimited size.
*
* @author Peter Klauser
*
*/
public class NonInterruptingThreadPoolCallExecutor extends ThreadPoolExecutor implements RpcServerCallExecutor, RejectedExecutionHandler {
private static Logger log = LoggerFactory.getLogger(NonInterruptingThreadPoolCallExecutor.class);
Map runningCalls = new ConcurrentHashMap();
public NonInterruptingThreadPoolCallExecutor(int corePoolSize, int maximumPoolSize) {
this(corePoolSize, maximumPoolSize, 30, TimeUnit.SECONDS, new ArrayBlockingQueue(corePoolSize, false), new RenamingThreadFactoryProxy("rpc", Executors.defaultThreadFactory()) );
}
public NonInterruptingThreadPoolCallExecutor(int corePoolSize, int maximumPoolSize, ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, 30, TimeUnit.SECONDS, new ArrayBlockingQueue(corePoolSize, false), threadFactory );
}
public NonInterruptingThreadPoolCallExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue workQueue, ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory);
setRejectedExecutionHandler(this);
}
/* (non-Javadoc)
* @see com.googlecode.protobuf.pro.duplex.execute.RpcServerCallExecutor#execute(com.googlecode.protobuf.pro.duplex.execute.PendingServerCallState)
*/
@Override
public void execute(PendingServerCallState call) {
CallRunner runner = new CallRunner(call);
runningCalls.put(runner, runner);
call.setExecutor(runner);
execute(runner);
}
/* (non-Javadoc)
* @see com.googlecode.protobuf.pro.duplex.execute.RpcServerCallExecutor#cancel(java.lang.Runnable)
*/
@Override
public void cancel(Runnable executor) {
CallRunner runner = runningCalls.remove(executor);
if ( runner != null ) {
PendingServerCallState call = runner.getCall();
// set the controller's cancel indicator
call.getController().startCancel();
// interrupt the thread running the task, to hopefully unblock any
// IO wait.
Thread threadToCancel = runner.getRunningThread();
if ( threadToCancel != null ) {
//threadToCancel.interrupt();
}
}
// the running task, still should finish by returning "null" to the RPC done
// callback.
}
/* (non-Javadoc)
* @see java.util.concurrent.ThreadPoolExecutor#beforeExecute(java.lang.Thread, java.lang.Runnable)
*/
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
CallRunner runner = runningCalls.get(r);
if ( runner != null ) {
runner.setRunningThread(t);
}
}
/* (non-Javadoc)
* @see java.util.concurrent.ThreadPoolExecutor#afterExecute(java.lang.Runnable, java.lang.Throwable)
*/
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if ( t != null ) {
log.warn("RpcCallRunner threw uncaught runtime exception.", t);
}
CallRunner runner = runningCalls.remove(r);
if ( runner != null ) {
ServerRpcController controller = runner.getCall().getController();
if ( controller.isCanceled() ) {
// we don't care if there was a response created or error, the
// client is not interested anymore. Just to the notification
if ( controller.getAndSetCancelCallbackNotified() ) {
RpcCallback
© 2015 - 2024 Weber Informatics LLC | Privacy Policy