poke.server.management.managers.ElectionManager.java Source code

Java tutorial

Introduction

Here is the source code for poke.server.management.managers.ElectionManager.java

Source

/*
 * copyright 2014, gash
 * 
 * Gash 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 poke.server.management.managers;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicReference;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import poke.monitor.HeartMonitor;
import poke.server.management.ManagementHandler;
import poke.server.management.ManagementInitializer;
import poke.server.management.managers.HeartbeatData.BeatStatus;

import com.google.protobuf.GeneratedMessage;

import eye.Comm.LeaderElection;
import eye.Comm.LeaderElection.VoteAction;
import eye.Comm.Management;

/**
 * The election manager is used to determine leadership within the network.
 * 
 * @author gash
 * 
 */
public class ElectionManager extends Thread {
    protected static Logger logger = LoggerFactory.getLogger("management");
    protected static AtomicReference<ElectionManager> instance = new AtomicReference<ElectionManager>();
    private HeartbeatManager heartbeatMgr;
    private HeartbeatConnector heartbeatConn;
    private ManagementHandler handler;
    ConcurrentLinkedQueue<HeartMonitor> monitors;
    private static String leader = null;

    protected ChannelFuture channel; // do not use directly, call connect()!
    private String nodeId;
    private String myId;

    boolean forever = true;

    /** @brief the number of votes this server can cast */
    private int votes = 1;
    private String reqNodeId;
    private static int N = 0;

    public static ElectionManager getInstance(String id, int votes) {
        instance.compareAndSet(null, new ElectionManager(id, votes));
        return instance.get();
    }

    public static ElectionManager getInstance() {
        return instance.get();
    }

    public void setMonitor(ConcurrentLinkedQueue<HeartMonitor> monitors) {
        this.monitors = monitors;
    }

    /**
     * initialize the manager for this server
     * 
     * @param nodeId
     *            The server's (this) ID
     */
    protected ElectionManager(String nodeId, int votes) {
        this.nodeId = nodeId;

        if (votes >= 0)
            this.votes = votes;
    }

    /**
     * create connection to remote server
     * 
     * @return
     */
    protected Channel connect(String host, int port) {
        // Start the connection attempt.
        if (channel == null) {
            try {
                handler = new ManagementHandler();
                ManagementInitializer mi = new ManagementInitializer(false);

                Bootstrap b = new Bootstrap();
                b.group(new NioEventLoopGroup()).channel(NioSocketChannel.class).handler(mi);
                b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000);
                b.option(ChannelOption.TCP_NODELAY, true);
                b.option(ChannelOption.SO_KEEPALIVE, true);

                // Make the connection attempt.
                channel = b.connect(host, port).syncUninterruptibly();
                channel.awaitUninterruptibly(5000l);

                if (N == Integer.MAX_VALUE)
                    N = 1;
                else
                    N++;

            } catch (Exception ex) {
                logger.debug("failed to initialize the heartbeat connection");
            }
        }

        if (channel != null && channel.isDone() && channel.isSuccess())
            return channel.channel();
        else
            throw new RuntimeException("Not able to establish connection to server");
    }

    /*
     * Generate Election Nominate Messages
     */
    private Management generateEM(String nodeId, VoteAction v) {
        LeaderElection.Builder l = LeaderElection.newBuilder();
        l.setDesc("Leader election Attribute Set");
        l.setNodeId(nodeId);
        l.setBallotId("dummy ballot");
        l.setDesc("my vote");
        l.setVote(v);
        Management.Builder m = Management.newBuilder();
        m.setElection(l.build());
        return m.build();
    }

    public static String getLeader() {
        return leader;
    }

    @Override
    public void run() {
        logger.info("Starting the run method");

        while (true) {
            monitors = heartbeatConn.getMonitors();
            GeneratedMessage msg = null;
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            for (HeartbeatData hd : heartbeatMgr.incomingHB.values()) {
                if (hd.getStatus() == BeatStatus.Active) {
                    if (msg == null)
                        msg = generateEM(this.nodeId, VoteAction.NOMINATE);
                    logger.info("this.nodeId " + this.nodeId);

                    try {
                        logger.info("sending leader nominate message");

                        for (HeartMonitor hm : monitors) {
                            if (hm.getWhoami() == hd.getNodeId()) {
                                String host = hm.getHost();
                                int port = hm.getPort();
                                Channel ch = connect(host, port);
                                ch.writeAndFlush(msg);

                            }

                        }
                    } catch (Exception e) {

                    }
                }
            }
        }
    }

    /**
     * @param args
     */
    public void processRequest(LeaderElection req) {
        if (req == null) {
            logger.info("Null request");
            return;
        }
        if (req.hasExpires()) {
            long ct = System.currentTimeMillis();
            if (ct > req.getExpires()) {
                logger.info("Election Over");
                return;
            }
        }

        logger.info("Election message received");

        if (req.getVote().getNumber() == VoteAction.ELECTION_VALUE) {
            logger.info("Election is declared");

        } else if (req.getVote().getNumber() == VoteAction.DECLAREVOID_VALUE) {
            // no one was elected, I am dropping into standby mode`
        } else if (req.getVote().getNumber() == VoteAction.DECLAREWINNER_VALUE) {
            // some node declared themself the leader
        } else if (req.getVote().getNumber() == VoteAction.ABSTAIN_VALUE) {
            // for some reason, I decline to vote
        } else if (req.getVote().getNumber() == VoteAction.NOMINATE_VALUE) {
            if (nodeId.equals("zero"))
                myId = "a";
            else if (nodeId.equals("one"))
                myId = "b";
            else if (nodeId.equals("two"))
                myId = "c";
            else if (nodeId.equals("three"))
                myId = "d";

            if (req.getNodeId().equals("zero"))
                reqNodeId = "a";
            else if (req.getNodeId().equals("one"))
                reqNodeId = "b";
            else if (req.getNodeId().equals("two"))
                reqNodeId = "c";
            else if (req.getNodeId().equals("three"))
                reqNodeId = "d";

            int comparedToMe = reqNodeId.compareTo(myId);
            if (comparedToMe < 0) {
                // Discard the id received from node and nominate myself
                logger.info("Discard request for leader for node :" + req.getNodeId());
            } else if (comparedToMe > 0) {
                // forward the message to all the nearest nodes. In case of LCR
                // there will be only
                // one nearest node as LCR works for unidirectional ring
                logger.info("Forward Node Id for leader election : " + req.getNodeId());
                for (HeartMonitor hm : monitors) {
                    String host = hm.getHost();
                    int port = hm.getPort();
                    Channel ch = connect(host, port);
                    GeneratedMessage msg = generateEM(req.getNodeId(), VoteAction.NOMINATE);
                    ch.writeAndFlush(msg);
                }
            } else if (comparedToMe == 0) {
                logger.info("Node Id " + req.getNodeId() + " is leader !! ");
                leader = req.getNodeId();
            }

        }
    }

    public void setHeartbeatManager(HeartbeatManager hbmgr) {
        this.heartbeatMgr = hbmgr;
    }

    public void setHeartbeatConnector(HeartbeatConnector conn) {
        this.heartbeatConn = conn;

    }

}