/**
* 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
*/
/*
* Author: Olivier Rütti
*/
package groupcomm.common.order;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.logging.Logger;
import framework.Constants;
import framework.GroupCommEventArgs;
import framework.GroupCommException;
import framework.GroupCommMessage;
import framework.PID;
import framework.libraries.Trigger;
import framework.libraries.serialization.TBoolean;
import framework.libraries.serialization.THashMap;
import framework.libraries.serialization.THashSet;
import framework.libraries.serialization.TList;
import framework.libraries.serialization.TLong;
import framework.libraries.serialization.TMap;
/**
* <b> This class implements the common code that ensures FIFO ordered channels.
* </b>
* <hr>
* <b> Events:
* <dt> <i>Init</i> </dt>
* <dd> Initializes the fifo layer </dd>
* <dt> <i>FIFOSend</i> </dt>
* <dd> Send a Broadcast message, with the abcast algorithm </dd>
* <dt> <i>Pt2PtDeliver</i> </dt>
* <dd> Happend when a message is received by the lower layers </dd>
* </dl>
*/
public class FIFOImpl {
private TMap messagesSentToProc;
private TMap messagesRecvByProc;
private TMap messagesToDeliver;
// Trigger class for events routing
private Trigger trigger;
private static final Logger logger = Logger.getLogger(FIFOImpl.class
.getName());
/**
* Constructor.
*
* @@param fifo
* object of a framework protocol based class, which ensure event
* routing for this protocol.
*/
public FIFOImpl(Trigger fifo) {
logger.entering("FIFOImpl", "<constr>");
this.trigger = fifo;
messagesSentToProc = new THashMap();
messagesRecvByProc = new THashMap();
messagesToDeliver = new THashMap();
logger.exiting("FIFOImpl", "<constr>");
}
/**
* Handler for the <i>Init</i> event. </br> It sends the list of known
* processes to the lower layer allowing them to communicate with us
*
* @@param ev
* <dl>
* <dt> arg1 : Set[PID] </dt>
* <dd> List of processes for broadcasting </dd>
* </dl>
*
* @@throws GroupCommException
* @@throws IOException
* @@throws ClassNotFoundException
*/
public void handleInit(GroupCommEventArgs ev) throws GroupCommException,
IOException, ClassNotFoundException {
logger.entering("FIFOImpl", "handleInit");
TList p = (TList) ev.removeFirst();
// Look for duplicate processes in the group
for (int i = 0; i < p.size(); i++) {
messagesSentToProc.put(p.get(i), new TLong(0));
messagesRecvByProc.put(p.get(i), new TLong(0));
messagesToDeliver.put(p.get(i), new THashMap());
for (int j = i + 1; j < p.size(); j++)
if (p.get(i).equals(p.get(j)))
throw new GroupCommException("Process" + p.get(i)
+ " appears more than once in the group.");
}
// join-remove
GroupCommEventArgs jrl = new GroupCommEventArgs();
jrl.addLast(new THashSet(p)); // join
jrl.addLast(new THashSet()); // remove
trigger.trigger(Constants.JOINREMOVELIST, jrl);
logger.exiting("FIFOImpl", "handleInit");
}
/**
* The handler for the <i>FIFOSend</i> event. <br/> It send the message to
* the specificied process while respecting FIFO order. The message are
* delivered in the rder they were sent. <br/>
*
* @@param ev
* <dl>
* <dt> arg1: GroupCommMessage </dt>
* <dd> The message </dd>
* <dt> arg2: PID </dt>
* <dd> The destination </dd>
* </dl>
* @@throws GroupCommException
* @@throws IOException
* @@throws ClassNotFoundException
*/
public void handleFIFOSend(GroupCommEventArgs ev)
throws GroupCommException {
logger.entering("FIFOImpl", "handleFIFOsend");
GroupCommMessage gm = (GroupCommMessage) ev.remove(0);
TList destList = (TList) ev.remove(0);
while (!destList.isEmpty()) {
GroupCommMessage gmSend = gm.cloneGroupCommMessage();
GroupCommEventArgs evSend = new GroupCommEventArgs();
PID dest = (PID) destList.remove(0);
TLong sn = (TLong) messagesSentToProc.get(dest);
if (sn == null)
throw new GroupCommException("Process " + dest
+ " not in the group");
// msg
gmSend.addFirst(sn);
evSend.addLast(gmSend);
evSend.addLast(dest);
evSend.addLast(new TBoolean(false));
messagesSentToProc.put(dest, new TLong(sn.longValue() + 1));
trigger.trigger(Constants.PT2PTSEND, evSend);
}
logger.exiting("FIFOImpl", "handleFIFOsend");
}
/**
* The handler for the <i>Pt2PtDeliver</i> event. <br/> When we recieve a
* message from the Reliable communication layer, we have to resent the
* message to all the receipents, if it's the first time it arrives. That's
* the R-Broadcast part of the protocol. It launch a consensus too.
*
* @@param ev
* <dl>
* <dt> arg1: GroupCommMessage (id::m) </dt>
* <dd> The message, with an id </dd>
* <dt> arg2: PID </dt>
* <dd> Source PID </dd>
* </dl>
*/
public void handlePt2PtDeliver(GroupCommEventArgs ev) {
logger.entering("FIFOImpl", "handlePt2PtDeliver");
// msg = id::m
// msgClone = id::m
GroupCommMessage msg = (GroupCommMessage) ev.get(0);
PID source = (PID) ev.get(1);
long sn = ((TLong) msg.removeFirst()).longValue();
long current = ((TLong) messagesRecvByProc.get(source)).longValue();
THashMap msgs = (THashMap) messagesToDeliver.get(source);
if (sn == current) {
// Deliver the message sn and all the following ones that
// are already received.
while (ev != null) {
current++;
trigger.trigger(Constants.FIFODELIVER, ev);
ev = (GroupCommEventArgs) msgs.remove(new TLong(current));
}
messagesRecvByProc.put(source, new TLong(current));
} else {
msgs.put(new TLong(sn), ev);
}
logger.exiting("FIFOImpl", "handlePt2PtDeliver");
}
/**
* Used for debug
*
* @@param out
* The output stream used for showing infos
*/
public void dump(OutputStream out) {
PrintStream err = new PrintStream(out);
err.println("======== FIFOImpl: dump =======");
err.println(" Buffered Messages: " + String.valueOf(messagesToDeliver));
err.println(" Number of Messages Sent: "
+ String.valueOf(messagesSentToProc));
err.println(" Number of Messages Recv: "
+ String.valueOf(messagesRecvByProc));
err.println("==================================");
}
}