All Downloads are FREE. Search and download functionalities are using the official Maven repository.

bboss.org.jgroups.protocols.SEQUENCER Maven / Gradle / Ivy

The newest version!

package bboss.org.jgroups.protocols;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicLong;

import bboss.org.jgroups.Address;
import bboss.org.jgroups.Event;
import bboss.org.jgroups.Global;
import bboss.org.jgroups.Header;
import bboss.org.jgroups.Message;
import bboss.org.jgroups.View;
import bboss.org.jgroups.ViewId;
import bboss.org.jgroups.annotations.Experimental;
import bboss.org.jgroups.annotations.MBean;
import bboss.org.jgroups.annotations.ManagedAttribute;
import bboss.org.jgroups.annotations.ManagedOperation;
import bboss.org.jgroups.stack.Protocol;
import bboss.org.jgroups.util.SeqnoTable;
import bboss.org.jgroups.util.Util;


/**
 * Implementation of total order protocol using a sequencer. Consult doc/design/SEQUENCER.txt for details
 * @author Bela Ban
 * @version $Id: SEQUENCER.java,v 1.36 2010/06/15 06:44:35 belaban Exp $
 */
@Experimental
@MBean(description="Implementation of total order protocol using a sequencer")
public class SEQUENCER extends Protocol {
    private Address                    local_addr=null, coord=null;
    private final Collection
members=new ArrayList
(); private volatile boolean is_coord=false; private AtomicLong seqno=new AtomicLong(0); /** Maintains messages forwarded to the coord which which no ack has been received yet. * Needs to be sorted so we resend them in the right order */ private final Map forward_table=new TreeMap(); /** Map: maintains the highest seqnos seen for a given member */ private final SeqnoTable received_table=new SeqnoTable(0); private long forwarded_msgs=0; private long bcast_msgs=0; private long received_forwards=0; private long received_bcasts=0; @ManagedAttribute public boolean isCoordinator() {return is_coord;} public Address getCoordinator() {return coord;} public Address getLocalAddress() {return local_addr;} @ManagedAttribute public long getForwarded() {return forwarded_msgs;} @ManagedAttribute public long getBroadcast() {return bcast_msgs;} @ManagedAttribute public long getReceivedForwards() {return received_forwards;} @ManagedAttribute public long getReceivedBroadcasts() {return received_bcasts;} @ManagedOperation public void resetStats() { forwarded_msgs=bcast_msgs=received_forwards=received_bcasts=0L; } @ManagedOperation public Map dumpStats() { Map m=super.dumpStats(); m.put("forwarded", new Long(forwarded_msgs)); m.put("broadcast", new Long(bcast_msgs)); m.put("received_forwards", new Long(received_forwards)); m.put("received_bcasts", new Long(received_bcasts)); return m; } @ManagedOperation public String printStats() { return dumpStats().toString(); } public Object down(Event evt) { switch(evt.getType()) { case Event.MSG: Message msg=(Message)evt.getArg(); Address dest=msg.getDest(); if(dest == null || dest.isMulticastAddress()) { // only handle multicasts long next_seqno=seqno.getAndIncrement(); if(is_coord) { SequencerHeader hdr=new SequencerHeader(SequencerHeader.BCAST, local_addr, next_seqno); msg.putHeader(this.id, hdr); broadcast(msg, false); // don't copy, just use the message passed as argument } else { // SequencerHeader hdr=new SequencerHeader(SequencerHeader.FORWARD, local_addr, next_seqno); // msg.putHeader(this.id, hdr); forwardToCoord(msg, next_seqno); } return null; // don't pass down } break; case Event.VIEW_CHANGE: handleViewChange((View)evt.getArg()); break; case Event.SET_LOCAL_ADDRESS: local_addr=(Address)evt.getArg(); break; } return down_prot.down(evt); } public Object up(Event evt) { Message msg; SequencerHeader hdr; switch(evt.getType()) { case Event.MSG: msg=(Message)evt.getArg(); hdr=(SequencerHeader)msg.getHeader(this.id); if(hdr == null) break; // pass up switch(hdr.type) { case SequencerHeader.FORWARD: if(!is_coord) { if(log.isErrorEnabled()) log.error(local_addr + ": non-coord; dropping FORWARD request from " + msg.getSrc()); return null; } broadcast(msg, true); // do copy the message received_forwards++; return null; case SequencerHeader.BCAST: deliver(msg, evt, hdr); received_bcasts++; return null; case SequencerHeader.WRAPPED_BCAST: unwrapAndDeliver(msg); // unwrap the original message (in the payload) and deliver it received_bcasts++; return null; } break; case Event.VIEW_CHANGE: Object retval=up_prot.up(evt); handleViewChange((View)evt.getArg()); return retval; case Event.SUSPECT: handleSuspect((Address)evt.getArg()); break; } return up_prot.up(evt); } /* --------------------------------- Private Methods ----------------------------------- */ private void handleViewChange(View v) { Vector
mbrs=v.getMembers(); if(mbrs.isEmpty()) return; boolean coord_changed=false; synchronized(this) { members.clear(); members.addAll(mbrs); Address prev_coord=coord; coord=mbrs.firstElement(); is_coord=local_addr != null && local_addr.equals(coord); coord_changed=prev_coord != null && !prev_coord.equals(coord); } if(coord_changed) { resendMessagesInForwardTable(); // maybe optimize in the future: broadcast directly if coord } // remove left members from received_table received_table.retainAll(mbrs); } private void handleSuspect(Address suspected_mbr) { boolean coord_changed=false; if(suspected_mbr == null) return; synchronized(this) { List
non_suspected_mbrs=new ArrayList
(members); non_suspected_mbrs.remove(suspected_mbr); if(!non_suspected_mbrs.isEmpty()) { Address prev_coord=coord; coord=non_suspected_mbrs.get(0); is_coord=local_addr != null && local_addr.equals(coord); coord_changed=prev_coord != null && !prev_coord.equals(coord); } } if(coord_changed) { resendMessagesInForwardTable(); // maybe optimize in the future: broadcast directly if coord } } /** * Sends all messages currently in forward_table to the new coordinator (changing the dest field). * This needs to be done, so the underlying reliable unicast protocol (e.g. UNICAST) adds these messages * to its retransmission mechanism
* Note that we need to resend the messages in order of their seqnos ! We also need to prevent other message * from being inserted until we're done, that's why there's synchronization. */ private void resendMessagesInForwardTable() { Map copy; synchronized(forward_table) { copy=new TreeMap(forward_table); } for(Map.Entry entry: copy.entrySet()) { Long key=entry.getKey(); byte[] val=entry.getValue(); Message forward_msg=new Message(coord, null, val); SequencerHeader hdr=new SequencerHeader(SequencerHeader.FORWARD, local_addr, key); forward_msg.putHeader(this.id, hdr); if (log.isTraceEnabled()) { log.trace("resending msg " + local_addr + "::" + key + " to coord (" + coord + ")"); } down_prot.down(new Event(Event.MSG, forward_msg)); } } private void forwardToCoord(final Message msg, long seqno) { msg.setSrc(local_addr); if(log.isTraceEnabled()) log.trace("forwarding msg " + msg + " (seqno " + seqno + ") to coord (" + coord + ")"); byte[] marshalled_msg; try { marshalled_msg=Util.objectToByteBuffer(msg); synchronized(forward_table) { forward_table.put(seqno, marshalled_msg); } Message forward_msg=new Message(coord, null, marshalled_msg); SequencerHeader hdr=new SequencerHeader(SequencerHeader.FORWARD, local_addr, seqno); forward_msg.putHeader(this.id, hdr); down_prot.down(new Event(Event.MSG, forward_msg)); forwarded_msgs++; } catch(Exception e) { log.error("failed marshalling message", e); } } private void broadcast(final Message msg, boolean copy) { Message bcast_msg=null; final SequencerHeader hdr=(SequencerHeader)msg.getHeader(this.id); if(!copy) { bcast_msg=msg; // no need to add a header, message already has one } else { bcast_msg=new Message(null, local_addr, msg.getRawBuffer(), msg.getOffset(), msg.getLength()); SequencerHeader new_hdr=new SequencerHeader(SequencerHeader.WRAPPED_BCAST, hdr.getOriginalSender(), hdr.getSeqno()); bcast_msg.putHeader(this.id, new_hdr); } if(log.isTraceEnabled()) log.trace("broadcasting msg " + bcast_msg + " (seqno " + hdr.getSeqno() + ")"); down_prot.down(new Event(Event.MSG, bcast_msg)); bcast_msgs++; } /** * Unmarshal the original message (in the payload) and then pass it up (unless already delivered) * @param msg */ private void unwrapAndDeliver(final Message msg) { try { SequencerHeader hdr=(SequencerHeader)msg.getHeader(this.id); Message msg_to_deliver=(Message)Util.objectFromByteBuffer(msg.getRawBuffer(), msg.getOffset(), msg.getLength()); long msg_seqno=hdr.getSeqno(); if(!canDeliver(msg_to_deliver.getSrc(), msg_seqno)) return; if(log.isTraceEnabled()) log.trace("delivering msg " + msg_to_deliver + " (seqno " + msg_seqno + "), original sender " + msg_to_deliver.getSrc()); up_prot.up(new Event(Event.MSG, msg_to_deliver)); } catch(Exception e) { log.error("failure unmarshalling buffer", e); } } private void deliver(Message msg, Event evt, SequencerHeader hdr) { Address sender=msg.getSrc(); if(sender == null) { if(log.isErrorEnabled()) log.error("sender is null, cannot deliver msg " + msg); return; } long msg_seqno=hdr.getSeqno(); if(!canDeliver(sender, msg_seqno)) return; if(log.isTraceEnabled()) log.trace("delivering msg " + msg + " (seqno " + msg_seqno + "), sender " + sender); up_prot.up(evt); } private boolean canDeliver(Address sender, long seqno) { // this is the ack for the message sent by myself if(sender.equals(local_addr)) { synchronized(forward_table) { forward_table.remove(seqno); } } // if msg was already delivered, discard it boolean added=received_table.add(sender, seqno); if(!added) { if(log.isWarnEnabled()) log.warn("seqno (" + sender + "::" + seqno + " has already been received " + "(highest received=" + received_table.getHighestReceived(sender) + "); discarding duplicate message"); } return added; } /* ----------------------------- End of Private Methods -------------------------------- */ public static class SequencerHeader extends Header { private static final byte FORWARD = 1; private static final byte BCAST = 2; private static final byte WRAPPED_BCAST = 3; byte type=-1; /** the original sender's address and a seqno */ ViewId tag=null; public SequencerHeader() { } public SequencerHeader(byte type, Address original_sender, long seqno) { this.type=type; this.tag=new ViewId(original_sender, seqno); } public Address getOriginalSender() { return tag != null? tag.getCoordAddress() : null; } public long getSeqno() { return tag != null? tag.getId() : -1; } public String toString() { StringBuilder sb=new StringBuilder(64); sb.append(printType()); if(tag != null) sb.append(" (tag=").append(tag).append(")"); return sb.toString(); } private final String printType() { switch(type) { case FORWARD: return "FORWARD"; case BCAST: return "BCAST"; case WRAPPED_BCAST: return "WRAPPED_BCAST"; default: return "n/a"; } } public void writeTo(DataOutputStream out) throws IOException { out.writeByte(type); Util.writeStreamable(tag, out); } public void readFrom(DataInputStream in) throws IOException, IllegalAccessException, InstantiationException { type=in.readByte(); tag=(ViewId)Util.readStreamable(ViewId.class, in); } public int size() { int size=Global.BYTE_SIZE *2; // type + presence byte if(tag != null) size+=tag.serializedSize(); return size; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy