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

com.gemstone.org.jgroups.protocols.NAKACK.MessageProtocol Maven / Gradle / Ivy

The newest version!
package JavaGroups.JavaStack.Protocols;

import java.io.*;
import java.util.*;
import JavaGroups.*;
import JavaGroups.JavaStack.*;



class NakAckHeader implements Serializable {
    public static final int NAK_MSG        = 1;  // asynchronous msg
    public static final int ACK_MSG        = 2;  // synchronous msg
    public static final int RETRANSMIT_MSG = 3;  // retransmit msg

    int     type=0;
    long    seqno=-1;
    ViewId  vid=null;


    
    NakAckHeader(int type, long seqno, ViewId vid) {
	this.type=type;
	this.seqno=seqno;
	this.vid=vid;
    }




    String Type2Str(int t) {
	switch(t) {
	case NAK_MSG: return "NAK_MSG";
	case ACK_MSG: return "ACK_MSG";
	case RETRANSMIT_MSG: return "RETRANSMIT_MSG";
	default: return "";
	}
    }

    public String toString() {
	return "[NAKACK: " + Type2Str(type) + ", seqno=" + seqno + ", vid=" + vid + "]";
    }
}





/**
   Combined NAK and ACK class. The layer contains a NAKer and an ACKer: depending on which
   one is set, a message will be sent using a negative acknowldegment scheme (NAK) or regular
   acknowledgement (ACK). Event SET_ACK_MODE switches between the 2 modes. The following
   communication between 2 peers exists (left side is initiator, right side receiver):
   

      send_nak
   -------------->       asynchronous


      send_ack
   ------------->>       synchronous
   <--------------
        ack


      retransmit
   <--------------       asynchronous


   
When using NAKs, a messages is just tagged with a sequence number (seqno) and broadcast asynchronously. A receiver requests retransmissions (asynchronous) for gaps between received messages. When ACKs are used, each message is broadcast to the current membership synchronously and only when a response from each member has been received (or a suspect notification) will the call return. If a response has not been received after a timeout, the message will be retransmitted to the corresponding member. If the response is not received after n retries, and no suspect notification has been received, the member will be suspected. When a message is sent, it will contain a header describing the type of the message, and containing additional data, such as sequence number etc. When a message is received, it is fed into either the ACKer or NAKer, depending on the header's type. */ public class NAKACK extends MessageProtocol { LosslessTransmission naker=new NAKer(); // LosslessTransmission acker=new ACKer(); // LosslessTransmission transmitter=naker; // NAK is default long seqno=0; // current message sequence number Hashtable received_msgs=new Hashtable(); // ordered by sender -> NakReceiverWindow Hashtable sent_msgs=new Hashtable(); // ordered by seqno (sent by me !) ViewId vid=null; View view=null; //Object myaddr=null; class LosslessTransmission implements NakReceiverWindow.RetransmitCommand { void Reset() { NakReceiverWindow win; sent_msgs.clear(); for(Enumeration e=received_msgs.elements(); e.hasMoreElements();) { win=(NakReceiverWindow)e.nextElement(); win.Reset(); } received_msgs.clear(); } void Send(long id, Message msg) { } void Receive(long id, Message msg) { Object sender=msg.GetSrc(); NakReceiverWindow win=(NakReceiverWindow)received_msgs.get(sender); Message msg_to_deliver; if(win == null) { win=new NakReceiverWindow(sender, this, 0); received_msgs.put(sender, win); } System.out.println("RECV #" + id); win.Add(id, msg); while(true) { msg_to_deliver=win.Remove(); if(msg_to_deliver != null) PassUp(new Event(Event.MSG, msg_to_deliver)); else break; } } /** Called by retransmission thread when gap is detected. Sends retr. request to originator of msg */ public void Retransmit(long seqno, Object sender, int num_tries) { System.out.println("--> Retransmit(" + seqno + ") to " + sender); NakAckHeader hdr=new NakAckHeader(NakAckHeader.RETRANSMIT_MSG, seqno, vid); Message retransmit_msg=new Message(sender, null, null); retransmit_msg.AddHeader(hdr); try { SendMessage(retransmit_msg, GroupRequest.GET_NONE, 0); // non-blocking request } catch(Exception e) { System.err.println("NAKACK.NAKer.Retransmit(): " + e); } } // Retransmit from sent-table void Retransmit(Object dest, long id) { Message m=(Message)sent_msgs.get(new Long(id)), retr_msg; if(m == null) { System.err.println("NAKACK.LosslessTransmission.Retransmit(): message with " + "seqno=" + id + " not found !"); return; } retr_msg=m.Copy(); retr_msg.SetDest(dest); try { SendMessage(retr_msg, GroupRequest.GET_NONE, 0); // non-blocking } catch(Exception e) { System.err.println("NAKACK.LosslessTransmission.Retransmit(): " +e); } } void Stable(long id) {} } class NAKer extends LosslessTransmission { void Send(long id, Message msg) { Message copy; if(vid == null) { System.err.println("NAKACK.NAKer.Send(): vid is null !"); return; } msg.AddHeader(new NakAckHeader(NakAckHeader.NAK_MSG, id, vid)); copy=msg.Copy(); sent_msgs.put(new Long(id), copy); System.out.println("SEND #" + id + ", msg is " + msg); // if(id % 7 == 0) { //transmitter.Retransmit(id, myaddr, 0); //return; //} CastMessage(view.GetMembers(), msg, GroupRequest.GET_NONE, 0); // don't wait for rsps } } class ACKer extends LosslessTransmission { // contains sent_table void Send(long id, Message msg) { if(vid == null) { System.err.println("NAKACK.ACKer.Send(): vid is null !"); return; } // +++ Send reliably (with ACKs) // msg.AddHeader(new NakAckHeader(NakAckHeader.ACK_MSG, id, vid)); // sent_msgs.put(new Long(id), msg); // System.out.println("NAKer: sending message #" + id + " --> " + msg); // PassDown(new Event(Event.MSG, msg)); } } private long GetNextSeqno() {return seqno++;} public String GetName() {return "NAKACK";} /** Callback. Called when a request for this protocol layer is received. */ public Object Handle(Message req) { Object obj; NakAckHeader hdr; int rc; obj=req.PeekHeader(); if(obj == null || !(obj instanceof NakAckHeader)) { System.err.println("NAKACK.Handle(): message does not contain a NakAckHeader !"); return null; } hdr=(NakAckHeader)req.RemoveHeader(); if(vid != null) { if(hdr.vid == null) { System.err.println("NAKACK.Handle(): message's view is null ! " + "Cannot check against our own view !"); } else { rc=hdr.vid.Compare(vid); if(rc == 0) { // same vid -> OK ; } else if(rc < 0) { // message sent in prev. view -> discard ! System.err.println("NAKACK.Handle(): message's vid is smaller than " + "current vid: message is discarded !"); return null; } else if(rc > 0) { System.out.println("NAKACK.Handle(): message's vid is bigger than " + "current vid: message is queued !"); // +++ Implement: queue message } else { System.err.println("NAKACK.Handle(): comparison of message's vid with ours " + "yielded " + rc); } } } else System.err.println("NAKACK.Handle(): our vid is not available ! "+ "Cannot check against message's vid !"); switch(hdr.type) { case NakAckHeader.NAK_MSG: case NakAckHeader.ACK_MSG: transmitter.Receive(hdr.seqno, req); break; case NakAckHeader.RETRANSMIT_MSG: transmitter.Retransmit(req.GetSrc(), hdr.seqno); break; default: System.err.println("NAKACK.HandleUpEvent(): NakAck header type " + hdr.type + " not known !"); break; } return null; } /** Callback. Called by superclass when event may be handled.

Do not use PassUp in this method as the event is passed up by default by the superclass after this method returns ! @return boolean Defaults to true. If false, event will not be passed up the stack. */ public boolean HandleUpEvent(Event evt) { // switch(evt.GetType()) { // case Event.SET_LOCAL_ADDRESS: // myaddr=evt.GetArg(); // break; // } return true; } /** Callback. Called by superclass when event may be handled.

Do not use PassDown in this method as the event is passed down by default by the superclass after this method returns ! @return boolean Defaults to true. If false, event will not be passed down the stack. */ public boolean HandleDownEvent(Event evt) { Message msg; switch(evt.GetType()) { case Event.MSG: msg=(Message)evt.GetArg(); if(msg.GetDest() != null && !((Address)msg.GetDest()).IsMulticastAddress()) return true; // unicast address: not null and not mcast, pass down unchanged transmitter.Send(GetNextSeqno(), msg); return false; // don't pass down the stack, transmitter does this for us ! case Event.VIEW_CHANGE: view=(View)evt.GetArg(); vid=new ViewId((Address)view.GetCreator(), view.GetId()); seqno=0; // reset sequence number transmitter.Reset(); // ++ Implement: if there are any queued messages that were previously // sent for this vid, add those that match the new vid now ! break; case Event.SWITCH_NAK: transmitter=naker; break; case Event.SWITCH_ACK: transmitter=acker; break; } return true; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy