/**
* Copyright 2010 The Apache Software Foundation
*
* 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.hadoop.hbase.client;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.concurrent.Callable;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.ipc.HBaseRPC;
import org.apache.hadoop.hbase.ipc.HRegionInterface;
import org.apache.hadoop.hbase.util.Bytes;
/**
* Abstract class that implements {@link Callable}. Implementation stipulates
* return type and method we actually invoke on remote Server. Usually
* used inside a try/catch that fields usual connection failures all wrapped
* up in a retry loop.
* <p>Call {@link #connect(boolean)} to connect to server hosting region
* that contains the passed row in the passed table before invoking
* {@link #call()}.
* @see HConnection#getRegionServerWithoutRetries(ServerCallable)
* @param <T> the class that the ServerCallable handles
*/
public abstract class ServerCallable<T> implements Callable<T> {
protected final HConnection connection;
protected final byte [] tableName;
protected final byte [] row;
protected HRegionLocation location;
protected HRegionInterface server;
protected int callTimeout;
protected long startTime, endTime;
/**
* @param connection Connection to use.
* @param tableName Table name to which <code>row</code> belongs.
* @param row The row we want in <code>tableName</code>.
*/
public ServerCallable(HConnection connection, byte [] tableName, byte [] row) {
this(connection, tableName, row, HConstants.DEFAULT_HBASE_CLIENT_OPERATION_TIMEOUT);
}
public ServerCallable(HConnection connection, byte [] tableName, byte [] row, int callTimeout) {
this.connection = connection;
this.tableName = tableName;
this.row = row;
this.callTimeout = callTimeout;
}
/**
* Connect to the server hosting region with row from tablename.
* @param reload Set this to true if connection should re-find the region
* @throws IOException e
*/
public void connect(final boolean reload) throws IOException {
this.location = connection.getRegionLocation(tableName, row, reload);
this.server = connection.getHRegionConnection(location.getHostname(),
location.getPort());
}
/** @return the server name
* @deprecated Just use {@link #toString()} instead.
*/
public String getServerName() {
if (location == null) return null;
return location.getHostnamePort();
}
/** @return the region name
* @deprecated Just use {@link #toString()} instead.
*/
public byte[] getRegionName() {
if (location == null) return null;
return location.getRegionInfo().getRegionName();
}
/** @return the row
* @deprecated Just use {@link #toString()} instead.
*/
public byte [] getRow() {
return row;
}
public void beforeCall() {
HBaseRPC.setRpcTimeout(this.callTimeout);
this.startTime = System.currentTimeMillis();
}
public void afterCall() {
HBaseRPC.resetRpcTimeout();
this.endTime = System.currentTimeMillis();
}
public void shouldRetry(Throwable throwable) throws IOException {
if (this.callTimeout != HConstants.DEFAULT_HBASE_CLIENT_OPERATION_TIMEOUT)
if (throwable instanceof SocketTimeoutException
|| (this.endTime - this.startTime > this.callTimeout)) {
throw (SocketTimeoutException) (SocketTimeoutException) new SocketTimeoutException(
"Call to access row '" + Bytes.toString(row) + "' on table '"
+ Bytes.toString(tableName)
+ "' failed on socket timeout exception: " + throwable)
.initCause(throwable);
} else {
this.callTimeout = ((int) (this.endTime - this.startTime));
}
}
}