1 /***
2 * Copyright 2003-2010 Terracotta, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package net.sf.ehcache.statistics.sampled;
17
18 import java.util.concurrent.atomic.AtomicBoolean;
19 import java.util.concurrent.atomic.AtomicInteger;
20
21 import net.sf.ehcache.CacheException;
22 import net.sf.ehcache.Statistics;
23 import net.sf.ehcache.statistics.CacheUsageListener;
24 import net.sf.ehcache.util.FailSafeTimer;
25 import net.sf.ehcache.util.counter.CounterConfig;
26 import net.sf.ehcache.util.counter.CounterManager;
27 import net.sf.ehcache.util.counter.CounterManagerImpl;
28 import net.sf.ehcache.util.counter.sampled.SampledCounter;
29 import net.sf.ehcache.util.counter.sampled.SampledCounterConfig;
30 import net.sf.ehcache.util.counter.sampled.SampledRateCounter;
31 import net.sf.ehcache.util.counter.sampled.SampledRateCounterConfig;
32
33 /***
34 * An implementation of {@link SampledCacheStatistics} This also implements {@link CacheUsageListener} and depends on the notification
35 * received from
36 * these to update the stats
37 * <p />
38 *
39 * @author <a href="mailto:asanoujam@terracottatech.com">Abhishek Sanoujam</a>
40 * @since 1.7
41 */
42 public class SampledCacheStatisticsImpl implements CacheUsageListener, SampledCacheStatistics {
43
44 private static final int AVERAGE_SEARCH_SAMPLE_INTERVAL = 10;
45 private static final int DEFAULT_HISTORY_SIZE = 30;
46 private static final int DEFAULT_INTERVAL_SECS = 1;
47 private static final SampledCounterConfig DEFAULT_SAMPLED_COUNTER_CONFIG = new SampledCounterConfig(DEFAULT_INTERVAL_SECS,
48 DEFAULT_HISTORY_SIZE, true, 0L);
49 private static final SampledRateCounterConfig DEFAULT_SAMPLED_RATE_COUNTER_CONFIG = new SampledRateCounterConfig(DEFAULT_INTERVAL_SECS,
50 DEFAULT_HISTORY_SIZE, true);
51
52 private volatile CounterManager counterManager;
53 private final SampledCounter cacheHitCount;
54 private final SampledCounter cacheHitInMemoryCount;
55 private final SampledCounter cacheHitOffHeapCount;
56 private final SampledCounter cacheHitOnDiskCount;
57 private final SampledCounter cacheMissCount;
58 private final SampledCounter cacheMissInMemoryCount;
59 private final SampledCounter cacheMissOffHeapCount;
60 private final SampledCounter cacheMissOnDiskCount;
61 private final SampledCounter cacheMissExpiredCount;
62 private final SampledCounter cacheMissNotFoundCount;
63 private final SampledCounter cacheElementEvictedCount;
64 private final SampledCounter cacheElementRemoved;
65 private final SampledCounter cacheElementExpired;
66 private final SampledCounter cacheElementPut;
67 private final SampledCounter cacheElementUpdated;
68 private final SampledCounter cacheSearchCount;
69 private final SampledCounter cacheXaCommitCount;
70 private final SampledCounter cacheXaRollbackCount;
71 private final SampledRateCounter averageGetTime;
72 private final SampledRateCounter averageSearchTime;
73
74 private final AtomicBoolean sampledStatisticsEnabled;
75 private final AtomicInteger statisticsAccuracy;
76
77 /***
78 * Constructor that accepts a timer which will be used to schedule the
79 * sampled counters
80 */
81 public SampledCacheStatisticsImpl(FailSafeTimer timer) {
82 counterManager = new CounterManagerImpl(timer);
83 cacheHitCount = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
84 cacheHitInMemoryCount = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
85 cacheHitOffHeapCount = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
86 cacheHitOnDiskCount = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
87 cacheMissCount = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
88 cacheMissInMemoryCount = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
89 cacheMissOffHeapCount = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
90 cacheMissOnDiskCount = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
91 cacheMissExpiredCount = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
92 cacheMissNotFoundCount = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
93 cacheElementEvictedCount = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
94 cacheElementRemoved = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
95 cacheElementExpired = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
96 cacheElementPut = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
97 cacheElementUpdated = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
98 cacheSearchCount = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
99 cacheXaCommitCount = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
100 cacheXaRollbackCount = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);
101
102 averageGetTime = (SampledRateCounter) createSampledCounter(DEFAULT_SAMPLED_RATE_COUNTER_CONFIG);
103 averageSearchTime = (SampledRateCounter) createSampledCounter(
104 new SampledRateCounterConfig(AVERAGE_SEARCH_SAMPLE_INTERVAL, DEFAULT_HISTORY_SIZE, true));
105
106 this.sampledStatisticsEnabled = new AtomicBoolean(true);
107 this.statisticsAccuracy = new AtomicInteger(Statistics.STATISTICS_ACCURACY_BEST_EFFORT);
108 }
109
110 private SampledCounter createSampledCounter(CounterConfig defaultCounterConfig) {
111 return (SampledCounter) counterManager.createCounter(defaultCounterConfig);
112 }
113
114 private void incrementIfStatsEnabled(SampledCounter... counters) {
115 if (!sampledStatisticsEnabled.get()) {
116 return;
117 }
118 for (SampledCounter counter : counters) {
119 counter.increment();
120 }
121 }
122
123 /***
124 * Clears the collected statistics. Resets all counters to zero
125 */
126 public void clearStatistics() {
127 cacheHitCount.getAndReset();
128 cacheHitInMemoryCount.getAndReset();
129 cacheHitOffHeapCount.getAndReset();
130 cacheHitOnDiskCount.getAndReset();
131 cacheMissCount.getAndReset();
132 cacheMissInMemoryCount.getAndReset();
133 cacheMissOffHeapCount.getAndReset();
134 cacheMissOnDiskCount.getAndReset();
135 cacheMissExpiredCount.getAndReset();
136 cacheMissNotFoundCount.getAndReset();
137 cacheElementEvictedCount.getAndReset();
138 cacheElementRemoved.getAndReset();
139 cacheElementExpired.getAndReset();
140 cacheElementPut.getAndReset();
141 cacheElementUpdated.getAndReset();
142 cacheSearchCount.getAndReset();
143 cacheXaCommitCount.getAndReset();
144 cacheXaRollbackCount.getAndReset();
145 averageGetTime.getAndReset();
146 averageSearchTime.getAndReset();
147 }
148
149 /***
150 * {@inheritDoc}
151 */
152 public void notifyCacheElementEvicted() {
153 incrementIfStatsEnabled(cacheElementEvictedCount);
154 }
155
156 /***
157 * {@inheritDoc}
158 */
159 public void notifyCacheHitInMemory() {
160 incrementIfStatsEnabled(cacheHitCount, cacheHitInMemoryCount);
161 }
162
163 /***
164 * {@inheritDoc}
165 */
166 public void notifyCacheHitOffHeap() {
167 incrementIfStatsEnabled(cacheHitCount, cacheHitOffHeapCount);
168 }
169
170 /***
171 * {@inheritDoc}
172 */
173 public void notifyCacheHitOnDisk() {
174 incrementIfStatsEnabled(cacheHitCount, cacheHitOnDiskCount);
175 }
176
177 /***
178 * {@inheritDoc}
179 */
180 public void notifyCacheMissedWithExpired() {
181 incrementIfStatsEnabled(cacheMissCount, cacheMissExpiredCount);
182 }
183
184 /***
185 * {@inheritDoc}
186 */
187 public void notifyCacheMissedWithNotFound() {
188 incrementIfStatsEnabled(cacheMissCount, cacheMissNotFoundCount);
189 }
190
191 /***
192 * {@inheritDoc}
193 */
194 public void notifyCacheMissInMemory() {
195 incrementIfStatsEnabled(cacheMissCount, cacheMissInMemoryCount);
196 }
197
198 /***
199 * {@inheritDoc}
200 */
201 public void notifyCacheMissOffHeap() {
202 incrementIfStatsEnabled(cacheMissCount, cacheMissOffHeapCount);
203 }
204
205 /***
206 * {@inheritDoc}
207 */
208 public void notifyCacheMissOnDisk() {
209 incrementIfStatsEnabled(cacheMissCount, cacheMissOnDiskCount);
210 }
211
212 /***
213 * {@inheritDoc}
214 */
215 public void dispose() {
216 counterManager.shutdown();
217 }
218
219 /***
220 * {@inheritDoc}
221 */
222 public void notifyCacheElementExpired() {
223 incrementIfStatsEnabled(cacheElementExpired);
224 }
225
226 /***
227 * {@inheritDoc}
228 */
229 public void notifyCacheElementPut() throws CacheException {
230 incrementIfStatsEnabled(cacheElementPut);
231 }
232
233 /***
234 * {@inheritDoc}
235 */
236 public void notifyCacheElementRemoved() throws CacheException {
237 incrementIfStatsEnabled(cacheElementRemoved);
238 }
239
240 /***
241 * {@inheritDoc}
242 */
243 public void notifyCacheElementUpdated() throws CacheException {
244 incrementIfStatsEnabled(cacheElementUpdated);
245 }
246
247 /***
248 * {@inheritDoc}
249 */
250 public void notifyTimeTakenForGet(long millis) {
251 if (!sampledStatisticsEnabled.get()) {
252 return;
253 }
254 averageGetTime.increment(millis, 1);
255 }
256
257 /***
258 * {@inheritDoc}
259 */
260 public void notifyRemoveAll() {
261
262 }
263
264 /***
265 * {@inheritDoc}
266 */
267 @Override
268 public Object clone() throws CloneNotSupportedException {
269 super.clone();
270 throw new CloneNotSupportedException();
271 }
272
273 /***
274 * {@inheritDoc}
275 */
276 public void notifyStatisticsEnabledChanged(boolean enableStatistics) {
277 if (!enableStatistics) {
278 sampledStatisticsEnabled.set(false);
279 }
280 }
281
282 /***
283 * {@inheritDoc}
284 */
285 public void notifyStatisticsAccuracyChanged(int statisticsAccuracyValue) {
286 if (Statistics.isValidStatisticsAccuracy(statisticsAccuracyValue)) {
287 statisticsAccuracy.set(statisticsAccuracyValue);
288 return;
289 }
290 throw new IllegalArgumentException("Invalid statistics accuracy value: " + statisticsAccuracyValue);
291 }
292
293 /***
294 * {@inheritDoc}
295 */
296 public void notifyStatisticsCleared() {
297 cacheHitCount.getAndReset();
298 cacheHitInMemoryCount.getAndReset();
299 cacheHitOffHeapCount.getAndReset();
300 cacheHitOnDiskCount.getAndReset();
301 cacheMissCount.getAndReset();
302 cacheMissInMemoryCount.getAndReset();
303 cacheMissOffHeapCount.getAndReset();
304 cacheMissOnDiskCount.getAndReset();
305 cacheMissExpiredCount.getAndReset();
306 cacheMissNotFoundCount.getAndReset();
307 cacheElementEvictedCount.getAndReset();
308 cacheElementRemoved.getAndReset();
309 cacheElementExpired.getAndReset();
310 cacheElementPut.getAndReset();
311 cacheElementUpdated.getAndReset();
312 cacheXaCommitCount.getAndReset();
313 cacheXaRollbackCount.getAndReset();
314 averageGetTime.getAndReset();
315 }
316
317 /***
318 * {@inheritDoc}
319 */
320 public long getCacheHitMostRecentSample() {
321 return cacheHitCount.getMostRecentSample().getCounterValue();
322 }
323
324 /***
325 * {@inheritDoc}
326 */
327 public long getAverageGetTimeMostRecentSample() {
328 return averageGetTime.getMostRecentSample().getCounterValue();
329 }
330
331 /***
332 * {@inheritDoc}
333 */
334 public long getCacheElementEvictedMostRecentSample() {
335 return cacheElementEvictedCount.getMostRecentSample().getCounterValue();
336 }
337
338 /***
339 * {@inheritDoc}
340 */
341 public long getCacheHitInMemoryMostRecentSample() {
342 return cacheHitInMemoryCount.getMostRecentSample().getCounterValue();
343 }
344
345 /***
346 * {@inheritDoc}
347 */
348 public long getCacheHitOffHeapMostRecentSample() {
349 return cacheHitOffHeapCount.getMostRecentSample().getCounterValue();
350 }
351
352 /***
353 * {@inheritDoc}
354 */
355 public long getCacheHitOnDiskMostRecentSample() {
356 return cacheHitOnDiskCount.getMostRecentSample().getCounterValue();
357 }
358
359 /***
360 * {@inheritDoc}
361 */
362 public long getCacheMissExpiredMostRecentSample() {
363 return cacheMissExpiredCount.getMostRecentSample().getCounterValue();
364 }
365
366 /***
367 * {@inheritDoc}
368 */
369 public long getCacheMissMostRecentSample() {
370 return cacheMissCount.getMostRecentSample().getCounterValue();
371 }
372
373 /***
374 * {@inheritDoc}
375 */
376 public long getCacheMissInMemoryMostRecentSample() {
377 return cacheMissInMemoryCount.getMostRecentSample().getCounterValue();
378 }
379
380 /***
381 * {@inheritDoc}
382 */
383 public long getCacheMissOffHeapMostRecentSample() {
384 return cacheMissOffHeapCount.getMostRecentSample().getCounterValue();
385 }
386
387 /***
388 * {@inheritDoc}
389 */
390 public long getCacheMissOnDiskMostRecentSample() {
391 return cacheMissOnDiskCount.getMostRecentSample().getCounterValue();
392 }
393
394 /***
395 * {@inheritDoc}
396 */
397 public long getCacheMissNotFoundMostRecentSample() {
398 return cacheMissNotFoundCount.getMostRecentSample().getCounterValue();
399 }
400
401 /***
402 * {@inheritDoc}
403 */
404 public long getCacheElementExpiredMostRecentSample() {
405 return cacheElementExpired.getMostRecentSample().getCounterValue();
406 }
407
408 /***
409 * {@inheritDoc}
410 */
411 public long getCacheElementPutMostRecentSample() {
412 return cacheElementPut.getMostRecentSample().getCounterValue();
413 }
414
415 /***
416 * {@inheritDoc}
417 */
418 public long getCacheElementRemovedMostRecentSample() {
419 return cacheElementRemoved.getMostRecentSample().getCounterValue();
420 }
421
422 /***
423 * {@inheritDoc}
424 */
425 public long getCacheElementUpdatedMostRecentSample() {
426 return cacheElementUpdated.getMostRecentSample().getCounterValue();
427 }
428
429 /***
430 * {@inheritDoc}
431 */
432 public int getStatisticsAccuracy() {
433 return statisticsAccuracy.get();
434 }
435
436 /***
437 * {@inheritDoc}
438 */
439 public String getStatisticsAccuracyDescription() {
440 int value = statisticsAccuracy.get();
441 if (value == 0) {
442 return "None";
443 } else if (value == 1) {
444 return "Best Effort";
445 } else {
446 return "Guaranteed";
447 }
448 }
449
450 /***
451 * {@inheritDoc}
452 */
453 public boolean isSampledStatisticsEnabled() {
454 return sampledStatisticsEnabled.get();
455 }
456
457 /***
458 * {@inheritDoc}
459 */
460 public long getAverageSearchTime() {
461 return this.averageSearchTime.getMostRecentSample().getCounterValue();
462 }
463
464 /***
465 * {@inheritDoc}
466 */
467 public long getSearchesPerSecond() {
468 return cacheSearchCount.getMostRecentSample().getCounterValue();
469 }
470
471 /***
472 * {@inheritDoc}
473 */
474 public void notifyCacheSearch(long executeTime) {
475 this.cacheSearchCount.increment();
476 this.averageSearchTime.increment(executeTime, 1);
477 }
478
479 /***
480 * {@inheritDoc}
481 */
482 public long getCacheXaCommitsMostRecentSample() {
483 return cacheXaCommitCount.getMostRecentSample().getCounterValue();
484 }
485
486 /***
487 * {@inheritDoc}
488 */
489 public void notifyXaCommit() {
490 incrementIfStatsEnabled(cacheXaCommitCount);
491 }
492
493 /***
494 * {@inheritDoc}
495 */
496 public long getCacheXaRollbacksMostRecentSample() {
497 return cacheXaRollbackCount.getMostRecentSample().getCounterValue();
498 }
499
500 /***
501 * {@inheritDoc}
502 */
503 public void notifyXaRollback() {
504 incrementIfStatsEnabled(cacheXaRollbackCount);
505 }
506 }