View Javadoc

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