org.stem.client.ClusterDescriber.java Source code

Java tutorial

Introduction

Here is the source code for org.stem.client.ClusterDescriber.java

Source

/*
 * Copyright 2014 Alexey Plotnik
 *
 * 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 org.stem.client;

import com.google.common.base.Throwables;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.Uninterruptibles;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.stem.api.REST;
import org.stem.coordination.ZNode;
import org.stem.coordination.ZookeeperClient;
import org.stem.coordination.ZookeeperEventListener;
import org.stem.coordination.ZookeeperPaths;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;

public class ClusterDescriber {

    private static final Logger logger = LoggerFactory.getLogger(ClusterDescriber.class);

    final StemCluster.Manager cluster;
    final StateNotifier notifier;

    private volatile boolean isShutdown;

    private class StateNotifier {

        final ZookeeperEventListener<REST.TopologySnapshot> stateWatcher;

        public StateNotifier() {

            stateWatcher = new ZookeeperEventListener<REST.TopologySnapshot>() {
                @Override
                public Class<? extends REST.TopologySnapshot> getBaseClass() {
                    return REST.TopologySnapshot.class;
                }

                @Override
                protected ZNode.Codec codec() {
                    return REST.TopologySnapshot.CODEC;
                }

                @Override
                protected synchronized void onNodeUpdated(REST.TopologySnapshot object) {
                    logger.info("Updated topology response received");
                    onTopologyChanged(object);
                }

                @Override
                protected void onError(Throwable t) {
                    super.onError(t);
                }
            };
        }

        void start() throws Exception {
            cluster.coordinationClient.listenForZNode(ZookeeperPaths.topologySnapshotPath(), stateWatcher);
        }

        // TODO: stop() {}
    }

    public ClusterDescriber(StemCluster.Manager cluster) {
        this.cluster = cluster;
        this.notifier = new StateNotifier();
    }

    private void onTopologyChanged(REST.TopologySnapshot state) {
        refreshNodeList(cluster, state);
        //refreshNodeList(cluster, state.getTopology(), false);
        //updateMapping(state.getMapping());
        // TODO: !!!!!!!!!!!
    }

    void start() {
        if (isShutdown)
            return;

        try {
            REST.TopologySnapshot state = tryReadState();
            refreshNodeList(cluster, state);
            //refreshNodeList(cluster, topology, true);
            // TODO: refreshBucketMap(cluster, true);

            notifier.start();
        } catch (Exception e) {
            Throwables.propagate(e);
        }
    }

    private void refreshNodeList(StemCluster.Manager cluster, REST.TopologySnapshot state) {
        List<InetSocketAddress> foundHosts = new ArrayList<>();
        REST.Topology topology = state.getTopology();
        for (REST.StorageNode nodeInfo : topology.nodes()) {
            InetSocketAddress addr = nodeInfo.getSocketAddress();
            foundHosts.add(addr);
        }

        List<ListenableFuture<?>> futures = new ArrayList<>(foundHosts.size());

        for (InetSocketAddress addr : foundHosts) {
            Host host = cluster.metadata.getHost(addr);
            boolean isNew = false;
            if (null == host) {
                host = cluster.metadata.add(addr);
                isNew = true;
            }

            if (isNew)
                futures.add(cluster.triggerOnAdd(host));
        }

        try {
            ListenableFuture<List<Object>> f = Futures.allAsList(futures);

            Uninterruptibles.getUninterruptibly(f);
        } catch (ExecutionException e) {
            logger.error("Some error while handling addition of new nodes. We continue anyway");
        }

        cluster.metadata.updateRouting(state.getTopology(), state.getMapping()); // TODO: merge both parameters into single instance (REST.TopologySnapshot)
    }

    @Deprecated
    private void refreshNodeList(StemCluster.Manager cluster, REST.Topology topology, boolean isInitialAttempt) {
        List<InetSocketAddress> foundHosts = new ArrayList<InetSocketAddress>();
        List<String> dcs = new ArrayList<String>(); // TODO: implement extraction of dc name
        List<String> racks = new ArrayList<String>(); // TODO: implement extraction of rack name

        for (REST.StorageNode nodeInfo : topology.nodes()) {
            InetSocketAddress addr = nodeInfo.getSocketAddress();
            foundHosts.add(addr);
        }

        for (InetSocketAddress addr : foundHosts) {
            Host host = cluster.metadata.getHost(addr);
            boolean isNew = false;
            if (null == host) {
                host = cluster.metadata.add(addr);
                isNew = true;
            }

            if (isNew && !isInitialAttempt)
                cluster.triggerOnAdd(host); // Create connection pools in non-blocking mode

            // TODO: remove hosts
        }

        // TODO: wait until all pools will be ready
        cluster.metadata.setTopology(topology);
    }

    private void refreshNodeList() {
        refreshNodeList(cluster, cluster.metadata.getTopology(), false);
    }

    private REST.TopologySnapshot tryReadState() {
        return readState();
    }

    private REST.TopologySnapshot readState() {
        try {
            return zookeeperClient().readZNodeData(ZookeeperPaths.topologySnapshotPath(),
                    REST.TopologySnapshot.class, REST.TopologySnapshot.CODEC);

        } catch (Exception e) {
            Throwables.propagate(e);
        }
        return null;
    }

    private ZookeeperClient zookeeperClient() {
        return cluster.coordinationClient;
    }

    public CloseFuture closeAsync() {
        isShutdown = true;

        return CloseFuture.immediateFuture();
    }

    public void onUp(Host host) {
    }

    public void onDown(Host host) {

    }

    public void onRemove(Host host) {
        refreshNodeList();
    }

    public void onSuspected(Host host) {

    }

    public void refreshNodeInfo(Host host) {
        // TODO: should or not we to implement it?
    }
}