KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > management > stats > AggregateInteger


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.management.stats;
5
6 import java.io.Serializable JavaDoc;
7 import java.text.MessageFormat JavaDoc;
8
9 public final class AggregateInteger implements Serializable JavaDoc {
10
11   /**
12    * @param {0} name
13    * @param {1} n
14    * @param {2} sum
15    * @param {3} minimum
16    * @param {4} maximum
17    * @param {5} average
18    */

19   private static final String JavaDoc TO_STRING_FORMAT = "<{0}(integer): [samples/{1}], [sum/{2}], [minimum/{3}], [maximum/{4}], [average/{5}]>";
20
21   private static final class Sample {
22
23     final int sample;
24     final long timestamp;
25
26     Sample(final int sample) {
27       this.sample = sample;
28       timestamp = System.currentTimeMillis();
29     }
30
31   }
32
33   private final String JavaDoc name;
34
35   // Even though it is unnecessary to make ints volatile, we say so here to indicate that readers of these variables do
36
// not necessarily need synchronization; if they are a little behind in reading values it's ok so long as they are not
37
// corrupted (hence making them volatile), only the writers need actual synchronization
38
private volatile int n;
39   private volatile int sum;
40   private volatile int minimum;
41   private volatile int maximum;
42
43   // This used to be a variable-length linked list based on time rather than sample count, but the performance was
44
// miserable so now it's a fixed size circular buffer :(
45
private final Sample[] sampleHistory;
46   private int nextHistoryPosition;
47   private final Sample[] sampleHistorySnapshot;
48
49   /**
50    * Creates a new aggregate integer statistic without maintaining a history of samples.
51    *
52    * @param name the name of this statistic
53    */

54   public AggregateInteger(final String JavaDoc name) {
55     this(name, 0);
56   }
57
58   /**
59    * Creates a new aggregate integer statistic, maintaining a rolling history of samples for the last
60    * {@link historyLengthInSamples} samples. Sample rates are extrapolated based on how many samples are maintained.
61    */

62   public AggregateInteger(final String JavaDoc name, final int historyLengthInSamples) {
63     this.name = name;
64     sampleHistory = historyLengthInSamples > 0 ? new Sample[historyLengthInSamples] : null;
65     sampleHistorySnapshot = historyLengthInSamples > 0 ? new Sample[historyLengthInSamples] : null;
66     nextHistoryPosition = 0;
67     reset();
68   }
69
70   public synchronized void addSample(final int sample) {
71     if (sample < minimum) minimum = sample;
72     if (sample > maximum) maximum = sample;
73     ++n;
74     sum += sample;
75     // If we are keeping track of history, add our sample to the tail of the list and trim the front so it's within our
76
// timing boundary
77
if (sampleHistory != null) {
78       sampleHistory[nextHistoryPosition++] = new Sample(sample);
79       nextHistoryPosition %= sampleHistory.length;
80     }
81   }
82
83   /**
84    * Resets this statistic, all counters/averages/etc. go to 0; any history is cleared as well.
85    */

86   public synchronized void reset() {
87     n = sum = 0;
88     minimum = Integer.MAX_VALUE;
89     maximum = Integer.MIN_VALUE;
90     if (sampleHistory != null) {
91       for (int pos = 0; pos < sampleHistory.length; ++pos) {
92         sampleHistory[pos] = null;
93       }
94       nextHistoryPosition = 0;
95     }
96   }
97
98   public String JavaDoc getName() {
99     return name;
100   }
101
102   /**
103    * @return the maximum value of all samples
104    */

105   public int getMaximum() {
106     return maximum;
107   }
108
109   /**
110    * @return the minimum value of all samples
111    */

112   public int getMinimum() {
113     return minimum;
114   }
115
116   /**
117    * @return the number of samples (so far)
118    */

119   public int getN() {
120     return n;
121   }
122
123   /**
124    * @return the running sum of samples (so far)
125    */

126   public int getSum() {
127     return sum;
128   }
129
130   /**
131    * @return the running average of the samples (so far)
132    */

133   public double getAverage() {
134     return n > 0 ? ((double) sum / (double) n) : 0.0;
135   }
136
137   /**
138    * Returns an average rate at which samples were added, if you want this rate per second then pass in <strong>1000</strong>,
139    * if you want it per minute then pass in <strong>1000 * 60</strong>, etc. This rate is extrapolated from the entire
140    * available history as defined in the constructor. For finer and more accurate rates, the history length should be
141    * lengthened.
142    *
143    * @return the rate at which samples were added per {@link periodInMillis}, averaged over the (rolling) history
144    * length, or -1 if history is not being kept
145    */

146   public int getSampleRate(final long periodInMillis) {
147     // XXX:
148
// NOTE:
149
// IMPORTANT:
150
// If you mess with this method, please run the AggregateIntegerTest manually and un-disable the
151
// testGetSampleRate() method there. It does not pass reliably because it is timing dependent, but it should
152
// be run manually if this method is modified.
153
final int sampleRate;
154     if (sampleHistorySnapshot != null) {
155       // We synchronize on and use our history snapshot (thus keeping with our fixed-memory requirements) for each
156
// calculation
157
synchronized (sampleHistorySnapshot) {
158         final int snapshotPosition;
159         final int localN;
160         synchronized (this) {
161           for (int pos = 0; pos < sampleHistory.length; ++pos) {
162             sampleHistorySnapshot[pos] = sampleHistory[pos];
163           }
164           snapshotPosition = nextHistoryPosition;
165           localN = n;
166         }
167         if (localN > 0) {
168           // Now with our snapshot data we need to extrapolate our rate information
169
final Sample oldestSample;
170           final int existingSampleCount;
171           if (localN > sampleHistorySnapshot.length) {
172             oldestSample = sampleHistorySnapshot[snapshotPosition];
173             existingSampleCount = sampleHistorySnapshot.length;
174           } else {
175             oldestSample = sampleHistorySnapshot[0];
176             existingSampleCount = localN;
177           }
178           final double elapsedSampleTimeInMillis = System.currentTimeMillis() - oldestSample.timestamp;
179           if (elapsedSampleTimeInMillis > 0) {
180             sampleRate = (int) ((periodInMillis / elapsedSampleTimeInMillis) * existingSampleCount);
181           } else {
182             sampleRate = 0;
183           }
184         } else {
185           sampleRate = 0;
186         }
187       }
188     } else {
189       sampleRate = -1;
190     }
191     return sampleRate;
192   }
193
194   public String JavaDoc toString() {
195     return MessageFormat.format(TO_STRING_FORMAT, new Object JavaDoc[] { name, new Integer JavaDoc(n), new Integer JavaDoc(sum),
196         new Integer JavaDoc(minimum), new Integer JavaDoc(maximum), new Integer JavaDoc(sum / n) });
197   }
198
199 }
200
Popular Tags