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.relacs.types.GroupIndex;
24 import jgroup.util.InMessage;
25 import jgroup.util.MsgFactory;
26 import jgroup.util.OutMessage;
27
28 import org.apache.log4j.Logger;
29
30 /**
31 * The <code>MsgIamAlive</code> class
32 *
33 * @author Hein Meling
34 * @since Jgroup 1.2
35 */
36 final class MsgIamAlive
37 implements Msg, MssConstants, MssTag
38 {
39
40 ////////////////////////////////////////////////////////////////////////////////////////////
41 // Logger
42 ////////////////////////////////////////////////////////////////////////////////////////////
43
44 /** Obtain logger for this class */
45 private static Logger log = Logger.getLogger(MsgIamAlive.class);
46
47
48 ////////////////////////////////////////////////////////////////////////////////////////////
49 // Unique message instance
50 ////////////////////////////////////////////////////////////////////////////////////////////
51
52 /**
53 * As this message is never stored in a queue, a single message
54 * instance is sufficient. This allows us to save the cost of
55 * allocating and garbage collecting messages.
56 */
57 private static final MsgIamAlive msg = new MsgIamAlive();
58
59
60 ////////////////////////////////////////////////////////////////////////////////////////////
61 // Message Fields (dynamic part)
62 ////////////////////////////////////////////////////////////////////////////////////////////
63
64 /** Array of flow control entries */
65 private FCEntry[] fc;
66
67
68 ////////////////////////////////////////////////////////////////////////////////////////////
69 // Transient fields (recomputed during unmarshalling)
70 ////////////////////////////////////////////////////////////////////////////////////////////
71
72 /** Message to be sent */
73 private transient OutMessage outmsg;
74
75 /** Message received from the Mss */
76 private transient InMessage inmsg;
77
78 /** The index of the flow control entry associated with the local host */
79 private transient int localFCIndex = UNDEF;
80
81 /** The local host (where this message resides; sender or receiver) */
82 private transient MssHost localHost;
83
84 /** The message sender (obtained from the fragment header) */
85 private transient MssHost sender;
86
87 /** The incarnation identifier for the sender (obtained from the fragment header) */
88 private transient int incarnationId;
89
90
91 ////////////////////////////////////////////////////////////////////////////////////////////
92 // Marshalling and unmarshalling methods
93 ////////////////////////////////////////////////////////////////////////////////////////////
94
95 /**
96 * Marshal an IAMALIVE message.
97 */
98 static MsgIamAlive marshal(FCEntry[] fc)
99 throws IOException
100 {
101 msg.fc = fc;
102 msg.sender = HostTable.getLocalHost();
103
104 /*
105 * Here we check if this <code>MsgIamAlive</code> object has already
106 * been initialized with an outmsg object, in which case we simply
107 * clear the message object and reuse it. This avoids to create a
108 * new outmsg object (allocating additional memory) and there is no
109 * need to garbage collect the old one.
110 *
111 * Note that all <code>MsgIamAlive</code> messages are of the same
112 * size, including the flow control data of all hosts.
113 */
114 int size = GroupIndex.SIZE + fc.length*FCEntry.SIZE;
115 if (msg.outmsg == null) {
116 msg.outmsg = MsgFactory.get(size);
117 }
118 if (log.isDebugEnabled()) {
119 log.debug("MsgIamAlive.size=" + size);
120 }
121 msg.outmsg.clear(size);
122
123 GroupIndex.marshal(msg.outmsg, fc.length);
124 for (int i = 0; i < fc.length; i++)
125 fc[i].writeExternal(msg.outmsg);
126 return msg;
127 }
128
129
130 /**
131 * Unmarshal an IAMALIVE message from the given stream.
132 */
133 static MsgIamAlive unmarshal(InMessage inmsg, FragmentHeader header)
134 throws IOException, ClassNotFoundException
135 {
136 msg.inmsg = inmsg;
137 msg.localHost = HostTable.getLocalHost();
138 msg.sender = header.getSender();
139 msg.incarnationId = header.getIncarnationId();
140
141 int len = GroupIndex.unmarshal(inmsg);
142 msg.fc = new FCEntry[len];
143 for (int i = 0; i < len; i++) {
144 msg.fc[i] = new FCEntry();
145 msg.fc[i].readExternal(inmsg);
146 if (msg.localFCIndex == UNDEF && msg.fc[i].key.isLocal())
147 msg.localFCIndex = i;
148 }
149 return msg;
150 }
151
152
153 ////////////////////////////////////////////////////////////////////////////////////////////
154 // MsgIamAlive specific methods (receiver side only)
155 ////////////////////////////////////////////////////////////////////////////////////////////
156
157 /**
158 * Update the flow control data on the receiver side.
159 */
160 void updateFC(MssDS mssds)
161 {
162 if (sender.isLocal()) {
163
164 localHost.flush();
165
166 } else {
167
168 for (int i = 0; i < fc.length; i++) {
169 MssHost host = mssds.hostLookup(fc[i].key);
170 if (host == null) {
171 log.error("Unavailable host: " + fc[i].key);
172 continue;
173 }
174 if (log.isDebugEnabled()) {
175 log.debug("host=" + host + ", lastMsgRcvd=" + fc[i].lastMsgRcvd
176 + ", cindex=" + sender.getClusterIndex());
177 }
178 host.getMsgFlow().clusterWindow.set(sender.getClusterIndex(), fc[i].lastMsgRcvd);
179 }
180
181 }
182 }
183
184
185 /**
186 * Returns incarnation identifier for the sender of this message.
187 */
188 public int getIncarnationId()
189 {
190 return incarnationId;
191 }
192
193
194 ////////////////////////////////////////////////////////////////////////////////////////////
195 // Fragmentation handling (from Msg interface)
196 ////////////////////////////////////////////////////////////////////////////////////////////
197
198 /*
199 * The fragmentation iterator instance for this message; it can be
200 * reused for multiple iterations over this message.
201 */
202 private transient MsgFragmentIterator fragIter = null;
203
204
205 /**
206 * Returns a <code>FragmentIterator</code> for this
207 * <code>MsgIamAlive</code> object. This iterator allows to send the
208 * entire message as multiple fragments of specified size (payload).
209 * At the same time, it marks each fragment with a tag and message
210 * identifier provided through the <code>next()</code> method of the
211 * iterator.
212 *
213 * If there is already an iterator for this message, we reuse it.
214 */
215 public FragmentIterator iterator(MsgCntrl msgCntrl)
216 {
217 if (fragIter == null)
218 fragIter = new MsgFragmentIterator(this, msgCntrl);
219 else
220 fragIter.reset(outmsg);
221 return fragIter;
222 }
223
224
225 ////////////////////////////////////////////////////////////////////////////////////////////
226 // Msg interface methods
227 ////////////////////////////////////////////////////////////////////////////////////////////
228
229 /**
230 * Returns the tag associated with this message.
231 */
232 public byte getTag()
233 {
234 return IAMALIVE;
235 }
236
237
238 /**
239 * Returns the message identifier for this message; all IAMALIVE
240 * messages have <code>UNDEF</code> as their message identifier.
241 */
242 public int getMid()
243 {
244 return UNDEF;
245 }
246
247
248 /**
249 * Returns the sender of this message.
250 */
251 public MssHost getSender()
252 {
253 return sender;
254 }
255
256
257 /**
258 * Returns false always, since topology messages should never be routed.
259 */
260 public boolean hasToBeRouted()
261 {
262 return false;
263 }
264
265
266 /**
267 * Returns true if the sender of this message is the local host.
268 */
269 boolean isLocal()
270 {
271 return sender.isLocal();
272 }
273
274
275 /**
276 * Returns the message flow controller for the sender side.
277 */
278 public MsgFlowSndrSide getMsgFlow()
279 {
280 return sender.getCluster().getMsgFlow();
281 }
282
283
284 /**
285 * Returns the <code>OutMessage</code> associated with this message.
286 */
287 public OutMessage getOutMessage()
288 {
289 return outmsg;
290 }
291
292
293 ////////////////////////////////////////////////////////////////////////////////////////////
294 // Methods from Object
295 ////////////////////////////////////////////////////////////////////////////////////////////
296
297 /**
298 * Returns a string representation of this object
299 */
300 public String toString()
301 {
302 StringBuilder buf = new StringBuilder();
303 buf.append("IAMALIVE, ");
304 for (int i=0; i < fc.length; i++)
305 buf.append(fc[i]);
306 return buf.toString();
307 }
308
309 } // END MsgIamAlive