ch.usi.da.smr.PartitionManager.java Source code

Java tutorial

Introduction

Here is the source code for ch.usi.da.smr.PartitionManager.java

Source

package ch.usi.da.smr;
/* 
 * Copyright (c) 2013 Universit della Svizzera italiana (USI)
 * 
 * This file is part of URingPaxos.
 *
 * URingPaxos is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * URingPaxos is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with URingPaxos.  If not, see <http://www.gnu.org/licenses/>.
 */

import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.log4j.Logger;
import org.apache.thrift.transport.TTransportException;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;

import ch.usi.da.paxos.api.PaxosRole;
import ch.usi.da.paxos.ring.RingDescription;
import ch.usi.da.smr.transport.ABListener;
import ch.usi.da.smr.transport.ABSender;
import ch.usi.da.smr.transport.RawABListener;
import ch.usi.da.smr.transport.RawABSender;
import ch.usi.da.smr.transport.ThriftABListener;
import ch.usi.da.smr.transport.ThriftABSender;

/**
 * Name: PartitionManager<br>
 * Description: <br>
 * 
 * Creation date: Aug 28, 2013<br>
 * $Id$
 * 
 * @author Samuel Benz benz@geoid.ch
 */
public class PartitionManager implements Watcher {

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

    private final String zoo_host;

    private ZooKeeper zoo;

    private final String prefix = "/smr";

    private final String path = prefix + "/partitions";

    private final SortedMap<Integer, Integer> circle = new TreeMap<Integer, Integer>();

    private final List<Partition> partitions = new ArrayList<Partition>();

    private final Map<String, ABSender> proposers = new HashMap<String, ABSender>();

    private int global_ring = 16;

    private Replica replica = null;

    public PartitionManager(String zoo_host) {
        this.zoo_host = zoo_host;
    }

    public void init() throws KeeperException, InterruptedException, IOException {
        logger.info("Init PartitionManager");
        zoo = new ZooKeeper(zoo_host, 3000, null);
        zoo.register(this);
        // create path
        String p = "";
        for (String s : path.split("/")) {
            if (s.length() > 0) {
                p = p + "/" + s;
                if (zoo.exists(p, false) == null) {
                    zoo.create(p, null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
                }
            }
        }
        // set default global ring = 16
        if (zoo.exists(path + "/all", false) == null) {
            zoo.create(path + "/all", "16".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
        readPartitions();
    }

    public Partition register(int replicaID, int ringID, InetAddress ip, String token) {
        try {
            if (zoo.exists(path + "/" + token, false) == null) {
                zoo.create(path + "/" + token, Integer.toString(ringID).getBytes(), Ids.OPEN_ACL_UNSAFE,
                        CreateMode.PERSISTENT);
            } else {
                zoo.setData(path + "/" + token, Integer.toString(ringID).getBytes(), -1);
            }
            byte[] data = ip.getHostAddress().getBytes();
            zoo.create(path + "/" + token + "/" + Integer.toString(replicaID), data, Ids.OPEN_ACL_UNSAFE,
                    CreateMode.EPHEMERAL);
        } catch (KeeperException e) {
            logger.error(e);
        } catch (InterruptedException e) {
        }
        readPartitions();
        for (Partition p : partitions) {
            if (p.getID().equals(token)) {
                return p;
            }
        }
        return null;
    }

    public void deregister(int replicaID, String token) {
        try {
            zoo.delete(path + "/" + token + "/" + Integer.toString(replicaID), -1);
            zoo.delete(path + "/" + token, -1);
        } catch (KeeperException | InterruptedException e) {
        }
    }

    public List<Partition> getPartitions() {
        return Collections.unmodifiableList(partitions);
    }

    public List<String> getReplicas(String token) {
        List<String> replicas = new ArrayList<String>();
        try {
            List<String> ls = zoo.getChildren(path + "/" + token, true);
            for (String s : ls) {
                replicas.add(new String(zoo.getData(path + "/" + token + "/" + s, false, null)));
            }
        } catch (Exception e) {
            logger.error(e);
        }
        return replicas;
    }

    public SortedMap<Integer, Integer> getCircle() {
        return Collections.unmodifiableSortedMap(circle);
    }

    public int getGlobalRing() {
        return global_ring;
    }

    public int getRing(String key) {
        return getRing(MurmurHash.hash32(key));
    }

    private int getRing(int hash) {
        if (circle.isEmpty()) {
            return -1;
        }
        if (!circle.containsKey(hash)) {
            SortedMap<Integer, Integer> tailMap = circle.tailMap(hash);
            hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();
        }
        return circle.get(hash);
    }

    public ABListener getRawABListener(int ring, int replicaID)
            throws IOException, KeeperException, InterruptedException {
        List<PaxosRole> role = new ArrayList<PaxosRole>();
        role.add(PaxosRole.Learner);
        List<RingDescription> rings = new ArrayList<RingDescription>();
        rings.add(new RingDescription(ring, replicaID, role));
        if (getGlobalRing() > 0) {
            rings.add(new RingDescription(getGlobalRing(), replicaID, role));
        }
        logger.debug("Create RawABListener " + rings);
        Thread.sleep(1000); // wait until PartitionManger is ready
        return new RawABListener(zoo_host, rings);
    }

    public ABListener getThriftABListener(int ring, int replicaID) throws TTransportException {
        String host = "127.0.0.1";
        try {
            host = new String(zoo.getData("/ringpaxos/ring" + ring + "/nodes/" + replicaID, false, null));
            host = host.replaceAll("(;.*)", "");
            // Sanity check: is replicaID learner in ring(partition) && global_ring
            if (zoo.exists("/ringpaxos/ring" + ring + "/learners/" + replicaID, false) != null
                    && zoo.exists("/ringpaxos/ring" + global_ring + "/learners/" + replicaID, false) != null) {
                logger.debug("ABListener check for ring " + ring + " and " + global_ring + ": OK!");
            } else {
                logger.warn("ABListener check for ring " + ring + " and " + global_ring + ": Fail!");
            }
        } catch (KeeperException | InterruptedException e) {
            logger.error(e);
        }
        logger.debug("ThriftABListener host: " + host + ":" + (9090 + replicaID));
        return new ThriftABListener(host, 9090 + replicaID);
    }

    public ABSender getRawABSender(int ring, int clientID)
            throws IOException, KeeperException, InterruptedException {
        if (proposers.containsKey(ring + "-" + clientID)) {
            return proposers.get(ring + "-" + clientID);
        } else {
            List<PaxosRole> role = new ArrayList<PaxosRole>();
            role.add(PaxosRole.Proposer);
            List<RingDescription> rings = new ArrayList<RingDescription>();
            rings.add(new RingDescription(ring, clientID, role));
            logger.debug("RawABSender " + rings);
            ABSender proposer = new RawABSender(zoo_host, rings);
            proposers.put(ring + "-" + clientID, proposer);
            return proposer;
        }
    }

    public ABSender getThriftABSender(int ring, int clientID) throws TTransportException {
        if (proposers.containsKey(ring + "-" + clientID)) {
            return proposers.get(ring + "-" + clientID);
        } else {
            String host = "127.0.0.1";
            try {
                host = new String(zoo.getData("/ringpaxos/ring" + ring + "/nodes/" + clientID, false, null));
                host = host.replaceAll("(;.*)", "");
                if (zoo.exists("/ringpaxos/ring" + ring + "/proposers/" + clientID, false) != null) {
                    logger.debug("ABSender check for ring " + ring + ": OK!");
                } else {
                    logger.warn("ABSender check for ring " + ring + ": Fail!");
                }
            } catch (KeeperException | InterruptedException e) {
                logger.error(e);
            }
            logger.debug("ThriftABSender host: " + host + ":" + (9080 + clientID));
            ABSender proposer = new ThriftABSender(host, 9080 + clientID);
            proposers.put(ring + "-" + clientID, proposer);
            return proposer;
        }
    }

    @Override
    public void process(WatchedEvent event) {
        if (event.getType() == EventType.NodeChildrenChanged && event.getPath().startsWith(path)) {
            readPartitions();
        }
    }

    public void registerPartitionChangeNotifier(Replica replica) {
        this.replica = replica;
    }

    private synchronized void readPartitions() {
        partitions.clear();
        circle.clear();
        try {
            List<String> ls = zoo.getChildren(path, true);
            for (String s : ls) {
                int ring = Integer.parseInt(new String(zoo.getData(path + "/" + s, false, null)));
                if (s.equals("all")) {
                    global_ring = Integer.parseInt(new String(zoo.getData(path + "/all", false, null)));
                } else {
                    circle.put(Integer.parseInt(s, 16), ring);
                }
            }
            for (Entry<Integer, Integer> e : circle.entrySet()) {
                String id = Integer.toString(e.getKey(), 16);
                int high = e.getKey();
                SortedMap<Integer, Integer> headMap = circle.headMap(high);
                int low = headMap.isEmpty() ? circle.lastKey() : headMap.lastKey();
                Partition p = new Partition(id, e.getValue(), low + 1, high);
                partitions.add(p);
                if (replica != null && replica.token.equals(id)) {
                    replica.setPartition(p);
                }
            }
        } catch (Exception e) {
            logger.error(e);
        }
    }

    public static void main(String args[]) throws KeeperException, InterruptedException, IOException {
        final int replicaID = 1;
        PartitionManager partitions = new PartitionManager("127.0.0.1:2181");
        partitions.init();

        // two partitions
        //partitions.register(replicaID,1,InetAddress.getLocalHost(),"0");
        //partitions.register(replicaID,2,InetAddress.getLocalHost(),"7FFFFFFF");

        // four partitions
        //partitions.register(replicaID,3,InetAddress.getLocalHost(),"3FFFFFFF");
        //partitions.register(replicaID,4,InetAddress.getLocalHost(),"-3FFFFFFF");      

        // three partitions
        partitions.register(replicaID, 1, InetAddress.getLocalHost(), "0");
        partitions.register(replicaID, 2, InetAddress.getLocalHost(), "55555554");
        partitions.register(replicaID, 2, InetAddress.getLocalHost(), "-55555554");

        List<String> ps = new ArrayList<String>();
        for (Partition p : partitions.getPartitions()) {
            ps.add(p.getID());
            System.out.println(p + " size:" + (p.getHigh() - p.getLow()));
        }

        /*Thread.sleep(1000);
        partitions.deregister(replicaID,"0");
        Thread.sleep(1000);
        System.out.println("---------------------------------------------");
        for(Partition p : partitions.getPartitions()){
           System.out.println(p);
        }*/

        //System.err.println(partitions.getRing(1));

        for (String p : ps) {
            partitions.deregister(replicaID, p);
        }
    }

}