org.apache.hadoop.hbase.ipc.HBaseClientRPC.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hbase.ipc.HBaseClientRPC.java

Source

/**
 *
 * 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.ipc;

import java.io.IOException;
import java.lang.reflect.Proxy;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.Map;

import javax.net.SocketFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.IpcProtocol;
import org.apache.hadoop.hbase.client.RetriesExhaustedException;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.net.NetUtils;
import org.apache.hadoop.util.ReflectionUtils;

/**
 * An RPC implementation. This class provides the client side.
 */
@InterfaceAudience.Private
public class HBaseClientRPC {
    protected static final Log LOG = LogFactory.getLog("org.apache.hadoop.ipc.HBaseClientRPC");

    /**
     * Configuration key for the {@link org.apache.hadoop.hbase.ipc.RpcClientEngine}
     * implementation to load to handle connection protocols.  Handlers for individual
     * protocols can be configured using {@code "hbase.rpc.client.engine." +
     * protocol.class.name}.
     */
    public static final String RPC_ENGINE_PROP = "hbase.rpc.client.engine";

    // cache of RpcEngines by protocol
    private static final Map<Class<? extends IpcProtocol>, RpcClientEngine> PROTOCOL_ENGINES = new HashMap<Class<? extends IpcProtocol>, RpcClientEngine>();

    // Track what RpcEngine is used by a proxy class, for stopProxy()
    private static final Map<Class<?>, RpcClientEngine> PROXY_ENGINES = new HashMap<Class<?>, RpcClientEngine>();

    // thread-specific RPC timeout, which may override that of RpcEngine
    private static ThreadLocal<Integer> rpcTimeout = new ThreadLocal<Integer>() {
        @Override
        protected Integer initialValue() {
            return HConstants.DEFAULT_HBASE_CLIENT_OPERATION_TIMEOUT;
        }
    };

    // set a protocol to use a non-default RpcEngine
    static void setProtocolEngine(Configuration conf, Class<? extends IpcProtocol> protocol,
            Class<? extends RpcClientEngine> engine) {
        conf.setClass(RPC_ENGINE_PROP + "." + protocol.getName(), engine, RpcClientEngine.class);
    }

    // return the RpcEngine configured to handle a protocol
    static synchronized RpcClientEngine getProtocolEngine(Class<? extends IpcProtocol> protocol,
            Configuration conf) {
        RpcClientEngine engine = PROTOCOL_ENGINES.get(protocol);
        if (engine == null) {
            // check for a configured default engine
            Class<?> defaultEngine = conf.getClass(RPC_ENGINE_PROP, ProtobufRpcClientEngine.class);

            // check for a per interface override
            Class<?> impl = conf.getClass(RPC_ENGINE_PROP + "." + protocol.getName(), defaultEngine);
            LOG.debug("Using " + impl.getName() + " for " + protocol.getName());
            engine = (RpcClientEngine) ReflectionUtils.newInstance(impl, conf);
            if (protocol.isInterface()) {
                PROXY_ENGINES.put(Proxy.getProxyClass(protocol.getClassLoader(), protocol), engine);
            }
            PROTOCOL_ENGINES.put(protocol, engine);
        }
        return engine;
    }

    // return the RpcEngine that handles a proxy object
    private static synchronized RpcClientEngine getProxyEngine(Object proxy) {
        return PROXY_ENGINES.get(proxy.getClass());
    }

    /**
     * @param protocol      protocol interface
     * @param addr          address of remote service
     * @param conf          configuration
     * @param maxAttempts   max attempts
     * @param rpcTimeout    timeout for each RPC
     * @param timeout       timeout in milliseconds
     * @return proxy
     * @throws java.io.IOException e
     */
    public static IpcProtocol waitForProxy(Class<? extends IpcProtocol> protocol, InetSocketAddress addr,
            Configuration conf, int maxAttempts, int rpcTimeout, long timeout) throws IOException {
        // HBase does limited number of reconnects which is different from hadoop.
        long startTime = System.currentTimeMillis();
        IOException ioe;
        int reconnectAttempts = 0;
        while (true) {
            try {
                return getProxy(protocol, addr, conf, rpcTimeout);
            } catch (SocketTimeoutException te) {
                LOG.info("Problem connecting to server: " + addr);
                ioe = te;
            } catch (IOException ioex) {
                // We only handle the ConnectException.
                ConnectException ce = null;
                if (ioex instanceof ConnectException) {
                    ce = (ConnectException) ioex;
                    ioe = ce;
                } else if (ioex.getCause() != null && ioex.getCause() instanceof ConnectException) {
                    ce = (ConnectException) ioex.getCause();
                    ioe = ce;
                } else if (ioex.getMessage().toLowerCase().contains("connection refused")) {
                    ce = new ConnectException(ioex.getMessage());
                    ioe = ce;
                } else {
                    // This is the exception we can't handle.
                    ioe = ioex;
                }
                if (ce != null) {
                    handleConnectionException(++reconnectAttempts, maxAttempts, protocol, addr, ce);
                }
            }
            // check if timed out
            if (System.currentTimeMillis() - timeout >= startTime) {
                throw ioe;
            }

            // wait for retry
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ie) {
                // IGNORE
            }
        }
    }

    /**
     * @param retries    current retried times.
     * @param maxAttmpts max attempts
     * @param protocol   protocol interface
     * @param addr       address of remote service
     * @param ce         ConnectException
     * @throws org.apache.hadoop.hbase.client.RetriesExhaustedException
     *
     */
    private static void handleConnectionException(int retries, int maxAttmpts, Class<?> protocol,
            InetSocketAddress addr, ConnectException ce) throws RetriesExhaustedException {
        if (maxAttmpts >= 0 && retries >= maxAttmpts) {
            LOG.info("Server at " + addr + " could not be reached after " + maxAttmpts + " tries, giving up.");
            throw new RetriesExhaustedException("Failed setting up proxy " + protocol + " to " + addr.toString()
                    + " after attempts=" + maxAttmpts, ce);
        }
    }

    /**
     * Construct a client-side proxy object that implements the named protocol,
     * talking to a server at the named address.
     *
     * @param protocol      interface
     * @param addr          remote address
     * @param conf          configuration
     * @param factory       socket factory
     * @param rpcTimeout    timeout for each RPC
     * @return proxy
     * @throws java.io.IOException e
     */
    public static IpcProtocol getProxy(Class<? extends IpcProtocol> protocol, InetSocketAddress addr,
            Configuration conf, SocketFactory factory, int rpcTimeout) throws IOException {
        return getProxy(protocol, addr, User.getCurrent(), conf, factory, rpcTimeout);
    }

    /**
     * Construct a client-side proxy object that implements the named protocol,
     * talking to a server at the named address.
     *
     * @param protocol      interface
     * @param addr          remote address
     * @param ticket        ticket
     * @param conf          configuration
     * @param factory       socket factory
     * @param rpcTimeout    timeout for each RPC
     * @return proxy
     * @throws java.io.IOException e
     */
    public static IpcProtocol getProxy(Class<? extends IpcProtocol> protocol, InetSocketAddress addr, User ticket,
            Configuration conf, SocketFactory factory, int rpcTimeout) throws IOException {
        RpcClientEngine engine = getProtocolEngine(protocol, conf);
        IpcProtocol proxy = engine.getProxy(protocol, addr, ticket, conf, factory,
                Math.min(rpcTimeout, getRpcTimeout()));
        return proxy;
    }

    /**
     * Construct a client-side proxy object with the default SocketFactory
     *
     * @param protocol      interface
     * @param addr          remote address
     * @param conf          configuration
     * @param rpcTimeout    timeout for each RPC
     * @return a proxy instance
     * @throws java.io.IOException e
     */
    public static IpcProtocol getProxy(Class<? extends IpcProtocol> protocol, InetSocketAddress addr,
            Configuration conf, int rpcTimeout) throws IOException {
        return getProxy(protocol, addr, conf, NetUtils.getDefaultSocketFactory(conf), rpcTimeout);
    }

    /**
     * Stop this proxy and release its invoker's resource
     *
     * @param proxy the proxy to be stopped
     */
    public static void stopProxy(IpcProtocol proxy) {
        if (proxy != null) {
            getProxyEngine(proxy).stopProxy(proxy);
        }
    }

    public static void setRpcTimeout(int t) {
        rpcTimeout.set(t);
    }

    public static int getRpcTimeout() {
        return rpcTimeout.get();
    }

    public static void resetRpcTimeout() {
        rpcTimeout.remove();
    }
}