package org.jgroups.protocols; import org.jgroups.*; import org.jgroups.annotations.Experimental; import org.jgroups.annotations.Property; import org.jgroups.annotations.Unsupported; import org.jgroups.stack.Protocol; import org.jgroups.util.Util; import java.io.DataInput; import java.io.DataOutput; import java.util.ArrayList; import java.util.List; /** * Implementation of UTO-TCP as designed by EPFL. Implements chaining algorithm: each sender sends the message * to a coordinator who then forwards it to its neighbor on the right, who then forwards it to its neighbor to the right * etc.<p/> * This protocol has not yet been completed and is experimental at best ! * @author Bela Ban */ @Experimental @Unsupported public class HTOTAL extends Protocol { Address coord=null; Address neighbor=null; // to whom do we forward the message (member to the right, or null if we're at the tail) Address local_addr=null; List<Address> mbrs=new ArrayList<Address>(); boolean is_coord=false; @Property private boolean use_multipoint_forwarding=false; public Object down(Event evt) { switch(evt.getType()) { case Event.VIEW_CHANGE: determineCoordinatorAndNextMember((View)evt.getArg()); break; case Event.SET_LOCAL_ADDRESS: local_addr=(Address)evt.getArg(); break; case Event.MSG: Message msg=(Message)evt.getArg(); Address dest=msg.getDest(); if(dest == null) { // only process multipoint messages if(coord == null) log.error("coordinator is null, cannot send message to coordinator"); else { if(msg.getSrc() == null) msg.setSrc(local_addr); forwardTo(coord, msg); } return null; // handled here, don't pass down by default } break; } return down_prot.down(evt); } public Object up(Event evt) { switch(evt.getType()) { case Event.VIEW_CHANGE: determineCoordinatorAndNextMember((View)evt.getArg()); break; case Event.MSG: Message msg=(Message)evt.getArg(); HTotalHeader hdr=(HTotalHeader)msg.getHeader(this.id); if(hdr == null) break; // probably a unicast message, just pass it up Message copy=msg.copy(false); // do not copy the buffer if(use_multipoint_forwarding) { copy.setDest(null); down_prot.down(new Event(Event.MSG, copy)); } else { if(neighbor != null) { forwardTo(neighbor, copy); } } msg.setDest(hdr.dest); // set destination to be the original destination msg.setSrc(hdr.src); // set sender to be the original sender (important for retransmission requests) return up_prot.up(evt); // <-- we modify msg directly inside evt } return up_prot.up(evt); } private void forwardTo(Address destination, Message msg) { HTotalHeader hdr=(HTotalHeader)msg.getHeader(this.id); if(hdr == null) { hdr=new HTotalHeader(msg.getDest(), msg.getSrc()); msg.putHeader(this.id, hdr); } msg.setDest(destination); if(log.isTraceEnabled()) log.trace("forwarding message to " + destination + ", hdr=" + hdr); down_prot.down(new Event(Event.MSG, msg)); } private void determineCoordinatorAndNextMember(View v) { Object tmp; Address retval=null; mbrs.clear(); mbrs.addAll(v.getMembers()); coord=mbrs != null && !mbrs.isEmpty()? mbrs.get(0) : null; is_coord=coord != null && local_addr != null && coord.equals(local_addr); if(mbrs == null || mbrs.size() < 2 || local_addr == null) neighbor=null; else { for(int i=0; i < mbrs.size(); i++) { tmp=mbrs.get(i); if(local_addr.equals(tmp)) { if(i + 1 >= mbrs.size()) retval=null; // we don't wrap, last member is null else retval=mbrs.get(i + 1); break; } } } neighbor=retval; if(log.isTraceEnabled()) log.trace("coord=" + coord + ", neighbor=" + neighbor); } public static class HTotalHeader extends Header { Address dest, src; public HTotalHeader() { } public HTotalHeader(Address dest, Address src) { this.dest=dest; this.src=src; } public void writeTo(DataOutput out) throws Exception { Util.writeAddress(dest, out); Util.writeAddress(src, out); } public void readFrom(DataInput in) throws Exception { dest=Util.readAddress(in); src=Util.readAddress(in); } public int size() { return Util.size(dest) + Util.size(src); } public String toString() { return "dest=" + dest + ", src=" + src; } } }