View Javadoc

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;
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  /***
35   * Implementation which can be used both as a {@link LiveCacheStatistics} and {@link LiveCacheStatisticsData}
36   *
37   * @author <a href="mailto:asanoujam@terracottatech.com">Abhishek Sanoujam</a>
38   * @since 1.7
39   */
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  
46      private final AtomicBoolean statisticsEnabled = new AtomicBoolean(true);
47      private final AtomicLong cacheHitInMemoryCount = new AtomicLong();
48      private final AtomicLong cacheHitOffHeapCount = new AtomicLong();
49      private final AtomicLong cacheHitOnDiskCount = new AtomicLong();
50      private final AtomicLong cacheMissNotFound = new AtomicLong();
51      private final AtomicLong cacheMissInMemoryCount = new AtomicLong();
52      private final AtomicLong cacheMissOffHeapCount = new AtomicLong();
53      private final AtomicLong cacheMissOnDiskCount = new AtomicLong();
54      private final AtomicLong cacheMissExpired = new AtomicLong();
55      private final AtomicLong cacheElementEvictedCount = new AtomicLong();
56      private final AtomicLong totalGetTimeTakenMillis = new AtomicLong();
57      private final AtomicLong cacheElementRemoved = new AtomicLong();
58      private final AtomicLong cacheElementExpired = new AtomicLong();
59      private final AtomicLong cacheElementPut = new AtomicLong();
60      private final AtomicLong cacheElementUpdated = new AtomicLong();
61      private final AtomicInteger statisticsAccuracy = new AtomicInteger();
62      private final AtomicLong minGetTimeMillis = new AtomicLong(MIN_MAX_DEFAULT_VALUE);
63      private final AtomicLong maxGetTimeMillis = new AtomicLong(MIN_MAX_DEFAULT_VALUE);
64      private final AtomicLong xaCommitCount = new AtomicLong();
65      private final AtomicLong xaRollbackCount = new AtomicLong();
66  
67      private final List<CacheUsageListener> listeners = new CopyOnWriteArrayList<CacheUsageListener>();
68  
69      private final Ehcache cache;
70  
71      /***
72       * Constructor that accepts the backing {@link Ehcache}, needed for {@link #getSize()}
73       *
74       * @param cache
75       */
76      public LiveCacheStatisticsImpl(Ehcache cache) {
77          this.cache = cache;
78      }
79  
80      /***
81       * {@inheritDoc}
82       */
83      public void clearStatistics() {
84          cacheHitInMemoryCount.set(0);
85          cacheHitOffHeapCount.set(0);
86          cacheHitOnDiskCount.set(0);
87          cacheMissExpired.set(0);
88          cacheMissNotFound.set(0);
89          cacheMissInMemoryCount.set(0);
90          cacheMissOffHeapCount.set(0);
91          cacheMissOnDiskCount.set(0);
92          cacheElementEvictedCount.set(0);
93          totalGetTimeTakenMillis.set(0);
94          cacheElementRemoved.set(0);
95          cacheElementExpired.set(0);
96          cacheElementPut.set(0);
97          cacheElementUpdated.set(0);
98          minGetTimeMillis.set(MIN_MAX_DEFAULT_VALUE);
99          maxGetTimeMillis.set(MIN_MAX_DEFAULT_VALUE);
100         xaCommitCount.set(0);
101         xaRollbackCount.set(0);
102         for (CacheUsageListener l : listeners) {
103             l.notifyStatisticsCleared();
104         }
105     }
106 
107     /***
108      * {@inheritDoc}
109      */
110     public void xaCommit() {
111         if (!statisticsEnabled.get()) {
112             return;
113         }
114         xaCommitCount.incrementAndGet();
115         for (CacheUsageListener l : listeners) {
116             l.notifyXaCommit();
117         }
118     }
119 
120     /***
121      * {@inheritDoc}
122      */
123     public void xaRollback() {
124         if (!statisticsEnabled.get()) {
125             return;
126         }
127         xaRollbackCount.incrementAndGet();
128         for (CacheUsageListener l : listeners) {
129             l.notifyXaRollback();
130         }
131     }
132 
133     /***
134      * {@inheritDoc}
135      */
136     public boolean isStatisticsEnabled() {
137         return statisticsEnabled.get();
138     }
139 
140     /***
141      * {@inheritDoc}
142      */
143     public void setStatisticsEnabled(boolean enableStatistics) {
144         if (enableStatistics) {
145             clearStatistics();
146         }
147         statisticsEnabled.set(enableStatistics);
148         for (CacheUsageListener l : listeners) {
149             l.notifyStatisticsEnabledChanged(enableStatistics);
150         }
151     }
152 
153     /***
154      * {@inheritDoc}
155      */
156     public void addGetTimeMillis(long millis) {
157         if (!statisticsEnabled.get()) {
158             return;
159         }
160         totalGetTimeTakenMillis.addAndGet(millis);
161         for (CacheUsageListener l : listeners) {
162             l.notifyTimeTakenForGet(millis);
163         }
164         if (minGetTimeMillis.get() == MIN_MAX_DEFAULT_VALUE || (millis < minGetTimeMillis.get() /*&& millis > 0*/)) {
165             minGetTimeMillis.set(millis);
166         }
167         if (maxGetTimeMillis.get() == MIN_MAX_DEFAULT_VALUE || (millis > maxGetTimeMillis.get() && millis > 0)) {
168             maxGetTimeMillis.set(millis);
169         }
170     }
171 
172     /***
173      * {@inheritDoc}
174      */
175     public void cacheHitInMemory() {
176         if (!statisticsEnabled.get()) {
177             return;
178         }
179         cacheHitInMemoryCount.incrementAndGet();
180         for (CacheUsageListener l : listeners) {
181             l.notifyCacheHitInMemory();
182         }
183     }
184 
185     /***
186      * {@inheritDoc}
187      */
188     public void cacheHitOffHeap() {
189         if (!statisticsEnabled.get()) {
190             return;
191         }
192         cacheHitOffHeapCount.incrementAndGet();
193         for (CacheUsageListener l : listeners) {
194             l.notifyCacheHitOffHeap();
195         }
196     }
197 
198     /***
199      * {@inheritDoc}
200      */
201     public void cacheHitOnDisk() {
202         if (!statisticsEnabled.get()) {
203             return;
204         }
205         cacheHitOnDiskCount.incrementAndGet();
206         for (CacheUsageListener l : listeners) {
207             l.notifyCacheHitOnDisk();
208         }
209     }
210 
211     /***
212      * {@inheritDoc}
213      */
214     public void cacheMissExpired() {
215         if (!statisticsEnabled.get()) {
216             return;
217         }
218         cacheMissExpired.incrementAndGet();
219         for (CacheUsageListener l : listeners) {
220             l.notifyCacheMissedWithExpired();
221         }
222     }
223 
224     /***
225      * {@inheritDoc}
226      */
227     public void cacheMissNotFound() {
228         if (!statisticsEnabled.get()) {
229             return;
230         }
231         cacheMissNotFound.incrementAndGet();
232         for (CacheUsageListener l : listeners) {
233             l.notifyCacheMissedWithNotFound();
234         }
235     }
236 
237     /***
238      * {@inheritDoc}
239      */
240     public void cacheMissInMemory() {
241         if (!statisticsEnabled.get()) {
242             return;
243         }
244         cacheMissInMemoryCount.incrementAndGet();
245         for (CacheUsageListener l : listeners) {
246             l.notifyCacheMissInMemory();
247         }
248     }
249 
250     /***
251      * {@inheritDoc}
252      */
253     public void cacheMissOffHeap() {
254         if (!statisticsEnabled.get()) {
255             return;
256         }
257         cacheMissOffHeapCount.incrementAndGet();
258         for (CacheUsageListener l : listeners) {
259             l.notifyCacheMissOffHeap();
260         }
261     }
262 
263     /***
264      * {@inheritDoc}
265      */
266     public void cacheMissOnDisk() {
267         if (!statisticsEnabled.get()) {
268             return;
269         }
270         cacheMissOnDiskCount.incrementAndGet();
271         for (CacheUsageListener l : listeners) {
272             l.notifyCacheMissOnDisk();
273         }
274     }
275 
276     /***
277      * {@inheritDoc}
278      */
279     public void setStatisticsAccuracy(int statisticsAccuracy) {
280         if (!Statistics.isValidStatisticsAccuracy(statisticsAccuracy)) {
281             throw new IllegalArgumentException("Invalid statistics accuracy value: " + statisticsAccuracy);
282         }
283         this.statisticsAccuracy.set(statisticsAccuracy);
284         for (CacheUsageListener l : listeners) {
285             l.notifyStatisticsAccuracyChanged(statisticsAccuracy);
286         }
287     }
288 
289     /***
290      * {@inheritDoc}
291      */
292     public void dispose() {
293         for (CacheUsageListener l : listeners) {
294             l.dispose();
295         }
296     }
297 
298     /***
299      * {@inheritDoc}
300      */
301     public void notifyElementEvicted(Ehcache cache, Element element) {
302         if (!statisticsEnabled.get()) {
303             return;
304         }
305         cacheElementEvictedCount.incrementAndGet();
306         for (CacheUsageListener l : listeners) {
307             l.notifyCacheElementEvicted();
308         }
309     }
310 
311     /***
312      * {@inheritDoc}
313      */
314     public void notifyElementExpired(Ehcache cache, Element element) {
315         if (!statisticsEnabled.get()) {
316             return;
317         }
318         cacheElementExpired.incrementAndGet();
319         for (CacheUsageListener l : listeners) {
320             l.notifyCacheElementExpired();
321         }
322     }
323 
324     /***
325      * {@inheritDoc}
326      */
327     public void notifyElementPut(Ehcache cache, Element element) throws CacheException {
328         if (!statisticsEnabled.get()) {
329             return;
330         }
331         cacheElementPut.incrementAndGet();
332         for (CacheUsageListener l : listeners) {
333             l.notifyCacheElementPut();
334         }
335     }
336 
337     /***
338      * {@inheritDoc}
339      */
340     public void notifyElementRemoved(Ehcache cache, Element element) throws CacheException {
341         if (!statisticsEnabled.get()) {
342             return;
343         }
344         cacheElementRemoved.incrementAndGet();
345         for (CacheUsageListener l : listeners) {
346             l.notifyCacheElementRemoved();
347         }
348     }
349 
350     /***
351      * {@inheritDoc}
352      */
353     public void notifyElementUpdated(Ehcache cache, Element element) throws CacheException {
354         if (!statisticsEnabled.get()) {
355             return;
356         }
357         cacheElementUpdated.incrementAndGet();
358         for (CacheUsageListener l : listeners) {
359             l.notifyCacheElementUpdated();
360         }
361     }
362 
363     /***
364      * {@inheritDoc}
365      */
366     public void notifyRemoveAll(Ehcache cache) {
367         if (!statisticsEnabled.get()) {
368             return;
369         }
370         for (CacheUsageListener l : listeners) {
371             l.notifyRemoveAll();
372         }
373     }
374 
375     /***
376      * {@inheritDoc}
377      */
378     @Override
379     public Object clone() throws CloneNotSupportedException {
380         // to shut up check-style, why do we need this ?
381         super.clone();
382         throw new CloneNotSupportedException();
383     }
384 
385     /***
386      * {@inheritDoc}
387      */
388     public float getAverageGetTimeMillis() {
389         long accessCount = getCacheHitCount() + getCacheMissCount();
390         if (accessCount == 0) {
391             return 0f;
392         }
393         return (float) totalGetTimeTakenMillis.get() / accessCount;
394     }
395 
396     /***
397      * {@inheritDoc}
398      */
399     public void registerCacheUsageListener(CacheUsageListener cacheUsageListener) throws IllegalStateException {
400         if (!isStatisticsEnabled()) {
401             LOG.warn("Registering a CacheUsageListener on {} whose statistics are currently disabled.  "
402                     + "No events will be fired until statistics are enabled.", cache.getName());
403         }
404         listeners.add(cacheUsageListener);
405     }
406 
407     /***
408      * {@inheritDoc}
409      */
410     public void removeCacheUsageListener(CacheUsageListener cacheUsageListener) throws IllegalStateException {
411         listeners.remove(cacheUsageListener);
412     }
413 
414     /***
415      * {@inheritDoc}
416      */
417     public long getCacheHitCount() {
418         return cacheHitInMemoryCount.get() + cacheHitOffHeapCount.get() + cacheHitOnDiskCount.get();
419     }
420 
421     /***
422      * {@inheritDoc}
423      */
424     public long getCacheMissCount() {
425         return cacheMissNotFound.get() + cacheMissExpired.get();
426     }
427 
428     /***
429      * {@inheritDoc}
430      */
431     public long getInMemoryMissCount() {
432         return cacheMissInMemoryCount.get();
433     }
434 
435     /***
436      * {@inheritDoc}
437      */
438     public long getOffHeapMissCount() {
439         return cacheMissOffHeapCount.get();
440     }
441 
442     /***
443      * {@inheritDoc}
444      */
445     public long getOnDiskMissCount() {
446         return cacheMissOnDiskCount.get();
447     }
448 
449 
450     /***
451      * {@inheritDoc}
452      */
453     public long getCacheMissCountExpired() {
454         return cacheMissExpired.get();
455     }
456 
457     /***
458      * {@inheritDoc}
459      */
460     public long getEvictedCount() {
461         return cacheElementEvictedCount.get();
462     }
463 
464     /***
465      * {@inheritDoc}
466      */
467     public long getInMemoryHitCount() {
468         return cacheHitInMemoryCount.get();
469     }
470 
471     /***
472      * {@inheritDoc}
473      */
474     public long getOffHeapHitCount() {
475         return cacheHitOffHeapCount.get();
476     }
477 
478     /***
479      * {@inheritDoc}
480      */
481     public long getOnDiskHitCount() {
482         return cacheHitOnDiskCount.get();
483     }
484 
485     /***
486      * {@inheritDoc}
487      */
488     public long getSize() {
489         if (!statisticsEnabled.get()) {
490             return 0;
491         }
492         return cache.getSizeBasedOnAccuracy(statisticsAccuracy.get());
493     }
494 
495     /***
496      * {@inheritDoc}
497      * @deprecated see {@link #getLocalHeapSize()}
498      */
499     @Deprecated
500     public long getInMemorySize() {
501         return getLocalHeapSize();
502     }
503 
504     /***
505      * {@inheritDoc}
506      * @deprecated see {@link #getLocalOffHeapSize()}
507      */
508     @Deprecated
509     public long getOffHeapSize() {
510         return getLocalOffHeapSize();
511     }
512 
513     /***
514      * {@inheritDoc}
515      * @deprecated see {@link #getLocalDiskSize()}
516      */
517     @Deprecated
518     public long getOnDiskSize() {
519         return getLocalDiskSize();
520     }
521 
522     /***
523      * {@inheritDoc}
524      */
525     public long getLocalHeapSize() {
526         if (!statisticsEnabled.get()) {
527             return 0;
528         }
529         return cache.getMemoryStoreSize();
530     }
531 
532     /***
533      * {@inheritDoc}
534      */
535     public long getLocalOffHeapSize() {
536         if (!statisticsEnabled.get()) {
537             return 0;
538         }
539         return cache.getOffHeapStoreSize();
540     }
541 
542     /***
543      * {@inheritDoc}
544      */
545     public long getLocalDiskSize() {
546         if (!statisticsEnabled.get()) {
547             return 0;
548         }
549         return cache.getDiskStoreSize();
550     }
551 
552     /***
553      * {@inheritDoc}
554      */
555     public long getLocalDiskSizeInBytes() {
556         if (!statisticsEnabled.get()) {
557             return 0;
558         }
559         return cache.calculateOnDiskSize();
560     }
561 
562     /***
563      * {@inheritDoc}
564      */
565     public long getLocalHeapSizeInBytes() {
566         if (!statisticsEnabled.get()) {
567             return 0;
568         }
569         return cache.calculateInMemorySize();
570     }
571 
572     /***
573      * {@inheritDoc}
574      */
575     public long getLocalOffHeapSizeInBytes() {
576         if (!statisticsEnabled.get()) {
577             return 0;
578         }
579         return cache.calculateOffHeapSize();
580     }
581 
582 
583     /***
584      * {@inheritDoc}
585      */
586     public String getCacheName() {
587         return cache.getName();
588     }
589 
590     /***
591      * {@inheritDoc}
592      */
593     public int getStatisticsAccuracy() {
594         return statisticsAccuracy.get();
595     }
596 
597     /***
598      * {@inheritDoc}
599      */
600     public long getExpiredCount() {
601         return cacheElementExpired.get();
602     }
603 
604     /***
605      * {@inheritDoc}
606      */
607     public long getPutCount() {
608         return cacheElementPut.get();
609     }
610 
611     /***
612      * {@inheritDoc}
613      */
614     public long getRemovedCount() {
615         return cacheElementRemoved.get();
616     }
617 
618     /***
619      * {@inheritDoc}
620      */
621     public long getUpdateCount() {
622         return cacheElementUpdated.get();
623     }
624 
625     /***
626      * {@inheritDoc}
627      */
628     public String getStatisticsAccuracyDescription() {
629         int value = statisticsAccuracy.get();
630         if (value == 0) {
631             return "None";
632         } else if (value == 1) {
633             return "Best Effort";
634         } else {
635             return "Guaranteed";
636         }
637     }
638 
639     /***
640      * {@inheritDoc}
641      *
642      * @see net.sf.ehcache.statistics.LiveCacheStatistics#getMaxGetTimeMillis()
643      */
644     public long getMaxGetTimeMillis() {
645         return maxGetTimeMillis.get();
646     }
647 
648     /***
649      * {@inheritDoc}
650      *
651      * @see net.sf.ehcache.statistics.LiveCacheStatistics#getXaCommitCount()
652      */
653     public long getXaCommitCount() {
654         return xaCommitCount.get();
655     }
656 
657     /***
658      * {@inheritDoc}
659      *
660      * @see net.sf.ehcache.statistics.LiveCacheStatistics#getXaRollbackCount()
661      */
662     public long getXaRollbackCount() {
663         return xaRollbackCount.get();
664     }
665 
666     /***
667      * {@inheritDoc}
668      */
669     public long getWriterQueueLength() {
670         long length = -1;
671         CacheWriterManager writerManager = cache.getWriterManager();
672         if (writerManager instanceof WriteBehindManager) {
673             length = ((WriteBehindManager)writerManager).getQueueSize();
674         }
675         return length;
676     }
677 
678     /***
679      * {@inheritDoc}
680      *
681      * @see net.sf.ehcache.statistics.LiveCacheStatistics#getMinGetTimeMillis()
682      */
683     public long getMinGetTimeMillis() {
684         return minGetTimeMillis.get();
685     }
686 }