package ch.usi.da.paxos; /* * 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.BufferedInputStream; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.util.List; import org.apache.log4j.Logger; import org.apache.zookeeper.KeeperException; import ch.usi.da.paxos.api.PaxosNode; import ch.usi.da.paxos.lab.Experiment1; import ch.usi.da.paxos.message.Control; import ch.usi.da.paxos.message.ControlType; import ch.usi.da.paxos.message.Value; import ch.usi.da.paxos.ring.Node; import ch.usi.da.paxos.ring.ProposerRole; import ch.usi.da.paxos.ring.RingDescription; import ch.usi.da.paxos.storage.Decision; /** * Name: TTYNode<br> * Description: <br> * * Creation date: Jun 21, 2013<br> * $Id$ * * @author leandro.pacheco.de.sousa@usi.ch */ public class TTYNode { static { // get hostname and pid for log file name String host = "localhost"; try { Process proc = Runtime.getRuntime().exec("hostname"); BufferedInputStream in = new BufferedInputStream(proc.getInputStream()); byte [] b = new byte[in.available()]; in.read(b); in.close(); host = new String(b).replace("\n",""); } catch (IOException e) { } int pid = 0; try { pid = Integer.parseInt((new File("/proc/self")).getCanonicalFile().getName()); } catch (NumberFormatException | IOException e) { } System.setProperty("logfilename", "L" + host + "-" + pid + ".log"); System.setProperty("valuesfilename", "L" + host + "-" + pid + ".values"); System.setProperty("proposalfilename", "L" + host + "-" + pid + ".proposal"); } private final static Logger logger = Logger.getLogger(TTYNode.class); private final static Logger valuelogger = Logger.getLogger(Value.class); /** * Thread that reads values from the standard input and proposes them to all * the rings. */ private static class StdinProposer implements Runnable { PaxosNode paxos; public StdinProposer(PaxosNode paxos) { this.paxos = paxos; } @Override public void run() { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String s; try { while ((s = in.readLine()) != null && s.length() != 0) { if (s.startsWith("exp")) { Thread t = new Thread(new Experiment1(paxos)); t.setName("Experiment"); t.run(); continue; } // propose value read from stdin to ALL the rings for (RingDescription ring : paxos.getRings()) { if (s.contains("start")) { try { ProposerRole p = (ProposerRole) paxos.getProposer(ring.getRingID()); p.setTestMode(); for(int i=0;i<p.getConcurrentValues();i++){ p.propose(p.getTestValue()); } } catch (ClassCastException e){ logger.error("Proposer did not support TestMode"); } } else if (s.startsWith("!")) { if(paxos.getProposer(ring.getRingID()) != null){ paxos.getProposer(ring.getRingID()).control(parseControl(s.replace("!",""))); }else{ logger.info("Node isn't a proposer for ring " + ring.getRingID()); } } else { if(paxos.getProposer(ring.getRingID()) != null){ paxos.getProposer(ring.getRingID()).propose(s.getBytes()); }else{ logger.info("Node isn't a proposer for ring " + ring.getRingID()); } } } } in.close(); System.exit(0); // used to stop properly in eclipse } catch (IOException e) { logger.error(e); } } } /** * Thread that prints learned values to stdout. */ private static class StdoutLearner implements Runnable { PaxosNode paxos; public StdoutLearner(PaxosNode paxos) { this.paxos = paxos; } @Override public void run() { if (paxos.getLearner() == null) { return; // not a learner } while(true) { try { Decision d = paxos.getLearner().getDecisions().take(); if(valuelogger.isDebugEnabled()){ valuelogger.debug(d); }else if(valuelogger.isInfoEnabled() && !d.getValue().isSkip() && d.getValue().getValue().length > 0){ valuelogger.info(d.getValue().asString()); } } catch (InterruptedException e) { logger.error(e); } } } } protected static Control parseControl(String s){ String[] token = s.split(","); if(token.length > 2){ ControlType type = ControlType.Prepare; if(token[0].startsWith("s")){ type = ControlType.Subscribe; }else if(token[0].startsWith("u")){ type = ControlType.Unsubscribe; } return new Control(1,type,Integer.parseInt(token[1]),Integer.parseInt(token[2])); }else{ return null; } } public static void main(String[] args) { String zoo_host = "127.0.0.1:2181"; if (args.length > 2) { zoo_host = args[2]; } int groupID = -1; if (args.length > 3) { groupID = Integer.parseInt(args[3]); logger.info("Node is in group " + groupID); } if (args.length < 2) { System.err.println("Plese use \"Node\" \"node ID\" \"ring ID:roles[;ring ID:roles]\" [zookeeper] [groupID] (eg. 1 1:PAL)"); } else { int nodeID = Integer.parseInt(args[0]); List<RingDescription> rings = Util.parseRingsArgument(args[1]); // start paxos node final Node node = new Node(nodeID,groupID,zoo_host,rings); try { node.start(); Runtime.getRuntime().addShutdownHook(new Thread(){ @Override public void run(){ try { node.stop(); } catch (InterruptedException e) { } } }); } catch (IOException | KeeperException | InterruptedException e) { e.printStackTrace(); System.exit(1); } // start stdin learner Thread lt = new Thread(new StdoutLearner(node)); lt.setName("StdoutLearner"); lt.start(); // start stdout proposer Thread pt = new Thread(new StdinProposer(node)); pt.setName("StdinProposer"); pt.start(); } } }