/* * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0 * (the "License"). You may not use this work except in compliance with the License, which is * available at www.apache.org/licenses/LICENSE-2.0 * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied, as more fully set forth in the License. * * See the NOTICE file distributed with this work for information regarding copyright ownership. */ package alluxio; import alluxio.exception.status.AlluxioStatusException; import alluxio.exception.status.UnavailableException; import alluxio.network.connection.ThriftClientPool; import alluxio.retry.ExponentialBackoffRetry; import alluxio.retry.RetryPolicy; import alluxio.thrift.AlluxioService; import alluxio.thrift.AlluxioTException; import alluxio.thrift.TStatus; import com.google.common.base.Preconditions; import org.apache.thrift.TException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; /** * The base class for clients that use {@link alluxio.network.connection.ThriftClientPool}. * * @param <C> the Alluxio service type */ public abstract class AbstractThriftClient<C extends AlluxioService.Client> { private static final Logger LOG = LoggerFactory.getLogger(AbstractThriftClient.class); protected static final int BASE_SLEEP_MS = Configuration.getInt(PropertyKey.USER_RPC_RETRY_BASE_SLEEP_MS); protected static final int MAX_SLEEP_MS = Configuration.getInt(PropertyKey.USER_RPC_RETRY_MAX_SLEEP_MS); protected static final int RPC_MAX_NUM_RETRY = Configuration.getInt(PropertyKey.USER_RPC_RETRY_MAX_NUM_RETRY); /** * If the implementation of this function guarantees that the client returned will not * be returned to any other caller. Then this whole class is threadsafe. * * @return a Thrift service client */ protected abstract C acquireClient() throws IOException; /** * @param client the client to release */ protected abstract void releaseClient(C client); /** * The RPC to be executed in {@link #retryRPC(RpcCallable)}. * * @param <V> the return value of {@link #call(AlluxioService.Client)} * @param <C> the Alluxio service type */ protected interface RpcCallable<V, C extends AlluxioService.Client> { /** * The task where RPC happens. * * @return RPC result * @throws TException when any exception defined in thrift happens */ V call(C client) throws TException; } /** * Tries to execute an RPC defined as a {@link RpcCallable}. * * @param rpc the RPC call to be executed * @param <V> type of return value of the RPC call * @return the return value of the RPC call */ protected <V> V retryRPC(RpcCallable<V, C> rpc) throws IOException { TException exception = null; RetryPolicy retryPolicy = new ExponentialBackoffRetry(BASE_SLEEP_MS, MAX_SLEEP_MS, RPC_MAX_NUM_RETRY); do { C client = acquireClient(); try { return rpc.call(client); } catch (AlluxioTException e) { if (e.getStatus().equals(TStatus.INTERNAL)) { throw new RuntimeException(e.getMessage()); } throw AlluxioStatusException.fromThrift(e); } catch (TException e) { LOG.error(e.getMessage(), e); closeClient(client); exception = e; } finally { releaseClient(client); } } while (retryPolicy.attemptRetry()); LOG.error("Failed after {} retries.", retryPolicy.getRetryCount()); Preconditions.checkNotNull(exception); throw new UnavailableException(exception); } /** * Close the given client. * * @param client the client to close */ private void closeClient(C client) { ThriftClientPool.closeThriftClient(client); } }