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