All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dasasian.chok.client.NodeProxyManager Maven / Gradle / Ivy

There is a newer version: 1.7
Show newest version
/**
 * Copyright (C) 2014 Dasasian ([email protected])
 *
 * 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.dasasian.chok.client;

import com.google.common.collect.HashMultiset;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multiset;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.RPC;
import org.apache.hadoop.ipc.VersionedProtocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.EOFException;
import java.io.IOException;
import java.lang.reflect.Proxy;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class NodeProxyManager implements INodeProxyManager {

    private final static Logger LOG = LoggerFactory.getLogger(NodeProxyManager.class);
    private final Class serverClass;
    private final Configuration hadoopConf;
    private final Map node2ProxyMap = new ConcurrentHashMap<>();
    private final INodeSelectionPolicy selectionPolicy;
    private final Multiset failedNodeInteractions = HashMultiset.create();
    private int successiveProxyFailuresBeforeReestablishing = 3;

    public NodeProxyManager(Class serverClass, Configuration hadoopConf, INodeSelectionPolicy selectionPolicy) {
        this.serverClass = serverClass;
        this.hadoopConf = hadoopConf;
        this.selectionPolicy = selectionPolicy;
    }

    /**
     * @return how many successive proxy invocation errors must happen before the
     * proxy is re-established.
     */
    public int getSuccessiveProxyFailuresBeforeReestablishing() {
        return successiveProxyFailuresBeforeReestablishing;
    }

    public void setSuccessiveProxyFailuresBeforeReestablishing(int successiveProxyFailuresBeforeReestablishing) {
        this.successiveProxyFailuresBeforeReestablishing = successiveProxyFailuresBeforeReestablishing;
    }

    public VersionedProtocol createNodeProxy(final String nodeName) throws IOException {
        LOG.debug("creating proxy for node: " + nodeName);

        String[] hostName_port = nodeName.split(":");
        if (hostName_port.length != 2) {
            throw new RuntimeException("invalid node name format '" + nodeName + "' (It should be a host name with a port number devided by a ':')");
        }
        final String hostName = hostName_port[0];
        final String port = hostName_port[1];
        final InetSocketAddress inetSocketAddress = new InetSocketAddress(hostName, Integer.parseInt(port));
        VersionedProtocol proxy = RPC.getProxy(serverClass, 0L, inetSocketAddress, hadoopConf);
        LOG.debug(String.format("Created a proxy %s for %s:%s %s", Proxy.getInvocationHandler(proxy), hostName, port, inetSocketAddress));
        return proxy;
    }

    @Override
    public VersionedProtocol getProxy(String nodeName, boolean establishIfNoExists) {
        VersionedProtocol versionedProtocol = node2ProxyMap.get(nodeName);
        if (versionedProtocol == null && establishIfNoExists) {
            synchronized (nodeName.intern()) {
                if (!node2ProxyMap.containsKey(nodeName)) {
                    try {
                        versionedProtocol = createNodeProxy(nodeName);
                        node2ProxyMap.put(nodeName, versionedProtocol);
                    } catch (Exception e) {
                        LOG.error("Could not create proxy for node '" + nodeName, e);
                    }
                }
            }
        }
        return versionedProtocol;
    }

    @Override
    public ImmutableSetMultimap createNode2ShardsMap(Collection shards) throws ShardAccessException {
        return selectionPolicy.createNode2ShardsMap(shards);
    }

    @SuppressWarnings("unchecked")
    @Override
    public void reportNodeCommunicationFailure(String nodeName, Throwable t) {
        // TODO jz: not sure if there are cases a proxy is getting invalid and
        // re-establishing it would fix the communication. If so, we should check
        // the for the exception which occurs in such cases and re-establish the
        // proxy.
        failedNodeInteractions.add(nodeName);
        int failureCount = failedNodeInteractions.count(nodeName);
        if (failureCount >= successiveProxyFailuresBeforeReestablishing || exceptionContains(t, ConnectException.class, EOFException.class)) {
            dropNodeProxy(nodeName, failureCount);
        }
    }

    @SafeVarargs
    private final boolean exceptionContains(Throwable t, Class... exceptionClasses) {
        while (t != null) {
            for (Class exceptionClass : exceptionClasses) {
                if (t.getClass().equals(exceptionClass)) {
                    return true;
                }
            }
            t = t.getCause();
        }
        return false;
    }

    private void dropNodeProxy(String nodeName, int failureCount) {
        synchronized (nodeName.intern()) {
            if (node2ProxyMap.containsKey(nodeName)) {
                LOG.warn("removing proxy for node '" + nodeName + "' after " + failureCount + " proxy-invocation errors");
                failedNodeInteractions.remove(nodeName, Integer.MAX_VALUE);
                selectionPolicy.removeNode(nodeName);
                VersionedProtocol proxy = node2ProxyMap.remove(nodeName);
                RPC.stopProxy(proxy);
            }
        }
    }

    @Override
    public void reportNodeCommunicationSuccess(String node) {
        failedNodeInteractions.remove(node, Integer.MAX_VALUE);
    }

    @Override
    public void shutdown() {
        Collection proxies = node2ProxyMap.values();
        proxies.forEach(RPC::stopProxy);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy