1
16 package net.sf.ehcache.statistics;
17
18 import java.util.List;
19 import java.util.concurrent.CopyOnWriteArrayList;
20 import java.util.concurrent.atomic.AtomicBoolean;
21 import java.util.concurrent.atomic.AtomicInteger;
22 import java.util.concurrent.atomic.AtomicLong;
23
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 import net.sf.ehcache.CacheException;
28 import net.sf.ehcache.Ehcache;
29 import net.sf.ehcache.Element;
30 import net.sf.ehcache.Statistics;
31 import net.sf.ehcache.writer.CacheWriterManager;
32 import net.sf.ehcache.writer.writebehind.WriteBehindManager;
33
34
40 public class LiveCacheStatisticsImpl implements LiveCacheStatistics, LiveCacheStatisticsData {
41
42 private static final Logger LOG = LoggerFactory.getLogger(LiveCacheStatisticsImpl.class.getName());
43
44 private static final int MIN_MAX_DEFAULT_VALUE = -1;
45 private static final int MILLIS_PER_SECOND = 1000;
46 private static final int NANOS_PER_MILLI = MILLIS_PER_SECOND * MILLIS_PER_SECOND;
47 private static final int HIT_RATIO_MULTIPLIER = 100;
48
49 private final AtomicBoolean statisticsEnabled = new AtomicBoolean(true);
50 private final AtomicLong cacheHitInMemoryCount = new AtomicLong();
51 private final AtomicLong cacheHitOffHeapCount = new AtomicLong();
52 private final AtomicLong cacheHitOnDiskCount = new AtomicLong();
53 private final AtomicLong cacheMissNotFound = new AtomicLong();
54 private final AtomicLong cacheMissInMemoryCount = new AtomicLong();
55 private final AtomicLong cacheMissOffHeapCount = new AtomicLong();
56 private final AtomicLong cacheMissOnDiskCount = new AtomicLong();
57 private final AtomicLong cacheMissExpired = new AtomicLong();
58 private final AtomicLong cacheElementEvictedCount = new AtomicLong();
59 private final AtomicLong totalGetTimeTakenNanos = new AtomicLong();
60 private final AtomicLong cacheElementRemoved = new AtomicLong();
61 private final AtomicLong cacheElementExpired = new AtomicLong();
62 private final AtomicLong cacheElementPut = new AtomicLong();
63 private final AtomicLong cacheElementUpdated = new AtomicLong();
64 private final AtomicInteger statisticsAccuracy = new AtomicInteger();
65 private final AtomicLong minGetTimeNanos = new AtomicLong(MIN_MAX_DEFAULT_VALUE);
66 private final AtomicLong maxGetTimeNanos = new AtomicLong(MIN_MAX_DEFAULT_VALUE);
67 private final AtomicLong xaCommitCount = new AtomicLong();
68 private final AtomicLong xaRollbackCount = new AtomicLong();
69 private final AtomicLong xaRecoveredCount = new AtomicLong();
70
71 private final List<CacheUsageListener> listeners = new CopyOnWriteArrayList<CacheUsageListener>();
72
73 private final Ehcache cache;
74
75
80 public LiveCacheStatisticsImpl(Ehcache cache) {
81 this.cache = cache;
82 }
83
84
87 public void clearStatistics() {
88 cacheHitInMemoryCount.set(0);
89 cacheHitOffHeapCount.set(0);
90 cacheHitOnDiskCount.set(0);
91 cacheMissExpired.set(0);
92 cacheMissNotFound.set(0);
93 cacheMissInMemoryCount.set(0);
94 cacheMissOffHeapCount.set(0);
95 cacheMissOnDiskCount.set(0);
96 cacheElementEvictedCount.set(0);
97 totalGetTimeTakenNanos.set(0);
98 cacheElementRemoved.set(0);
99 cacheElementExpired.set(0);
100 cacheElementPut.set(0);
101 cacheElementUpdated.set(0);
102 minGetTimeNanos.set(MIN_MAX_DEFAULT_VALUE);
103 maxGetTimeNanos.set(MIN_MAX_DEFAULT_VALUE);
104 xaCommitCount.set(0);
105 xaRollbackCount.set(0);
106 for (CacheUsageListener l : listeners) {
107 l.notifyStatisticsCleared();
108 }
109 }
110
111
114 public void xaCommit() {
115 if (!statisticsEnabled.get()) {
116 return;
117 }
118 xaCommitCount.incrementAndGet();
119 for (CacheUsageListener l : listeners) {
120 l.notifyXaCommit();
121 }
122 }
123
124
127 public void xaRollback() {
128 if (!statisticsEnabled.get()) {
129 return;
130 }
131 xaRollbackCount.incrementAndGet();
132 for (CacheUsageListener l : listeners) {
133 l.notifyXaRollback();
134 }
135 }
136
137
140 public void xaRecovered(int count) {
141 if (!statisticsEnabled.get()) {
142 return;
143 }
144 xaRecoveredCount.addAndGet(count);
145 }
146
147
150 public boolean isStatisticsEnabled() {
151 return statisticsEnabled.get();
152 }
153
154
157 public void setStatisticsEnabled(boolean enableStatistics) {
158 if (enableStatistics) {
159 clearStatistics();
160 }
161 statisticsEnabled.set(enableStatistics);
162 for (CacheUsageListener l : listeners) {
163 l.notifyStatisticsEnabledChanged(enableStatistics);
164 }
165 }
166
167
170 public void addGetTimeNanos(long nanos) {
171 if (!statisticsEnabled.get()) {
172 return;
173 }
174 totalGetTimeTakenNanos.addAndGet(nanos);
175 for (CacheUsageListener l : listeners) {
176 l.notifyGetTimeNanos(nanos);
177 l.notifyTimeTakenForGet(nanos / NANOS_PER_MILLI);
178 }
179 if (minGetTimeNanos.get() == MIN_MAX_DEFAULT_VALUE || (nanos < minGetTimeNanos.get())) {
180 minGetTimeNanos.set(nanos);
181 }
182 if (maxGetTimeNanos.get() == MIN_MAX_DEFAULT_VALUE || (nanos > maxGetTimeNanos.get() && nanos > 0)) {
183 maxGetTimeNanos.set(nanos);
184 }
185 }
186
187
190 public void addGetTimeMillis(long millis) {
191 if (!statisticsEnabled.get()) {
192 return;
193 }
194 totalGetTimeTakenNanos.addAndGet(millis);
195 for (CacheUsageListener l : listeners) {
196 l.notifyTimeTakenForGet(millis);
197 }
198 if (minGetTimeNanos.get() == MIN_MAX_DEFAULT_VALUE || (millis < minGetTimeNanos.get() )) {
199 minGetTimeNanos.set(millis);
200 }
201 if (maxGetTimeNanos.get() == MIN_MAX_DEFAULT_VALUE || (millis > maxGetTimeNanos.get() && millis > 0)) {
202 maxGetTimeNanos.set(millis);
203 }
204 }
205
206
209 public void cacheHitInMemory() {
210 if (!statisticsEnabled.get()) {
211 return;
212 }
213 cacheHitInMemoryCount.incrementAndGet();
214 for (CacheUsageListener l : listeners) {
215 l.notifyCacheHitInMemory();
216 }
217 }
218
219
222 public void cacheHitOffHeap() {
223 if (!statisticsEnabled.get()) {
224 return;
225 }
226 cacheHitOffHeapCount.incrementAndGet();
227 for (CacheUsageListener l : listeners) {
228 l.notifyCacheHitOffHeap();
229 }
230 }
231
232
235 public void cacheHitOnDisk() {
236 if (!statisticsEnabled.get()) {
237 return;
238 }
239 cacheHitOnDiskCount.incrementAndGet();
240 for (CacheUsageListener l : listeners) {
241 l.notifyCacheHitOnDisk();
242 }
243 }
244
245
248 public void cacheMissExpired() {
249 if (!statisticsEnabled.get()) {
250 return;
251 }
252 cacheMissExpired.incrementAndGet();
253 for (CacheUsageListener l : listeners) {
254 l.notifyCacheMissedWithExpired();
255 }
256 }
257
258
261 public void cacheMissNotFound() {
262 if (!statisticsEnabled.get()) {
263 return;
264 }
265 cacheMissNotFound.incrementAndGet();
266 for (CacheUsageListener l : listeners) {
267 l.notifyCacheMissedWithNotFound();
268 }
269 }
270
271
274 public void cacheMissInMemory() {
275 if (!statisticsEnabled.get()) {
276 return;
277 }
278 cacheMissInMemoryCount.incrementAndGet();
279 for (CacheUsageListener l : listeners) {
280 l.notifyCacheMissInMemory();
281 }
282 }
283
284
287 public void cacheMissOffHeap() {
288 if (!statisticsEnabled.get()) {
289 return;
290 }
291 cacheMissOffHeapCount.incrementAndGet();
292 for (CacheUsageListener l : listeners) {
293 l.notifyCacheMissOffHeap();
294 }
295 }
296
297
300 public void cacheMissOnDisk() {
301 if (!statisticsEnabled.get()) {
302 return;
303 }
304 cacheMissOnDiskCount.incrementAndGet();
305 for (CacheUsageListener l : listeners) {
306 l.notifyCacheMissOnDisk();
307 }
308 }
309
310
313 public void setStatisticsAccuracy(int statisticsAccuracy) {
314 if (!Statistics.isValidStatisticsAccuracy(statisticsAccuracy)) {
315 throw new IllegalArgumentException("Invalid statistics accuracy value: " + statisticsAccuracy);
316 }
317 this.statisticsAccuracy.set(statisticsAccuracy);
318 for (CacheUsageListener l : listeners) {
319 l.notifyStatisticsAccuracyChanged(statisticsAccuracy);
320 }
321 }
322
323
326 public void dispose() {
327 for (CacheUsageListener l : listeners) {
328 l.dispose();
329 }
330 }
331
332
335 public void notifyElementEvicted(Ehcache cache, Element element) {
336 if (!statisticsEnabled.get()) {
337 return;
338 }
339 cacheElementEvictedCount.incrementAndGet();
340 for (CacheUsageListener l : listeners) {
341 l.notifyCacheElementEvicted();
342 }
343 }
344
345
348 public void notifyElementExpired(Ehcache cache, Element element) {
349 if (!statisticsEnabled.get()) {
350 return;
351 }
352 cacheElementExpired.incrementAndGet();
353 for (CacheUsageListener l : listeners) {
354 l.notifyCacheElementExpired();
355 }
356 }
357
358
361 public void notifyElementPut(Ehcache cache, Element element) throws CacheException {
362 if (!statisticsEnabled.get()) {
363 return;
364 }
365 cacheElementPut.incrementAndGet();
366 for (CacheUsageListener l : listeners) {
367 l.notifyCacheElementPut();
368 }
369 }
370
371
374 public void notifyElementRemoved(Ehcache cache, Element element) throws CacheException {
375 if (!statisticsEnabled.get()) {
376 return;
377 }
378 cacheElementRemoved.incrementAndGet();
379 for (CacheUsageListener l : listeners) {
380 l.notifyCacheElementRemoved();
381 }
382 }
383
384
387 public void notifyElementUpdated(Ehcache cache, Element element) throws CacheException {
388 if (!statisticsEnabled.get()) {
389 return;
390 }
391 cacheElementUpdated.incrementAndGet();
392 for (CacheUsageListener l : listeners) {
393 l.notifyCacheElementUpdated();
394 }
395 }
396
397
400 public void notifyRemoveAll(Ehcache cache) {
401 if (!statisticsEnabled.get()) {
402 return;
403 }
404 for (CacheUsageListener l : listeners) {
405 l.notifyRemoveAll();
406 }
407 }
408
409
412 @Override
413 public Object clone() throws CloneNotSupportedException {
414
415 super.clone();
416 throw new CloneNotSupportedException();
417 }
418
419
422 public float getAverageGetTimeMillis() {
423 return getAverageGetTimeNanos() / (float) NANOS_PER_MILLI;
424 }
425
426
429 public long getAverageGetTimeNanos() {
430 long accessCount = getCacheHitCount() + getCacheMissCount();
431 if (accessCount == 0) {
432 return 0;
433 }
434 return totalGetTimeTakenNanos.get() / accessCount;
435 }
436
437
440 public void registerCacheUsageListener(CacheUsageListener cacheUsageListener) throws IllegalStateException {
441 if (!isStatisticsEnabled()) {
442 LOG.warn("Registering a CacheUsageListener on {} whose statistics are currently disabled. "
443 + "No events will be fired until statistics are enabled.", cache.getName());
444 }
445 listeners.add(cacheUsageListener);
446 }
447
448
451 public void removeCacheUsageListener(CacheUsageListener cacheUsageListener) throws IllegalStateException {
452 listeners.remove(cacheUsageListener);
453 }
454
455
458 public long getCacheHitCount() {
459 return cacheHitInMemoryCount.get() + cacheHitOffHeapCount.get() + cacheHitOnDiskCount.get();
460 }
461
462
465 public long getCacheMissCount() {
466 return cacheMissNotFound.get() + cacheMissExpired.get();
467 }
468
469
472 public long getInMemoryMissCount() {
473 return cacheMissInMemoryCount.get();
474 }
475
476
479 public long getOffHeapMissCount() {
480 return cacheMissOffHeapCount.get();
481 }
482
483
486 public long getOnDiskMissCount() {
487 return cacheMissOnDiskCount.get();
488 }
489
490
491
494 public long getCacheMissCountExpired() {
495 return cacheMissExpired.get();
496 }
497
498
501 public int getCacheHitRatio() {
502 long hits = getCacheHitCount();
503 long accesses = hits + getCacheMissCount();
504
505 return (int) (accesses == 0 ? 0 : ((hits / (double) accesses) * HIT_RATIO_MULTIPLIER));
506 }
507
508
511 public long getEvictedCount() {
512 return cacheElementEvictedCount.get();
513 }
514
515
518 public long getInMemoryHitCount() {
519 return cacheHitInMemoryCount.get();
520 }
521
522
525 public long getOffHeapHitCount() {
526 return cacheHitOffHeapCount.get();
527 }
528
529
532 public long getOnDiskHitCount() {
533 return cacheHitOnDiskCount.get();
534 }
535
536
539 public long getSize() {
540 if (!statisticsEnabled.get()) {
541 return 0;
542 }
543 return cache.getSizeBasedOnAccuracy(statisticsAccuracy.get());
544 }
545
546
550 @Deprecated
551 public long getInMemorySize() {
552 return getLocalHeapSize();
553 }
554
555
559 @Deprecated
560 public long getOffHeapSize() {
561 return getLocalOffHeapSize();
562 }
563
564
568 @Deprecated
569 public long getOnDiskSize() {
570 return getLocalDiskSize();
571 }
572
573
576 public long getLocalHeapSize() {
577 if (!statisticsEnabled.get()) {
578 return 0;
579 }
580 return cache.getMemoryStoreSize();
581 }
582
583
586 public long getLocalOffHeapSize() {
587 if (!statisticsEnabled.get()) {
588 return 0;
589 }
590 return cache.getOffHeapStoreSize();
591 }
592
593
596 public long getLocalDiskSize() {
597 if (!statisticsEnabled.get()) {
598 return 0;
599 }
600 return cache.getDiskStoreSize();
601 }
602
603
606 public long getLocalDiskSizeInBytes() {
607 if (!statisticsEnabled.get()) {
608 return 0;
609 }
610 return cache.calculateOnDiskSize();
611 }
612
613
616 public long getLocalHeapSizeInBytes() {
617 if (!statisticsEnabled.get()) {
618 return 0;
619 }
620 return cache.calculateInMemorySize();
621 }
622
623
626 public long getLocalOffHeapSizeInBytes() {
627 if (!statisticsEnabled.get()) {
628 return 0;
629 }
630 return cache.calculateOffHeapSize();
631 }
632
633
634
637 public String getCacheName() {
638 return cache.getName();
639 }
640
641
644 public int getStatisticsAccuracy() {
645 return statisticsAccuracy.get();
646 }
647
648
651 public long getExpiredCount() {
652 return cacheElementExpired.get();
653 }
654
655
658 public long getPutCount() {
659 return cacheElementPut.get();
660 }
661
662
665 public long getRemovedCount() {
666 return cacheElementRemoved.get();
667 }
668
669
672 public long getUpdateCount() {
673 return cacheElementUpdated.get();
674 }
675
676
679 public String getStatisticsAccuracyDescription() {
680 int value = statisticsAccuracy.get();
681 if (value == 0) {
682 return "None";
683 } else if (value == 1) {
684 return "Best Effort";
685 } else {
686 return "Guaranteed";
687 }
688 }
689
690
695 public long getMaxGetTimeMillis() {
696 return maxGetTimeNanos.get() / NANOS_PER_MILLI;
697 }
698
699
704 public long getMinGetTimeMillis() {
705 return minGetTimeNanos.get() / NANOS_PER_MILLI;
706 }
707
708
713 public long getMaxGetTimeNanos() {
714 return maxGetTimeNanos.get();
715 }
716
717
722 public long getMinGetTimeNanos() {
723 return minGetTimeNanos.get();
724 }
725
726
731 public long getXaCommitCount() {
732 return xaCommitCount.get();
733 }
734
735
740 public long getXaRollbackCount() {
741 return xaRollbackCount.get();
742 }
743
744
749 public long getXaRecoveredCount() {
750 return xaRecoveredCount.get();
751 }
752
753
756 public long getWriterQueueLength() {
757 CacheWriterManager writerManager = cache.getWriterManager();
758 if (writerManager instanceof WriteBehindManager) {
759 return ((WriteBehindManager)writerManager).getQueueSize();
760 }
761 return 0;
762 }
763 }
764