/**
* 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.PID;
import framework.libraries.Trigger;
import framework.libraries.serialization.TCollection;
import framework.libraries.serialization.THashMap;
import framework.libraries.serialization.THashSet;
import framework.libraries.serialization.TInteger;
import framework.libraries.serialization.TLinkedList;
import framework.libraries.serialization.TList;
import framework.libraries.serialization.TSet;
public class LeaderHandler {
private PID myself;
// Set of monitored group of processes
private THashMap processes = new THashMap();
private THashMap cProcesses = new THashMap();
// Set of suspected processe
private TSet suspected = new THashSet();
// Object that routes outgoing events
private Trigger trigger = null;
private static final Logger logger = Logger.getLogger(LeaderHandler.class
.getName());
public LeaderHandler(Trigger trigger, PID myself) {
logger.entering("LeaderHandler", "<constr> 4 parameters");
this.trigger = trigger;
this.myself = myself;
logger.exiting("LeaderHandler", "<constr> 4 parameters");
}
private TLinkedList getAllProcesses() {
TLinkedList result = new TLinkedList();
TCollection allGroups = processes.keySet();
Iterator it = allGroups.iterator();
while (it.hasNext()) {
TList l = (TList) it.next();
int sizeL = l.size();
for (int i = 0; i < sizeL; i++)
if (!result.contains(l.get(i)))
result.add(l.get(i));
}
return result;
}
/**
* Le handler de l'�v�nement <i>StartStopMonitor</i>. <br>
* Cet �v�nement permet de d�buter ou d'arreter le failure detector pour
* certains processus.
*
* @param e
* <dl>
* <dt> start : Set </dt>
* <dd> L'ensemble de processus que nous devons commencer �
* monitorer. </dd>
* <dt> stop : Set </dt>
* <dd> L'ensemble de processus que nous devons arr�ter de
* monitorer.</dd>
* </dl>
*/
public void handleStartStopMonitor(GroupCommEventArgs e)
throws GroupCommException {
logger.entering("LeaderHandler", "handleStartStopMonitor");
TList start = (TList) e.removeFirst();
TList stop = (TList) e.removeFirst();
// Compute the list of processes that FD must start to monitor
// and that FD must stop to monitor
TList before = getAllProcesses();
int beforeSize = before.size();
if (!stop.isEmpty())
stop(stop);
if (!start.isEmpty())
start(start);
TList after = getAllProcesses();
int afterSize = after.size();
TSet startMonitor = new THashSet();
TSet stopMonitor = new THashSet();
for (int i = 0; i < beforeSize; i++)
if (!after.contains(before.get(i)))
stopMonitor.add(before.get(i));
for (int i = 0; i < afterSize; i++)
if (!before.contains(after.get(i)))
startMonitor.add(after.get(i));
triggerStartStop(startMonitor, stopMonitor);
logger.exiting("LeaderHandler", "handleStartStopMonitor");
}
/**
* Handler for event <i>Suspect</i>. Every time the Failure Detector
* changes its suspect list, it triggers an event that this handler is bound
* to.
*
* @param e
* <dl>
* <dt> arg1 : Set[PID] </dt>
* <dd> The updated suspect list. </dd>
* </dl>
*/
public void handleSuspect(GroupCommEventArgs e) {
logger.entering("LeaderHandler", "handleSuspect");
suspected = (TSet) e.removeFirst();
TCollection allGroups = processes.keySet();
Iterator it = allGroups.iterator();
while (it.hasNext()) {
TList l = (TList) it.next();
PID leader = (PID) l.get(0);
int sizeL = l.size();
// Cherche le le nouveau leader du groupe
// Le leader est le premier de la liste non suspect�
for (int i = 0; i < sizeL && suspected.contains(leader); i++)
leader = (PID) l.get(i);
// Si le leader a chang� -> trigger l'�v�nement
if (!leader.equals((PID) processes.get(l))) {
processes.put(l, leader);
triggerNewLeader(l, leader);
}
}
logger.exiting("LeaderHandler", "handleSuspect");
}
/**
* Commence � monitorer les processus dans <i>s</i>, si ils ne l'�taient
* pas d�j�.
*/
private void start(TList s) { // throws AlreadySchedulingException {
logger.entering("LeaderHandler", "start");
if (!cProcesses.containsKey(s)) {
processes.put(s, s.get(0));
cProcesses.put(s, new TInteger(1));
} else {
int n = ((TInteger) cProcesses.get(s)).intValue();
cProcesses.put(s, new TInteger(n + 1));
}
triggerNewLeader(s, (PID) processes.get(s));
logger.exiting("LeaderHandler", "start");
}
/**
* Arr�te de monitorer les processus contenus dans <i>s</i>. Tous les
* processus dans <i>s</i> doivent �tre monitor�s.
*/
private void stop(TList s) { // throws NoSuchTaskException {
logger.entering("LeaderHandler", "stop");
int n = ((TInteger) cProcesses.get(s)).intValue();
if (n == 1) {
processes.remove(s);
cProcesses.remove(s);
} else
cProcesses.put(s, new TInteger(n - 1));
logger.exiting("LeaderHandler", "stop");
}
private void triggerNewLeader(TList group, PID leader) {
logger.entering("LeaderHandler", "triggerNewLeader");
GroupCommEventArgs e = new GroupCommEventArgs();
e.addLast(leader);
e.addLast(group);
trigger.trigger(Constants.NEWLEADER, e);
logger.exiting("LeaderHandler", "triggerNewLeader");
}
private void triggerStartStop(TSet start, TSet stop) {
logger.entering("LeaderHandler", "triggerStartStopMonitor");
GroupCommEventArgs e = new GroupCommEventArgs();
e.addLast(start);
e.addLast(stop);
trigger.trigger(Constants.STARTSTOPMONITOR, e);
logger.exiting("LeaderHandler", "triggerStartStopMonitor");
}
/**
* Used for debugging. </br> Undocumented.
*/
public void dump(OutputStream out) {
PrintStream err = new PrintStream(out);
err.println("========= LeaderHandler: dump =========");
err.println(" Monitored Processes: " + processes);
err.println("===================================");
}
}