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()
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
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 }