/** * Fortika - Robust Group Communication * Copyright (C) 2002-2006 Sergio Mena de la Cruz (EPFL) (sergio.mena@epfl.ch) * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package groupcomm.common.fd; import java.io.OutputStream; import java.io.PrintStream; import java.util.Iterator; import java.util.logging.Logger; import framework.Constants; import framework.GroupCommEventArgs; import framework.GroupCommException; import framework.GroupCommMessage; import framework.PID; import framework.libraries.Timer; import framework.libraries.Trigger; import framework.libraries.serialization.TBoolean; import framework.libraries.serialization.THashMap; import framework.libraries.serialization.THashSet; import framework.libraries.serialization.TInteger; import framework.libraries.serialization.TLinkedList; import framework.libraries.serialization.TMap; import framework.libraries.serialization.TSet; public class FDHandler { private PID myself; private static final int DEFAULT_SEND_TIMEOUT = 1000; //milliseconds private static final int DEFAULT_SUSPECT_RETRIES = 3; //retries // Set of monitored processes private TMap processes = null; //Set of Suspected processes private TSet suspects = null; //Object that routes outgoing events private Trigger trigger = null; //Interface to framework's timer facilities private Timer timer = null; //Number of timeouts before suspecting a process private int n = DEFAULT_SUSPECT_RETRIES; //Timeout value (milliseconds) private int sendTimeOut = DEFAULT_SEND_TIMEOUT; private static final Logger logger = Logger.getLogger(FDHandler.class.getName()); // public FDHandler (Trigger trigger, Timer timer, PID myself){ // logger.entering("FDHandler","<constr> 2 parameters"); // this.trigger = trigger; // this.timer = timer; // processes = new HashMap(); // suspects = new HashSet(); // logger.exiting("FDHandler","<constr> 2 parameters"); // } public FDHandler(Trigger trigger, Timer timer, PID myself, int sendTimeOut, int suspectRetries) { logger.entering("FDHandler", "<constr> 4 parameters"); this.trigger = trigger; this.timer = timer; this.myself = myself; processes = new THashMap(); suspects = new THashSet(); //Detected by A. Klaey if (sendTimeOut > 0) this.sendTimeOut = sendTimeOut; if (suspectRetries > 0) this.n = suspectRetries; logger.exiting("FDHandler", "<constr> 4 parameters"); } public TLinkedList getState(){ TLinkedList state = new TLinkedList(); state.addLast(processes.keySet()); state.addLast(suspects); return state; } public void setState(TLinkedList state){ processes.clear(); TSet tmpProcesses = (TSet) state.removeFirst(); suspects = (TSet) state.removeFirst(); Iterator it = tmpProcesses.iterator(); while(it.hasNext()){ PID p = (PID) it.next(); if (!processes.containsKey(p) && !p.equals(myself)) { processes.put(p, new TInteger(0)); timer.schedule(p, true, sendTimeOut); triggerAlive(p, true); } } triggerSuspect(); } public void handleStartStopMonitor(GroupCommEventArgs e) throws GroupCommException { //NoSuchTaskException, //AlreadySchedulingException { logger.entering("FDHandler", "handleStartStopMonitor"); TSet start = (TSet) e.removeFirst(); TSet stop = (TSet) e.removeFirst(); //Checks if there is some process in both sets Iterator i = stop.iterator(); while (i.hasNext()) { PID p = (PID) i.next(); if (start.contains(p)) { throw new GroupCommException(); } } stop(stop); start(start); logger.exiting("FDHandler", "handleStartStopMonitor"); } public void handleTimeOut(GroupCommEventArgs arg) { logger.entering("FDHandler", "handleTimeOut"); PID pid = (PID) arg.get(0); //Manage the Suspect Timeout int timeOut = ((TInteger) processes.get(pid)).intValue(); timeOut++; if (timeOut < n) { // Timeout not yet expired processes.put(pid, new TInteger(timeOut)); } else { // Timeout expired if (!suspects.contains(pid)) { suspects.add(pid); triggerSuspect(); } } //p's timer expires... // time to Send a ping to p triggerAlive(pid, true); logger.exiting("FDHandler", "handleTimeOut"); } public void handleAlive(GroupCommEventArgs e) { //throws InvalidHostException{ logger.entering("FDHandler", "handleAlive"); GroupCommMessage msg = (GroupCommMessage) e.removeFirst(); PID src = (PID) msg.tunpack(); boolean original = ((TBoolean) msg.tunpack()).booleanValue(); PID dest = (PID) msg.tunpack(); if (!dest.equals(myself)) { //Maybe I'm another incarnation. Discard it logger.exiting("FDHandler", "handleAlive"); return; } if (processes.containsKey(src)) { //I monitor p // I have to reset its timer // and remove it from the suspects (if he was inside) processes.put(src, new TInteger(0)); timer.reset(src); if (suspects.contains(src)) { suspects.remove(src); triggerSuspect(); } } if (original) { //I am not the one which launches the heartbeat. // I reply triggerAlive(src, false); } logger.exiting("FDHandler", "handleAlive"); } private void start(TSet s) { // throws AlreadySchedulingException { logger.entering("FDHandler", "start"); boolean startSuspect = false; //ORUTTI CHANGE (begin) TLinkedList toRemove = new TLinkedList(); Iterator k = suspects.iterator(); while (k.hasNext()) { PID p = (PID) k.next(); //SMENADEL CHANGE (begin) //Iterator i = s.iterator(); //boolean isInStart = false; //while (i.hasNext()){ //PID q = (PID)i.next(); //if (q.equals(p)){ //isInStart = true; //startSuspect = true; //} //} //if (!isInStart) //toRemove.add(p); //We only look at processes suspected and not monitored if (!processes.containsKey(p)) { if (s.contains(p)) { startSuspect = true; } else { toRemove.add(p); } } //SMENADEL CHANGE (end) } while (!toRemove.isEmpty()) suspects.remove(toRemove.removeFirst()); //ORUTTI CHANGE (end) Iterator i = s.iterator(); while (i.hasNext()) { PID p = (PID) i.next(); //If the process is already being monitored, do nothing //If the process is myself, do nothing, either if (!processes.containsKey(p) && !p.equals(myself)) { processes.put(p, new TInteger(0)); timer.schedule(p, true, sendTimeOut); triggerAlive(p, true); } } //ORUTTI CHANGE (begin) if (startSuspect) triggerSuspect(); //ORUTTI CHANGE (end) logger.exiting("FDHandler", "start"); } private void stop(TSet s) { // throws NoSuchTaskException { logger.entering("FDHandler", "stop"); //boolean changed = false; Iterator i = s.iterator(); while (i.hasNext()) { PID p = (PID) i.next(); if (processes.containsKey(p)) { processes.remove(p); timer.cancel(p); } // ORUTTI CHANGE (Begin) //if(suspects.contains(p)){ //suspects.remove(p); //changed = true; //} } //if(changed) triggerSuspect(); // ORUTTI CHANGE (End) logger.exiting("FDHandler", "stop"); } private void triggerAlive(PID dest, boolean orig) { logger.entering("FDHandler", "triggerAlive"); GroupCommMessage m = new GroupCommMessage(); m.tpack(dest); m.tpack(new TBoolean(orig)); m.tpack(myself); GroupCommEventArgs e = new GroupCommEventArgs(); e.addLast(m); e.addLast(dest); trigger.trigger(Constants.ALIVE, e); logger.exiting("FDHandler", "triggerAlive"); } private void triggerSuspect() { logger.entering("FDHandler", "triggerSuspect"); THashSet s = new THashSet(suspects); GroupCommEventArgs e = new GroupCommEventArgs(); e.addFirst(s); trigger.trigger(Constants.SUSPECT, e); logger.exiting("FDHandler", "triggerSuspect"); } /** * Used for debugging. </br> * Undocumented. */ public void dump(OutputStream out) { PrintStream err = new PrintStream(out); err.println("========= FDHandler: dump ========="); err.println(" Monitored Processes: " + processes); err.println(" Suspected Processes: " + suspects); err.println(" Send timeout: " + sendTimeOut); err.println(" Suspect timeout: " + n); err.println("==================================="); } }