ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/server/uk/org/iscream/cms/server/client/monitors/Heartbeat__Monitor.java
Revision: 1.19
Committed: Mon Mar 26 18:07:11 2001 UTC (23 years, 2 months ago) by tdb
Branch: MAIN
CVS Tags: PROJECT_COMPLETION
Changes since 1.18: +8 -8 lines
Log Message:
The "checking" part had moved from the main class to an inner class, thus the
synchronize(this) blocks were pointing at different "this"'s. This how now been
fixed, we hope.

File Contents

# Content
1 //---PACKAGE DECLARATION---
2 package uk.org.iscream.client.monitors;
3
4 //---IMPORTS---
5 import java.util.HashMap;
6 import java.util.Iterator;
7 import uk.org.iscream.client.*;
8 import uk.org.iscream.core.*;
9 import uk.org.iscream.util.*;
10 import uk.org.iscream.componentmanager.*;
11
12 /**
13 * This Monitor watches heartbeats.
14 * It generates an alert when a heartbeat that is expected
15 * does not arrive. Unlike all the other monitors, this one
16 * is driven by an event *not* occuring, rather than an
17 * event occuring. This means it must be actively checking
18 * for missing heartbeat's, and thus has an extra inner class
19 * thread.
20 *
21 * @author $Author: tdb1 $
22 * @version $Id: Heartbeat__Monitor.java,v 1.18 2001/03/23 02:32:49 tdb1 Exp $
23 */
24 public class Heartbeat__Monitor extends MonitorSkeleton {
25
26 //---FINAL ATTRIBUTES---
27
28 /**
29 * The current CVS revision of this class
30 */
31 public final String REVISION = "$Revision: 1.18 $";
32
33 /**
34 * A description of this monitor
35 */
36 public final String DESC = "Monitors Heartbeats.";
37
38 /**
39 * The default (used if not configured) period at
40 * which to check for old heartbeats. (in seconds)
41 */
42 public final int DEFAULT_CHECK_PERIOD = 60;
43
44 //---STATIC METHODS---
45
46 //---CONSTRUCTORS---
47
48 /**
49 * Constructs a new Heartbeat monitor, and starts off
50 * the worker thread.
51 */
52 public Heartbeat__Monitor() {
53 super();
54 new HeartbeatWorker().start();
55 }
56
57 //---PUBLIC METHODS---
58
59 /**
60 * Analyse a packet of data. In this case, this will just
61 * register the fact that a heartbeat has arrived.
62 *
63 * @param packet The packet of data to analyse
64 */
65 public void analysePacket(XMLPacket packet) {
66 String source = packet.getParam("packet.attributes.machine_name");
67 if (!_hosts.containsKey(source)) {
68 synchronized(this) {
69 _hosts.put(source, new HeartbeatHolder(new Register(source, _name)));
70 }
71 }
72 HeartbeatHolder lastHeartbeat = (HeartbeatHolder) _hosts.get(source);
73 lastHeartbeat.setLastHeartbeat(System.currentTimeMillis()/1000);
74 }
75
76 /**
77 * Overrides the {@link java.lang.Object#toString() Object.toString()}
78 * method to provide clean logging (every class should have this).
79 *
80 * This uses the uk.org.iscream.util.NameFormat class
81 * to format the toString()
82 *
83 * @return the name of this class and its CVS revision
84 */
85 public String toString() {
86 return FormatName.getName(
87 _name,
88 getClass().getName(),
89 REVISION);
90 }
91
92 /**
93 * return the String representation of what the monitor does
94 */
95 public String getDescription(){
96 return DESC;
97 }
98
99 //---PRIVATE METHODS---
100
101 /**
102 * Checks whether the time since the last heartbeat
103 * is beyond the threshold(s).
104 *
105 * @param timeSinceLastHB a long time since the last heartbeat arrived
106 * @param reg the Register for this host
107 * @return the level which has been breached, if any
108 */
109 private int checkAttributeThreshold(long timeSinceLastHB, Register reg) {
110 for(int thresholdLevel = Alert.thresholdLevels.length - 1; thresholdLevel >= 0; thresholdLevel--) {
111 if (reg.getThreshold(thresholdLevel) != -1.0) {
112 if (((long) reg.getThreshold(thresholdLevel)) < timeSinceLastHB) {
113 return thresholdLevel;
114 }
115 }
116 }
117 return Alert.thresholdNORMAL;
118 }
119
120 //---ACCESSOR/MUTATOR METHODS---
121
122 /**
123 * Returns a reference to the Queue we're getting data
124 * from. This is specific to this monitor.
125 *
126 * @return a reference to a Queue to get data from
127 */
128 protected Queue getQueue() {
129 return MonitorManager.getInstance().getHeartbeatQueue();
130 }
131
132 //---ATTRIBUTES---
133
134 /**
135 * This is the friendly identifier of the
136 * component this class is running in.
137 * eg, a Filter may be called "filter1",
138 * If this class does not have an owning
139 * component, a name from the configuration
140 * can be placed here. This name could also
141 * be changed to null for utility classes.
142 */
143 private String _name = "Heartbeat";
144
145 /**
146 * A reference to the configuration proxy in use
147 */
148 private ConfigurationProxy _cp = ConfigurationProxy.getInstance();
149
150 /**
151 * A HashMap of hosts, with associated HeartbeatHolder's.
152 */
153 private HashMap _hosts = new HashMap();
154
155 /**
156 * A reference to the system logger.
157 */
158 private Logger _logger = ReferenceManager.getInstance().getLogger();
159
160 //---STATIC ATTRIBUTES---
161
162 //---INNER CLASSES---
163
164 /**
165 * This inner class simply holding some information
166 * about a specific host.
167 */
168 private class HeartbeatHolder {
169
170 /**
171 * Construct a new HeartbeatHolder.
172 */
173 public HeartbeatHolder(Register register) {
174 _register = register;
175 }
176
177 /**
178 * Set the time of the last heartbeat
179 */
180 public void setLastHeartbeat(long lastHeartbeat) {
181 _lastHeartbeat = lastHeartbeat;
182 }
183
184 /**
185 * Get the time of the last heartbeat
186 */
187 public long getLastHeartbeat() {
188 return _lastHeartbeat;
189 }
190
191 /**
192 * Get the Register
193 */
194 public Register getRegister() {
195 return _register;
196 }
197
198 /**
199 * last heartbeat time
200 */
201 private long _lastHeartbeat;
202
203 /**
204 * register ref
205 */
206 private Register _register;
207 }
208
209 /**
210 * This worker thread just checks all the hosts and then
211 * waits a period of time before doing it again. It sends
212 * Alerts as required.
213 */
214 private class HeartbeatWorker extends Thread {
215
216 /**
217 * The main run method of this worker thread. It simply
218 * checks through all the hosts it has stored, running
219 * the analyseHB method on each. It then removes any
220 * that have passed a FINAL, and waits a (configured)
221 * length of time before doing it again.
222 */
223 public void run() {
224 ConfigurationProxy cp = ConfigurationProxy.getInstance();
225 while(true) {
226 // this cycle period of this monitor's checks
227 int checkPeriod = 0;
228 try {
229 checkPeriod = Integer.parseInt(cp.getProperty(_name, "Monitor.Heartbeat.checkPeriod"));
230 } catch (PropertyNotFoundException e) {
231 checkPeriod = DEFAULT_CHECK_PERIOD;
232 _logger.write(Heartbeat__Monitor.this.toString(), Logger.WARNING, "Monitor.Heartbeat.checkPeriod value unavailable using default of " + checkPeriod + " seconds");
233 } catch (NumberFormatException e) {
234 checkPeriod = DEFAULT_CHECK_PERIOD;
235 _logger.write(Heartbeat__Monitor.this.toString(), Logger.WARNING, "Erronous Monitor.Heartbeat.checkPeriod value in configuration using default of " + checkPeriod + " seconds");
236 }
237
238 synchronized(Heartbeat__Monitor.this) {
239 // perform the checks (use HB hash, although they *should* be the same)
240 Iterator i = _hosts.keySet().iterator();
241 while(i.hasNext()) {
242 // get host
243 String source = (String) i.next();
244 // check it
245 boolean remove = analyseHB(source);
246 // remove it if it's passed a FINAL
247 if(remove) {
248 i.remove();
249 }
250 }
251 }
252
253 // wait a while
254 try {Thread.sleep(checkPeriod * 1000);} catch (InterruptedException e) {}
255 }
256 }
257
258 /**
259 * Analyses a given host's state, and if need be generates
260 * a relevant Alert. Note that it also checks if the last
261 * alert sent is FINAL, in which case it returns true to
262 * indicate removal of this host.
263 *
264 * @param source the host to check
265 * @return whether this host can be deleted
266 */
267 private boolean analyseHB(String source) {
268 ConfigurationProxy cp = ConfigurationProxy.getInstance();
269 HeartbeatHolder hbHolder = (HeartbeatHolder) _hosts.get(source);
270 Register reg = hbHolder.getRegister();
271
272 // get host's HB interval (seconds)
273 // this should always exist, thus we set to 0
274 int hostHBinterval = 0;
275 try {
276 hostHBinterval = Integer.parseInt(cp.getProperty("Host."+source, "Host.TCPUpdateTime"));
277 } catch (PropertyNotFoundException e) {
278 hostHBinterval = 0;
279 _logger.write(Heartbeat__Monitor.this.toString(), Logger.WARNING, "TCPUpdateTime value unavailable using default of " + hostHBinterval + " seconds");
280 } catch (NumberFormatException e) {
281 hostHBinterval = 0;
282 _logger.write(Heartbeat__Monitor.this.toString(), Logger.WARNING, "Erronous TCPUpdateTime value in configuration using default of " + hostHBinterval + " seconds");
283 }
284
285 // get host's last HB time (seconds)
286 long lastHeartbeat = hbHolder.getLastHeartbeat();
287 // time since last heartbeat (seconds)
288 long timeSinceLastHB = (System.currentTimeMillis()/1000) - lastHeartbeat;
289 // time since (or until if negative) the expected heartbeat
290 long timeSinceExpectedHB = timeSinceLastHB - (long) hostHBinterval;
291
292 // best do a check in case the expected heartbeat is in the future
293 if(timeSinceExpectedHB < 0) {
294 timeSinceExpectedHB = 0;
295 }
296
297 // find out the threshold level we're at
298 int newThreshold = checkAttributeThreshold(timeSinceExpectedHB, reg);
299
300 // process the alert
301 Heartbeat__Monitor.this.processAlert(newThreshold, "Heartbeat", reg, source, String.valueOf(timeSinceExpectedHB));
302
303 if(reg.getLastAlertLevel() == Alert.alertFINAL) {
304 return true;
305 }
306 return false;
307 }
308 }
309 }