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