/**
* 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.
*/
package org.apache.tajo.rpc;
import java.io.IOException;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import com.google.protobuf.ServiceException;
import org.apache.tajo.conf.TajoConf;
public abstract class ServerCallable<T> {
protected InetSocketAddress addr;
protected long startTime;
protected long endTime;
protected Class protocol;
protected boolean asyncMode;
protected boolean closeConn;
protected RpcConnectionPool connPool;
public abstract T call(NettyClientBase client) throws Exception;
public ServerCallable(RpcConnectionPool connPool, InetSocketAddress addr, Class protocol, boolean asyncMode) {
this(connPool, addr, protocol, asyncMode, false);
}
public ServerCallable(RpcConnectionPool connPool, InetSocketAddress addr, Class protocol,
boolean asyncMode, boolean closeConn) {
this.connPool = connPool;
this.addr = addr;
this.protocol = protocol;
this.asyncMode = asyncMode;
this.closeConn = closeConn;
}
public void beforeCall() {
this.startTime = System.currentTimeMillis();
}
public long getStartTime(){
return startTime;
}
public void afterCall() {
this.endTime = System.currentTimeMillis();
}
public long getEndTime(){
return endTime;
}
boolean abort = false;
public void abort() {
abort = true;
}
/**
* Run this instance with retries, timed waits,
* and refinds of missing regions.
*
* @param <T> the type of the return value
* @return an object of type T
* @throws com.google.protobuf.ServiceException if a remote or network exception occurs
*/
public T withRetries() throws ServiceException {
//TODO configurable
final long pause = 500; //ms
final int numRetries = 3;
List<Throwable> exceptions = new ArrayList<Throwable>();
for (int tries = 0; tries < numRetries; tries++) {
NettyClientBase client = null;
try {
beforeCall();
if(addr != null) {
client = connPool.getConnection(addr, protocol, asyncMode);
}
return call(client);
} catch (IOException ioe) {
exceptions.add(ioe);
if(abort) {
throw new ServiceException(ioe.getMessage(), ioe);
}
if (tries == numRetries - 1) {
throw new ServiceException("Giving up after tries=" + tries, ioe);
}
} catch (Throwable t) {
throw new ServiceException(t);
} finally {
afterCall();
if(closeConn) {
connPool.closeConnection(client);
} else {
connPool.releaseConnection(client);
}
}
try {
Thread.sleep(pause * (tries + 1));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new ServiceException("Giving up after tries=" + tries, e);
}
}
return null;
}
/**
* Run this instance against the server once.
* @param <T> the type of the return value
* @return an object of type T
* @throws java.io.IOException if a remote or network exception occurs
* @throws RuntimeException other unspecified error
*/
public T withoutRetries() throws IOException, RuntimeException {
NettyClientBase client = null;
try {
beforeCall();
client = connPool.getConnection(addr, protocol, asyncMode);
return call(client);
} catch (Throwable t) {
Throwable t2 = translateException(t);
if (t2 instanceof IOException) {
throw (IOException)t2;
} else {
throw new RuntimeException(t2);
}
} finally {
afterCall();
if(closeConn) {
connPool.closeConnection(client);
} else {
connPool.releaseConnection(client);
}
}
}
private static Throwable translateException(Throwable t) throws IOException {
if (t instanceof UndeclaredThrowableException) {
t = t.getCause();
}
if (t instanceof RemoteException && t.getCause() != null) {
t = t.getCause();
}
return t;
}
}