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.daemon;
20
21 import java.util.HashSet;
22 import java.util.Set;
23 import java.util.Timer;
24 import java.util.TimerTask;
25
26 import jgroup.core.ConfigManager;
27 import jgroup.core.MemberId;
28 import jgroup.relacs.config.TransportConfig;
29 import jgroup.relacs.gm.PingListener;
30 import jgroup.relacs.gm.RemoteDispatcher;
31 import jgroup.relacs.mss.MssUser;
32
33 import org.apache.log4j.Logger;
34
35
36 /**
37 * The <code>MemberData</code> class is a data structure containing
38 * information about a member on a per-group basis. In particular,
39 * the current status of the member with respect to group membership
40 * is stored in this data structure.
41 *
42 * @author Alberto Montresor
43 * @since Jgroup 0.1
44 */
45 final class MemberData
46 {
47
48 ////////////////////////////////////////////////////////////////////////////////////////////
49 // Logger
50 ////////////////////////////////////////////////////////////////////////////////////////////
51
52 /** Obtain logger for this class */
53 private static final Logger log = Logger.getLogger(MemberData.class);
54
55
56 ////////////////////////////////////////////////////////////////////////////////////////////
57 // Constants
58 ////////////////////////////////////////////////////////////////////////////////////////////
59
60 /**
61 * Members having this status have joined the group and there neither
62 * crashed nor leaving the group
63 */
64 private static final int S_OK = 1;
65
66 /**
67 * Members having this status have requested to leave the group.
68 * They are in the process of being removed.
69 */
70 private static final int S_LEAVING = 2;
71
72 /**
73 * Members having this status have crashed; are in the process of
74 * of being removed
75 */
76 private static final int S_CRASHED = 3;
77
78 /**
79 * String representation of member status.
80 */
81 private static final String S_STAT[] = {
82 "INVALID_STATUS", "OK", "LEAVING", "CRASHED"
83 };
84
85
86 ////////////////////////////////////////////////////////////////////////////////////////////
87 // Fields
88 ////////////////////////////////////////////////////////////////////////////////////////////
89
90 /** Identifier */
91 private MemberId memberId;
92
93 /** Reference to the dispatcher service of this member */
94 private RemoteDispatcher dispatcher;
95
96 /** Current status of the member */
97 private int status;
98
99 /** Indicates if the member has acknowledged the most recent PrepareEvent */
100 private boolean prepared;
101
102 /** The set of acks that the daemon is awaiting from this member. */
103 private Set<Integer> acks = new HashSet<Integer>(5);
104
105 // Local Member Ping Management
106
107 /** Ping rate; how often local members are ping'ed */
108 private int pingRate;
109
110 /** The ping timer object associated with this member */
111 private Timer pingTimer;
112
113
114 ////////////////////////////////////////////////////////////////////////////////////////////
115 // Constructors
116 ////////////////////////////////////////////////////////////////////////////////////////////
117
118 /**
119 * Creates a new <CODE>MemberData</CODE> object associated a member
120 * identifier to a remote dispatcher and a ping listener.<p>
121 *
122 * @param id the identifier of the member associated to this
123 * data structure
124 * @param dispatcher the dispatcher of the member
125 */
126 MemberData(MemberId id, RemoteDispatcher dispatcher)
127 {
128 this.memberId = id;
129 this.dispatcher = dispatcher;
130 this.status = S_OK;
131 this.prepared = false;
132 TransportConfig tconf =
133 (TransportConfig) ConfigManager.getConfig(TransportConfig.class);
134 pingRate = tconf.getLocalPingRate();
135 }
136
137
138 ////////////////////////////////////////////////////////////////////////////////////////////
139 // Methods
140 ////////////////////////////////////////////////////////////////////////////////////////////
141
142 /**
143 * Returns the member identifier associated to this member.
144 */
145 MemberId getMemberId()
146 {
147 return memberId;
148 }
149
150
151 /**
152 * Returns true if this member is leaving the group.
153 */
154 boolean isLeaving()
155 {
156 return status == S_LEAVING;
157 }
158
159 /**
160 * Returns true if this member has crashed and left the group.
161 */
162 boolean isCrashed()
163 {
164 return status == S_CRASHED;
165 }
166
167 /**
168 * Returns true if this member has acknowledged the PrepareEvent.
169 */
170 boolean isPrepared()
171 {
172 return prepared;
173 }
174
175 /**
176 * Set this member to the leaving status.
177 */
178 void setLeaving()
179 {
180 this.status = S_LEAVING;
181 }
182
183 /**
184 * Set the leaving status of this member.
185 *
186 * @param status the new status of the member
187 */
188 void setCrashed()
189 {
190 if (log.isDebugEnabled())
191 log.debug("Marking " + memberId + " as CRASHED");
192 this.status = S_CRASHED;
193 }
194
195 /**
196 * Set the prepared status to true for this member.
197 */
198 void setPrepared()
199 {
200 prepared = true;
201 }
202
203 /**
204 * Set the prepared status to false for this member.
205 */
206 void resetPrepared()
207 {
208 prepared = false;
209 }
210
211 /**
212 * Returns a reference to the remote dispatcher that deals with events
213 * associated to this member. The remote dispatcher can be actually
214 * remote, if the member is in a JVM different from the local one;
215 * or can be in the local JVM.
216 */
217 RemoteDispatcher getRemoteDispatcher()
218 {
219 return dispatcher;
220 }
221
222 /**
223 * Returns true if the daemon is awaiting one or more ACKs from the member.
224 */
225 boolean hasOutstandingAcks()
226 {
227 return (acks.size() != 0);
228 }
229
230 /**
231 * Returns true if the daemon is awaiting for the given ACK for this member.
232 */
233 boolean awaitingAck(int mid)
234 {
235 return acks.contains(mid);
236 }
237
238 /**
239 * The daemon is awaiting an ACK for the given message from this member.
240 */
241 void setAck(int mid)
242 {
243 acks.add(mid);
244 }
245
246 /**
247 * The daemon is no longer awaiting an ACK for the given message from this member.
248 */
249 void removeAck(int mid)
250 {
251 acks.remove(mid);
252 }
253
254
255 ////////////////////////////////////////////////////////////////////////////////////////////
256 // Methods for object polling
257 ////////////////////////////////////////////////////////////////////////////////////////////
258
259 /**
260 * Schedule ping timer to ping the dispatcher object periodically.
261 *
262 * @param mssuser the daemon object assoicated with this member;
263 * to be notified if this member is suspected to have failed.
264 */
265 public void schedulePingTimer(final MssUser mssuser)
266 {
267 if (pingTimer != null) {
268 /*
269 * Ignored; it can be caused by the same member
270 * joining more than one group.
271 */
272 if (log.isDebugEnabled())
273 log.debug("Ping timer already scheduled for: " + memberId);
274 return;
275 }
276 TimerTask pingTT = new TimerTask() {
277 public void run() {
278 try {
279 /* Performs pinging */
280 if (log.isDebugEnabled())
281 log.debug("Pinging local member: " + memberId);
282 synchronized (dispatcher) {
283 ((PingListener) dispatcher).ping();
284 }
285 if (log.isDebugEnabled())
286 log.debug("Ping local member completed: " + memberId);
287 } catch (Exception e) {
288 mssuser.localSuspect(memberId);
289 cancelPingTimer();
290 log.warn("Mss unable to connect to replica", e);
291 }
292 }
293 };
294 pingTimer = new Timer("PingTimer-" + memberId.getLocalId(), true);
295 pingTimer.schedule(pingTT, pingRate, pingRate);
296 if (log.isDebugEnabled())
297 log.debug("Ping timer scheduled for: " + memberId);
298 }
299
300 /**
301 * Cancel ping timer for this member.
302 */
303 public void cancelPingTimer()
304 {
305 if (pingTimer != null) {
306 pingTimer.cancel();
307 if (log.isDebugEnabled())
308 log.debug("Ping timer canceled: " + memberId);
309 }
310 }
311
312
313 ////////////////////////////////////////////////////////////////////////////////////////////
314 // Methods from Object
315 ////////////////////////////////////////////////////////////////////////////////////////////
316
317 /**
318 * Returns a string representation of this object.
319 */
320 public String toString()
321 {
322 StringBuilder buf = new StringBuilder();
323 buf.append("[MemberData: ");
324 buf.append(memberId);
325 buf.append(", ");
326 buf.append(S_STAT[status]);
327 if (hasOutstandingAcks()) {
328 buf.append(", outstanding=");
329 buf.append(acks);
330 }
331 buf.append("]");
332 return buf.toString();
333 }
334
335 } // END MemberData