View Javadoc

1   /*
2    * Copyright (c) 1998-2002 The Jgroup Team.
3    *
4    * This program is free software; you can redistribute it and/or modify
5    * it under the terms of the GNU Lesser General Public License version 2 as
6    * published by the Free Software Foundation.
7    *
8    * This program is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   * GNU Lesser General Public License for more details.
12   *
13   * You should have received a copy of the GNU Lesser General Public License
14   * along with this program; if not, write to the Free Software
15   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16   *
17   */
18  
19  package jgroup.relacs.mss;
20  
21  import java.io.IOException;
22  
23  import jgroup.core.EndPoint;
24  import jgroup.relacs.types.EndPointImpl;
25  import jgroup.relacs.types.MessageId;
26  import jgroup.util.InMessage;
27  import jgroup.util.MsgFactory;
28  import jgroup.util.OutMessage;
29  
30  /**
31   *  The <code>MsgNACK</code> class is used to indicate that a message
32   *  has been lost and must be resent.
33   *
34   *  Note that this message is currently queued in the Mss, enabling
35   *  rescheduling of the NACK message.  This prevents us from using a
36   *  single message instance for all NACKs.
37   *
38   *  @author Hein Meling
39   *  @since Jgroup 1.2
40   */
41  final class MsgNACK
42    implements Msg, MssConstants, MssTag
43  {
44  
45    ////////////////////////////////////////////////////////////////////////////////////////////
46    // Size
47    ////////////////////////////////////////////////////////////////////////////////////////////
48  
49    /** Message size (1+4+6) bytes */
50    private static final int MSG_SIZE = 11;
51  
52  
53    ////////////////////////////////////////////////////////////////////////////////////////////
54    // Message Fields (static part)
55    ////////////////////////////////////////////////////////////////////////////////////////////
56  
57    /* Type of NACK message (REMOTENACK, SENTNACK) */
58    private byte nackType;
59  
60    /** Message identifier for the missing message */
61    int mid;
62  
63    /** Receiver of this NACK message (source of missing message) */
64    private MssHost source;
65  
66  
67    ////////////////////////////////////////////////////////////////////////////////////////////
68    // Transient fields (recomputed during unmarshalling)
69    ////////////////////////////////////////////////////////////////////////////////////////////
70  
71    /** Message to be sent */
72    private transient OutMessage outmsg;
73  
74    /** The message sender (obtained from the fragment header) */
75    private transient MssHost sender;
76  
77    /** NACK creation time; used to recompute RTT (not used on the receiver side) */
78    private transient long start;
79  
80  
81    ////////////////////////////////////////////////////////////////////////////////////////////
82    // Marshalling and unmarshalling methods
83    ////////////////////////////////////////////////////////////////////////////////////////////
84  
85    /**
86     *  Marshal an NACK message.
87     */
88    static MsgNACK marshal(byte nackType, MssHost source, int missingMid)
89      throws IOException
90    {
91      MsgNACK msg  = new MsgNACK();
92      msg.start = System.currentTimeMillis();
93      msg.sender = HostTable.getLocalHost();
94      msg.outmsg = MsgFactory.get(MSG_SIZE);
95  
96      msg.nackType = nackType;
97      msg.mid = missingMid;
98      msg.source = source;
99  
100     msg.outmsg.writeByte(nackType);
101     MessageId.marshal(msg.outmsg, missingMid);
102     source.getEndPoint().writeExternal(msg.outmsg);
103     return msg;
104   }
105 
106 
107   /**
108    *  Unmarshal an NACK message from the given stream.
109    */
110   static MsgNACK unmarshal(InMessage in, FragmentHeader header, MssDS mssds)
111     throws IOException, ClassNotFoundException
112   {
113     MsgNACK msg  = new MsgNACK();
114     msg.sender   = header.getSender();
115     msg.nackType = in.readByte();
116     msg.mid      = MessageId.unmarshal(in);
117     EndPoint srcEndPoint = new EndPointImpl();
118     srcEndPoint.readExternal(in);
119     msg.source = mssds.hostLookup(srcEndPoint);
120     return msg;
121   }
122 
123 
124   ////////////////////////////////////////////////////////////////////////////////////////////
125   // Methods
126   ////////////////////////////////////////////////////////////////////////////////////////////
127 
128   /**
129    *  Returns the NACK message type that this message represents.  There
130    *  are two possible values: REMOTENACK and SENTNACK.
131    */
132   byte getNACKType()
133   {
134     return nackType;
135   }
136 
137 
138   /**
139    *  Returns true if this NACK message is a REMOTENACK; false is
140    *  returned if it is a SENTNACK.
141    */
142   boolean isRemoteNACK()
143   {
144     return (nackType == REMOTENACK);
145   }
146 
147 
148   /**
149    *  Returns the source of the missing message; the source is equal to
150    *  the receiver of this NACK message.
151    */
152   MssHost getSource()
153   {
154     return source;
155   }
156 
157 
158   /**
159    * Returns the round trip time for this NACK message.  Used on the
160    * sender side to recompute the adaptive timeouts.
161    */
162   int getRTT()
163   {
164     return (int) (System.currentTimeMillis() - start);
165   }
166 
167 
168   /**
169    *  Returns the sender cluster of this message.
170    */
171   Cluster getCluster()
172   {
173     return sender.getCluster();
174   }
175 
176 
177   /**
178    *  Returns true if the sender of this message is the local host.
179    */
180   boolean isLocal()
181   {
182     return sender.isLocal();
183   }
184 
185 
186   ////////////////////////////////////////////////////////////////////////////////////////////
187   // Fragmentation handling (from Msg interface)
188   ////////////////////////////////////////////////////////////////////////////////////////////
189 
190   /*
191    * The fragmentation iterator instance for this message; it can be
192    * reused for multiple iterations over this message.
193    */
194   private transient MsgFragmentIterator fragIter = null;
195 
196 
197   /**
198    *  Returns a <code>FragmentIterator</code> for this
199    *  <code>MsgNACK</code> object.  This iterator allows to send the
200    *  entire message as multiple fragments of specified size (payload).
201    *  At the same time, it marks each fragment with a tag and message
202    *  identifier provided through the <code>next()</code> method of the
203    *  iterator.
204    */
205   public FragmentIterator iterator(MsgCntrl msgCntrl)
206   {
207     /* If there is already an iterator for this message, we reuse it. */
208     if (fragIter == null) 
209       fragIter = new MsgFragmentIterator(this, msgCntrl);
210     else 
211       fragIter.reset(outmsg);
212     return fragIter;
213   }
214 
215 
216 
217   ////////////////////////////////////////////////////////////////////////////////////////////
218   // Msg interface methods
219   ////////////////////////////////////////////////////////////////////////////////////////////
220 
221   /**
222    *  Returns the tag associated with this message.
223    */
224   public byte getTag() 
225   {
226     return NACK;
227   }
228 
229 
230   /**
231    *  Returns the message identifier for this message.
232    */
233   public int getMid()
234   {
235     return mid;
236   }
237 
238 
239   /**
240    *  Returns the sender of this message.
241    */
242   public MssHost getSender()
243   {
244     return sender;
245   }
246 
247 
248   /**
249    *  Returns false always, since NACK messages should never be routed.
250    */
251   public boolean hasToBeRouted()
252   {
253     return false;
254   }
255 
256 
257   /**
258    *  Returns the message flow controller for the sender side.
259    */
260   public MsgFlowSndrSide getMsgFlow()
261   {
262     return sender.getCluster().getMsgFlow();
263   }
264 
265 
266   /**
267    *  Returns the <code>OutMessage</code> associated with this message.
268    */
269   public OutMessage getOutMessage()
270   {
271     return outmsg;
272   }
273 
274 
275   ////////////////////////////////////////////////////////////////////////////////////////////
276   // Methods from Object
277   ////////////////////////////////////////////////////////////////////////////////////////////
278 
279   /**
280    *  Returns a string representation of this object
281    */
282   public String toString()
283   {
284     StringBuilder buf = new StringBuilder();
285     switch (nackType) {
286     case REMOTENACK:
287       buf.append("REMOTENACK");
288       break;
289 
290     case SENTNACK:
291       buf.append("SENTNACK");
292       break;
293 
294     default:
295       buf.append("Illegal NACK type: " + nackType);
296     }
297     buf.append(", missingMid=");
298     buf.append(mid);
299     buf.append(", source=");
300     buf.append(source);
301     if (sender != null) {
302       buf.append(", sender=");
303       buf.append(sender);
304     }
305     return buf.toString();
306   }
307 
308 } // END MsgNACK