1 /**
2  *  Copyright 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
17 package net.sf.ehcache;
18
19 import java.io.Serializable;
20
21 /**
22  * An immutable Cache statistics implementation
23  * <p/>
24  * This is like a value object, with the added ability to clear cache statistics on the cache.
25  * That ability does not survive any Serialization of this class. On deserialization the cache
26  * can be considered disconnected.
27  * <p/>
28  * The accuracy of these statistics are determined by the value of {@link Cache#getStatisticsAccuracy()}
29  * at the time the statistic was computed. This can be changed by setting {@link Cache#setStatisticsAccuracy}.
30  * <p/>
31  * Because this class maintains a reference to an Ehcache, any references held to this class will prevent the Ehcache
32  * from getting garbage collected.
33  * <p/>
34  * todo Add missCountExpired. Request from user.
35  *
36  * @author Greg Luck
37  * @version $Id: Statistics.java 5631 2012-05-10 08:31:33Z teck $
38  */

39 public class Statistics implements Serializable {
40
41     /**
42      * Fast but not accurate setting.
43      */

44     public static final int STATISTICS_ACCURACY_NONE = 0;
45
46     /**
47      * Best efforts accuracy setting.
48      */

49     public static final int STATISTICS_ACCURACY_BEST_EFFORT = 1;
50
51     /**
52      * Guaranteed accuracy setting.
53      */

54     public static final int STATISTICS_ACCURACY_GUARANTEED = 2;
55
56     private static final long serialVersionUID = 3606940454221918725L;
57
58     private transient Ehcache cache;
59
60     private final String cacheName;
61
62     private final int statisticsAccuracy;
63
64     private final long cacheHits;
65
66     private final long onDiskHits;
67
68     private final long offHeapHits;
69
70     private final long inMemoryHits;
71
72     private final long misses;
73
74     private final long onDiskMisses;
75
76     private final long offHeapMisses;
77
78     private final long inMemoryMisses;
79
80     private final long size;
81
82     private final long memoryStoreSize;
83
84     private final long offHeapStoreSize;
85
86     private final long diskStoreSize;
87
88     private final float averageGetTime;
89
90     private final long evictionCount;
91
92     private final long searchesPerSecond;
93
94     private final long averageSearchTime;
95     
96     private long writerQueueLength;
97
98
99     /**
100      * Creates a new statistics object, associated with a Cache
101      *
102      * @param cache              The cache that {@link #clearStatistics()} will call, if not disconnected
103      * @param statisticsAccuracy
104      * @param cacheHits
105      * @param onDiskHits
106      * @param offHeapHits
107      * @param inMemoryHits
108      * @param misses
109      * @param size
110      */

111     public Statistics(Ehcache cache, int statisticsAccuracy, long cacheHits, long onDiskHits, long offHeapHits,
112                       long inMemoryHits, long misses, long onDiskMisses, long offHeapMisses,
113                       long inMemoryMisses, long size, float averageGetTime, long evictionCount,
114                       long memoryStoreSize, long offHeapStoreSize, long diskStoreSize, long searchesPerSecond,
115                       long averageSearchTime, long writerQueueLength) {
116         this.cacheName = cache.getName();
117         this.statisticsAccuracy = statisticsAccuracy;
118         this.cacheHits = cacheHits;
119         this.onDiskHits = onDiskHits;
120         this.offHeapHits = offHeapHits;
121         this.inMemoryHits = inMemoryHits;
122         this.misses = misses;
123         this.onDiskMisses = onDiskMisses;
124         this.offHeapMisses = offHeapMisses;
125         this.inMemoryMisses = inMemoryMisses;
126         this.cache = cache;
127         this.size = size;
128         this.averageGetTime = averageGetTime;
129         this.evictionCount = evictionCount;
130         this.memoryStoreSize = memoryStoreSize;
131         this.offHeapStoreSize = offHeapStoreSize;
132         this.diskStoreSize = diskStoreSize;
133         this.searchesPerSecond = searchesPerSecond;
134         this.averageSearchTime = averageSearchTime;
135         this.writerQueueLength = writerQueueLength;
136     }
137
138
139     /**
140      * Clears the statistic counters to 0 for the associated Cache.
141      */

142     public void clearStatistics() {
143         if (cache == null) {
144             throw new IllegalStateException("This statistics object no longer references a Cache.");
145         }
146         cache.clearStatistics();
147     }
148
149     /**
150      * The number of times a requested item was found in the cache.
151      *
152      * @return the number of times a requested item was found in the cache
153      */

154     public long getCacheHits() {
155         return cacheHits;
156     }
157
158     /**
159      * Number of times a requested item was found in the Memory Store.
160      *
161      * @return the number of times a requested item was found in memory
162      */

163     public long getInMemoryHits() {
164         return inMemoryHits;
165     }
166
167     /**
168      * Number of times a requested item was found in the off-heap store.
169      *
170      * @return the number of times a requested item was found in off-heap
171      */

172     public long getOffHeapHits() {
173         return offHeapHits;
174     }
175
176     /**
177      * Number of times a requested item was found in the Disk Store.
178      *
179      * @return the number of times a requested item was found on Disk, or 0 if there is no disk storage configured.
180      */

181     public long getOnDiskHits() {
182         return onDiskHits;
183     }
184
185     /**
186      * @return the number of times a requested element was not found in the cache
187      */

188     public long getCacheMisses() {
189         return misses;
190
191     }
192
193     /**
194      * Number of times a requested item was not found in the Memory Store.
195      *
196      * @return the number of times a requested item was not found in memory
197      */

198     public long getInMemoryMisses() {
199         return inMemoryMisses;
200     }
201
202     /**
203      * Number of times a requested item was not found in the off-heap store.
204      *
205      * @return the number of times a requested item was not found in off-heap
206      */

207     public long getOffHeapMisses() {
208         return offHeapMisses;
209     }
210
211     /**
212      * Number of times a requested item was not found in the Disk Store.
213      *
214      * @return the number of times a requested item was not found on Disk, or 0 if there is no disk storage configured.
215      */

216     public long getOnDiskMisses() {
217         return onDiskMisses;
218     }
219
220     /**
221      * Gets the number of elements stored in the cache. Caclulating this can be expensive. Accordingly,
222      * this method will return three different values, depending on the statistics accuracy setting.
223      * <h3>Best Effort Size</h3>
224      * This result is returned when the statistics accuracy setting is {@link Statistics#STATISTICS_ACCURACY_BEST_EFFORT}.
225      * <p/>
226      * The size is the number of {@link Element}s in the {@link net.sf.ehcache.store.MemoryStore} plus
227      * the number of {@link Element}s in the {@link net.sf.ehcache.store.disk.DiskStore}.
228      * <p/>
229      * This number is the actual number of elements, including expired elements that have
230      * not been removed. Any duplicates between stores are accounted for.
231      * <p/>
232      * Expired elements are removed from the the memory store when
233      * getting an expired element, or when attempting to spool an expired element to
234      * disk.
235      * <p/>
236      * Expired elements are removed from the disk store when getting an expired element,
237      * or when the expiry thread runs, which is once every five minutes.
238      * <p/>
239      * <h3>Guaranteed Accuracy Size</h3>
240      * This result is returned when the statistics accuracy setting is {@link Statistics#STATISTICS_ACCURACY_GUARANTEED}.
241      * <p/>
242      * This method accounts for elements which might be expired or duplicated between stores. It take approximately
243      * 200ms per 1000 elements to execute.
244      * <h3>Fast but non-accurate Size</h3>
245      * This result is returned when the statistics accuracy setting is {@link #STATISTICS_ACCURACY_NONE}.
246      * <p/>
247      * The number given may contain expired elements. In addition if the DiskStore is used it may contain some double
248      * counting of elements. It takes 6ms for 1000 elements to execute. Time to execute is O(log n). 50,000 elements take
249      * 36ms.
250      *
251      * @return the number of elements in the ehcache, with a varying degree of accuracy, depending on accuracy setting.
252      */

253     public long getObjectCount() {
254         return size;
255     }
256
257     /**
258      *
259      * @return the number of objects in the memory store
260      */

261     public long getMemoryStoreObjectCount() {
262         return memoryStoreSize;
263     }
264
265     /**
266      *
267      * @return the number of objects in the off-heap store
268      */

269     public long getOffHeapStoreObjectCount() {
270         return offHeapStoreSize;
271     }
272
273     /**
274      *
275      * @return the number of objects in the disk store
276      */

277     public long getDiskStoreObjectCount() {
278         return diskStoreSize;
279     }
280
281     /**
282      * Accurately measuring statistics can be expensive. Returns the current accuracy setting.
283      *
284      * @return one of {@link #STATISTICS_ACCURACY_BEST_EFFORT}, {@link #STATISTICS_ACCURACY_GUARANTEED}, {@link #STATISTICS_ACCURACY_NONE}
285      */

286     public int getStatisticsAccuracy() {
287         return statisticsAccuracy;
288     }
289
290     /**
291      * Accurately measuring statistics can be expensive. Returns the current accuracy setting.
292      *
293      * @return a human readable description of the accuracy setting. One of "None""Best Effort" or "Guaranteed".
294      */

295     public String getStatisticsAccuracyDescription() {
296         if (statisticsAccuracy == 0) {
297             return "None";
298         } else if (statisticsAccuracy == 1) {
299             return "Best Effort";
300         } else {
301             return "Guaranteed";
302         }
303     }
304
305     /**
306      * @return the name of the Ehcache, or null if a reference is no longer held to the cache,
307      *         as, it would be after deserialization.
308      */

309     public String getAssociatedCacheName() {
310         if (cache != null) {
311             return cache.getName();
312         } else {
313             return cacheName;
314         }
315     }
316
317     /**
318      * @return the name of the Ehcache, or null if a reference is no longer held to the cache,
319      *         as, it would be after deserialization.
320      */

321     public Ehcache getAssociatedCache() {
322         if (cache != null) {
323             return cache;
324         } else {
325             return null;
326         }
327     }
328
329     /**
330      * Returns a {@link String} representation of the {@link Ehcache} statistics.
331      */

332     @Override
333     public final String toString() {
334         StringBuilder dump = new StringBuilder();
335
336         dump.append("[ ")
337                 .append(" name = ").append(getAssociatedCacheName())
338                 .append(" cacheHits = ").append(cacheHits)
339                 .append(" onDiskHits = ").append(onDiskHits)
340                 .append(" offHeapHits = ").append(offHeapHits)
341                 .append(" inMemoryHits = ").append(inMemoryHits)
342                 .append(" misses = ").append(misses)
343                 .append(" onDiskMisses = ").append(onDiskMisses)
344                 .append(" offHeapMisses = ").append(offHeapMisses)
345                 .append(" inMemoryMisses = ").append(inMemoryMisses)
346                 .append(" size = ").append(size)
347                 .append(" averageGetTime = ").append(averageGetTime)
348                 .append(" evictionCount = ").append(evictionCount)
349                 .append(" ]");
350
351         return dump.toString();
352     }
353
354     /**
355      * The average get time. Because ehcache support JDK1.4.2, each get time uses
356      * System.currentTimeMilis, rather than nanoseconds. The accuracy is thus limited.
357      */

358     public float getAverageGetTime() {
359         return averageGetTime;
360     }
361
362     /**
363      * Gets the number of cache evictions, since the cache was created, or statistics were cleared.
364      */

365     public long getEvictionCount() {
366         return evictionCount;
367     }
368
369     /**
370      * Gets the average execution time (in milliseconds) within the last sample period
371      */

372     public long getAverageSearchTime() {
373         return averageSearchTime;
374     }
375
376     /**
377      * Get the number of search executions that have completed in the last second
378      */

379     public long getSearchesPerSecond() {
380         return searchesPerSecond;
381     }
382
383     /**
384      * Utility method to determine if a given value is a valid statistics
385      * accuracy value or not
386      *
387      * @param statisticsAccuracy
388      * @return true if the value is one of
389      *         {@link Statistics#STATISTICS_ACCURACY_BEST_EFFORT},
390      *         {@link Statistics#STATISTICS_ACCURACY_GUARANTEED},
391      *         {@link Statistics#STATISTICS_ACCURACY_NONE}
392      */

393     public static boolean isValidStatisticsAccuracy(int statisticsAccuracy) {
394         return statisticsAccuracy == STATISTICS_ACCURACY_NONE
395                 || statisticsAccuracy == STATISTICS_ACCURACY_BEST_EFFORT
396                 || statisticsAccuracy == STATISTICS_ACCURACY_GUARANTEED;
397     }
398
399     /**
400      * Gets the size of the write-behind queue, if any.
401      * The value is for all local buckets
402      * @return Elements waiting to be processed by the write behind writer. -1 if no write-behind
403      */

404     public long getWriterQueueSize() {
405         return writerQueueLength;
406     }
407 }
408