package ch.usi.da.paxos.ring; /* * 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.InetSocketAddress; import java.util.Collections; import java.util.List; import org.apache.log4j.Logger; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.KeeperException.NoNodeException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher.Event.EventType; import org.apache.zookeeper.ZooKeeper; import ch.usi.da.paxos.TopologyManager; import ch.usi.da.paxos.api.PaxosNode; /** * Name: RingManager<br> * Description: <br> * * Creation date: Aug 12, 2012<br> * $Id$ * * @author Samuel Benz benz@geoid.ch */ public class RingManager extends TopologyManager { private final static Logger logger = Logger.getLogger(RingManager.class); private volatile int last_acceptor = 0; /** * @param node * @param ringID * @param addr * @param zoo */ public RingManager(PaxosNode node,int ringID,InetSocketAddress addr,ZooKeeper zoo) { super(node,ringID,addr,zoo,"/ringpaxos"); } /** * @param node * @param ringID * @param addr * @param zoo * @param prefix zookeeper prefix */ public RingManager(PaxosNode node, int ringID,InetSocketAddress addr,ZooKeeper zoo,String prefix) { super(node,ringID,addr,zoo,prefix); } /** * @param nodeID * @param ringID * @param addr * @param zoo * @param prefix zookeeper prefix */ public RingManager(int nodeID, int ringID,InetSocketAddress addr,ZooKeeper zoo,String prefix) { super(nodeID,ringID,addr,zoo,prefix); } /** * Init the ring manger * * (we need this init() because of the "this" references) * * @throws IOException * @throws KeeperException * @throws InterruptedException */ public void init() throws IOException, KeeperException, InterruptedException { network = new NetworkManager(this); zoo.register(this); getConfig(); network.startServer(); //Thread.sleep(1000); // give server time to start-up registerNode(); } /** * @throws InterruptedException * @throws KeeperException */ protected void getConfig() throws KeeperException, InterruptedException { super.getConfig(); // get last_acceptor try { List<String> l = zoo.getChildren(path + "/" + acceptor_path, true); int max = 0; for(String s : l){ int i = Integer.valueOf(s); if(i > max){ max = i; } } last_acceptor = max; } catch (NoNodeException e){ } } /** * @throws InterruptedException * @throws KeeperException */ protected void registerNode() throws KeeperException, InterruptedException { super.registerNode(); } private void notifyRingChanged(){ InetSocketAddress saddr = getNodeAddress(getRingSuccessor(nodeID)); logger.info("RingManager ring " + topologyID + " changed: " + nodes + " (succsessor: " + getRingSuccessor(nodeID) + " at " + saddr + ")"); if(saddr != null && currentConnection == null || !currentConnection.equals(saddr)){ network.disconnectClient(); network.connectClient(saddr); currentConnection = saddr; } } private void notifyNewCoordinator(){ logger.info("RingManger this node is the new coordinator for ring " + topologyID + "!"); Thread c = new Thread(new CoordinatorRole(this)); c.setName("Coordinator"); c.start(); } /** * @return the ring */ public List<Integer> getRing(){ return Collections.unmodifiableList(nodes); } /** * @return the ring id */ public int getRingID(){ return topologyID; } /** * @param id * @return the node id of the ring successor */ public int getRingSuccessor(int id){ int pos = nodes.indexOf(new Integer(id)); if(pos+1 >= nodes.size()){ return nodes.get(0); }else{ return nodes.get(pos+1); } } /** * @param id * @return the node id of the ring predecessor */ public int getRingPredecessor(int id){ int pos = nodes.indexOf(new Integer(id)); if(pos-1 < 0){ return nodes.get(nodes.size()-1); }else{ return nodes.get(pos-1); } } /** * @return the id of the last acceptor in the ring */ public int getLastAcceptor(){ return last_acceptor; } @Override public void process(WatchedEvent event) { int old_coordinator = coordinator; super.process(event); // ls nodes to form the ring try { if(event.getType() == EventType.NodeChildrenChanged){ if(event.getPath().startsWith(path + "/" + id_path)){ nodes.clear(); List<String> l = zoo.getChildren(path + "/" + id_path, true); for(String s : l){ nodes.add(Integer.valueOf(s)); } Collections.sort(nodes); notifyRingChanged(); }else if(event.getPath().startsWith(path + "/" + acceptor_path)){ List<String> l = zoo.getChildren(path + "/" + acceptor_path, true); int min = nodeID+1; int max = 0; for(String s : l){ int i = Integer.valueOf(s); if(i < min){ min = i; } if(i > max){ max = i; } } last_acceptor = max; coordinator = min; if(nodeID == min && old_coordinator != coordinator){ notifyNewCoordinator(); } } } } catch (KeeperException e) { logger.error(e); } catch (InterruptedException e) { } } }