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