View Javadoc

1   /*
2    * Copyright (c) 1998-2004 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.arm;
20  
21  import java.io.IOException;
22  import java.io.ObjectInput;
23  import java.io.ObjectOutput;
24  import java.util.HashMap;
25  import java.util.Map;
26  import java.util.Timer;
27  import java.util.TimerTask;
28  
29  import jgroup.core.arm.ARMEvent;
30  import jgroup.core.arm.DistributionScheme;
31  import jgroup.relacs.config.AppConfig;
32  import jgroup.relacs.types.ViewImpl;
33  
34  import org.apache.log4j.Logger;
35  
36  /**
37   * @author Hein Meling
38   * @since Jgroup 2.1
39   */
40  public class ReplicaPingEvent
41    implements ARMEvent
42  {
43  
44    private static final long serialVersionUID = -6041617835370010146L;
45  
46    ////////////////////////////////////////////////////////////////////////////////////////////
47    // Logger
48    ////////////////////////////////////////////////////////////////////////////////////////////
49  
50    /** Obtain logger for this class */
51    private static final Logger log = Logger.getLogger(ReplicaPingEvent.class);
52  
53  
54    ////////////////////////////////////////////////////////////////////////////////////////////
55    // Constants
56    ////////////////////////////////////////////////////////////////////////////////////////////
57  
58    /** The smallest allowed ping rate */
59    private static final int MIN_PING_RATE     = 1000;
60  
61    /** The default ping period for lease renewal */
62    private static final int DEFAULT_PING_RATE = 2000;
63  
64  
65    ////////////////////////////////////////////////////////////////////////////////////////////
66    // Fields
67    ////////////////////////////////////////////////////////////////////////////////////////////
68  
69    /** The group identifier for issuer of this ping event */
70    private int gid;
71  
72    /** The period to wait before alarming ARM */
73    private int suspectPeriod;
74  
75  
76    ////////////////////////////////////////////////////////////////////////////////////////////
77    // Static and transient fields
78    ////////////////////////////////////////////////////////////////////////////////////////////
79  
80    /** Map of renew timers (groupid -> renew timer for group) */
81    private static transient final Map<Integer,Timer> renewTimers =
82      new HashMap<Integer,Timer>(5);
83  
84    /** Access point to the replication manager for external events */
85    private transient DistributionScheme distScheme;
86  
87    /**
88     * The actual ping rate associated with this PingEvent object.
89     * This is the period between each renewal invocations performed
90     * by the <code>RecoveryLayer</code>.
91     *
92     * Note that since this field is transient, it will not be accessible
93     * to JVMs creating this object using the no-argument constructor.
94     * (deserialization).
95     */
96    private transient int pingRate;
97  
98  
99    ////////////////////////////////////////////////////////////////////////////////////////////
100   // Constructors
101   ////////////////////////////////////////////////////////////////////////////////////////////
102 
103   /**
104    * Default constructor for externalization
105    */
106   public ReplicaPingEvent() { }
107 
108   /**
109    * Private constructor to prevent external construction.
110    *
111    * @param gid
112    * @param pingRate
113    */
114   private ReplicaPingEvent(int gid, int pingRate)
115   {
116     this.gid = gid;
117     this.pingRate = pingRate;
118     if (pingRate < MIN_PING_RATE)
119       throw new IllegalArgumentException("Ping rate must be greater than " + MIN_PING_RATE);
120     suspectPeriod = 2*pingRate;
121   }
122 
123   /**
124    * @param gid the group identifier of the group renewing its lease
125    * @param groupSize the current size of the group
126    */
127   public static ReplicaPingEvent getNewPingEvent(int gid, int groupSize)
128   {
129     AppConfig app = AppConfig.getApplication(gid);
130     boolean groupFailureSupport = app.getBooleanParam("Recovery.GroupFailureSupport");
131     if (groupFailureSupport) {
132       int basePingRate = app.getIntParam("Recovery.RenewalRate", DEFAULT_PING_RATE);
133       int pingRate = (int) (Math.pow(basePingRate/1000, groupSize)*1000);
134       return new ReplicaPingEvent(gid, pingRate);
135     } else {
136       return null;
137     }
138   }
139 
140   ////////////////////////////////////////////////////////////////////////////////////////////
141   // Access methods
142   ////////////////////////////////////////////////////////////////////////////////////////////
143 
144   /**
145    * Get the ping rate associated with this object. <p>
146    * 
147    * Note that this can only be called on the object created by
148    * the argument constructor, since the <code>pingRate</code> field
149    * is not serialized.
150    */
151   public int getPingRate()
152   {
153     return pingRate;
154   }
155 
156 
157   ////////////////////////////////////////////////////////////////////////////////////////////
158   // ARMEvent interface methods
159   ////////////////////////////////////////////////////////////////////////////////////////////
160 
161   /* (non-Javadoc)
162    * @see jgroup.core.arm.ARMEvent#handle()
163    */
164   public void handle(DistributionScheme distScheme)
165   {
166     this.distScheme = distScheme;
167     synchronized (renewTimers) {
168       Timer renewTimer = (Timer) renewTimers.get(gid);
169       if (renewTimer != null) {
170         renewTimer.cancel();
171       }
172       renewTimer = new Timer("RenewTimer-" + gid, true);
173       renewTimers.put(gid, renewTimer);
174       if (log.isDebugEnabled()) {
175         log.debug("Lease expires @ " + (System.currentTimeMillis() + suspectPeriod)
176             + ", group: " + gid);
177       }
178       renewTimer.schedule(new RenewTask(), suspectPeriod);
179     }
180   }
181 
182 
183   /* (non-Javadoc)
184    * @see jgroup.core.arm.ARMEvent#getGroupId()
185    */
186   public int getGroupId()
187   {
188     return gid;
189   }
190 
191 
192   /* (non-Javadoc)
193    * @see jgroup.core.arm.ARMEvent#getObject()
194    */
195   public Object getObject()
196   {
197     // Currently we ignore these events.
198     return null;
199   }
200 
201 
202   /**
203    * This timer task is run only when a renewal does not occur.
204    */
205   private class RenewTask
206     extends TimerTask
207   {
208 
209     /* (non-Javadoc)
210      * @see java.util.TimerTask#run()
211      */
212     public void run()
213     {
214       if (log.isDebugEnabled())
215         log.debug("Lease expired @ " + System.currentTimeMillis());
216       synchronized (renewTimers) {
217         renewTimers.remove(gid);
218       }
219       distScheme.viewChangeEvent(new ViewImpl(gid));
220     }
221 
222   } // END RenewTask
223 
224 
225   public String toString()
226   {
227     return "ReplicaPingEvent: gid=" + gid + ", suspect_period=" + suspectPeriod;
228   }
229 
230 
231   ////////////////////////////////////////////////////////////////////////////////////////////
232   // Methods from the Externalizable interface (as required by the ARMEvent interface)
233   ////////////////////////////////////////////////////////////////////////////////////////////
234 
235   /* (non-Javadoc)
236    * @see java.io.Externalizable#readExternal(java.io.ObjectInput)
237    */
238   public void readExternal(ObjectInput in)
239     throws IOException, ClassNotFoundException
240   {
241     gid = in.readInt();
242     suspectPeriod = in.readInt();
243   }
244 
245   /* (non-Javadoc)
246    * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
247    */
248   public void writeExternal(ObjectOutput out)
249     throws IOException
250   {
251     out.writeInt(gid);
252     out.writeInt(suspectPeriod);
253   }
254 
255 } // END ReplicaPingEvent