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
17 package net.sf.ehcache.management;
18
19 import net.sf.ehcache.CacheException;
20 import net.sf.ehcache.Ehcache;
21 import net.sf.ehcache.Statistics;
22 import net.sf.ehcache.hibernate.management.impl.EhcacheHibernateMbeanNames;
23
24 import javax.management.MalformedObjectNameException;
25 import javax.management.ObjectName;
26
27 import java.io.Serializable;
28
29
30 /***
31 * A JMX CacheStatistics decorator for an ehcache Statistics class.
32 * <p/>
33 * An immutable Cache statistics implementation}
34 * <p/>
35 * This is like a value object, with the added ability to clear cache statistics on the cache.
36 * That ability does not survive any Serialization of this class. On deserialization the cache
37 * can be considered disconnected.
38 * <p/>
39 * The accuracy of these statistics are determined by the value of {#getStatisticsAccuracy()}
40 * at the time the statistic was computed. This can be changed by setting {@link net.sf.ehcache.Cache#setStatisticsAccuracy}.
41 * <p/>
42 * Because this class maintains a reference to an Ehcache, any references held to this class will precent the Ehcache
43 * from getting garbage collected.
44 *
45 * @author Greg Luck
46 * @version $Id: CacheStatistics.html 13146 2011-08-01 17:12:39Z oletizi $
47 * @since 1.3
48 */
49 public class CacheStatistics implements CacheStatisticsMBean, Serializable {
50
51 private static final long serialVersionUID = 8085302752781762030L;
52
53 private transient Ehcache ehcache;
54 private Statistics statistics;
55
56 private final ObjectName objectName;
57 private long lastUpdated;
58
59 /***
60 * Constructs an object from an ehcache statistics object
61 *
62 * @param ehcache the backing ehcache
63 */
64 public CacheStatistics(Ehcache ehcache) {
65 this.ehcache = ehcache;
66 objectName = createObjectName(ehcache.getCacheManager().getName(),
67 ehcache.getName());
68 }
69
70 /***
71 * Creates an object name using the scheme "net.sf.ehcache:type=CacheStatistics,CacheManager=<cacheManagerName>,name=<cacheName>"
72 */
73 static ObjectName createObjectName(String cacheManagerName, String cacheName) {
74 ObjectName objectName;
75 try {
76 objectName = new ObjectName("net.sf.ehcache:type=CacheStatistics,CacheManager=" + cacheManagerName + ",name="
77 + EhcacheHibernateMbeanNames.mbeanSafe(cacheName));
78 } catch (MalformedObjectNameException e) {
79 throw new CacheException(e);
80 }
81 return objectName;
82 }
83
84 /***
85 * Accurately measuring statistics can be expensive. Returns the current accuracy setting used
86 * in the creation of these statistics.
87 *
88 * @return one of {@link Statistics#STATISTICS_ACCURACY_BEST_EFFORT}, {@link Statistics#STATISTICS_ACCURACY_GUARANTEED}, {@link Statistics#STATISTICS_ACCURACY_NONE}
89 */
90 public int getStatisticsAccuracy() {
91 updateIfNeeded();
92 return statistics.getStatisticsAccuracy();
93 }
94
95 private void updateIfNeeded() {
96 if (System.currentTimeMillis() != lastUpdated) {
97 statistics = ehcache.getStatistics();
98 lastUpdated = System.currentTimeMillis();
99 }
100 }
101
102 /***
103 * Accurately measuring statistics can be expensive. Returns the current accuracy setting.
104 *
105 * @return a human readable description of the accuracy setting. One of "None", "Best Effort" or "Guaranteed".
106 */
107 public String getStatisticsAccuracyDescription() {
108 updateIfNeeded();
109 return statistics.getStatisticsAccuracyDescription();
110 }
111
112 /***
113 * @return the name of the Ehcache, or null is there no associated cache
114 */
115 public String getAssociatedCacheName() {
116 if (statistics == null) {
117 return null;
118 } else {
119 return statistics.getAssociatedCacheName();
120 }
121 }
122
123 /***
124 * Clears the statistic counters to 0 for the associated Cache.
125 */
126 public void clearStatistics() {
127 statistics.clearStatistics();
128 }
129
130 /***
131 * The number of times a requested item was found in the cache.
132 * <p/>
133 * Warning. This statistic is recorded as a long. If the statistic is large than Integer#MAX_VALUE
134 * precision will be lost.
135 *
136 * @return the number of times a requested item was found in the cache
137 */
138 public long getCacheHits() {
139 updateIfNeeded();
140 return statistics.getCacheHits();
141 }
142
143 /***
144 * Number of times a requested item was found in the Memory Store.
145 *
146 * @return the number of times a requested item was found in memory
147 */
148 public long getInMemoryHits() {
149 updateIfNeeded();
150 return statistics.getInMemoryHits();
151 }
152
153 /***
154 * Number of times a requested item was found in the off-heap store.
155 *
156 * @return the number of times a requested item was found in off-heap
157 */
158 public long getOffHeapHits() {
159 updateIfNeeded();
160 return statistics.getOffHeapHits();
161 }
162
163 /***
164 * Number of times a requested item was found in the Disk Store.
165 *
166 * @return the number of times a requested item was found on Disk, or 0 if there is no disk storage configured.
167 */
168 public long getOnDiskHits() {
169 updateIfNeeded();
170 return statistics.getOnDiskHits();
171 }
172
173 /***
174 * Warning. This statistic is recorded as a long. If the statistic is large than Integer#MAX_VALUE
175 * precision will be lost.
176 *
177 * @return the number of times a requested element was not found in the cache
178 */
179 public long getCacheMisses() {
180 updateIfNeeded();
181 return statistics.getCacheMisses();
182 }
183
184 /*** {@inheritDoc} */
185 public long getInMemoryMisses() {
186 updateIfNeeded();
187 return statistics.getInMemoryMisses();
188 }
189
190 /*** {@inheritDoc} */
191 public long getOffHeapMisses() {
192 updateIfNeeded();
193 return statistics.getOffHeapMisses();
194 }
195
196 /*** {@inheritDoc} */
197 public long getOnDiskMisses() {
198 updateIfNeeded();
199 return statistics.getOnDiskMisses();
200 }
201
202 /***
203 * Gets the number of elements stored in the cache. Caclulating this can be expensive. Accordingly,
204 * this method will return three different values, depending on the statistics accuracy setting.
205 * <h3>Best Effort Size</h3>
206 * This result is returned when the statistics accuracy setting is {@link net.sf.ehcache.Statistics#STATISTICS_ACCURACY_BEST_EFFORT}.
207 * <p/>
208 * The size is the number of {@link net.sf.ehcache.Element}s in the {@link net.sf.ehcache.store.MemoryStore} plus
209 * the number of {@link net.sf.ehcache.Element}s in the {@link net.sf.ehcache.store.disk.DiskStore}.
210 * <p/>
211 * This number is the actual number of elements, including expired elements that have
212 * not been removed. Any duplicates between stores are accounted for.
213 * <p/>
214 * Expired elements are removed from the the memory store when
215 * getting an expired element, or when attempting to spool an expired element to
216 * disk.
217 * <p/>
218 * Expired elements are removed from the disk store when getting an expired element,
219 * or when the expiry thread runs, which is once every five minutes.
220 * <p/>
221 * <h3>Guaranteed Accuracy Size</h3>
222 * This result is returned when the statistics accuracy setting is {@link net.sf.ehcache.Statistics#STATISTICS_ACCURACY_GUARANTEED}.
223 * <p/>
224 * This method accounts for elements which might be expired or duplicated between stores. It take approximately
225 * 200ms per 1000 elements to execute.
226 * <h3>Fast but non-accurate Size</h3>
227 * This result is returned when the statistics accuracy setting is {@link Statistics#STATISTICS_ACCURACY_NONE}.
228 * <p/>
229 * The number given may contain expired elements. In addition if the DiskStore is used it may contain some double
230 * counting of elements. It takes 6ms for 1000 elements to execute. Time to execute is O(log n). 50,000 elements take
231 * 36ms.
232 *
233 * @return the number of elements in the ehcache, with a varying degree of accuracy, depending on accuracy setting.
234 */
235 public long getObjectCount() {
236 updateIfNeeded();
237 return statistics.getObjectCount();
238 }
239
240 /***
241 * Gets the size of the write-behind queue, if any.
242 * The value is for all local buckets
243 * @return Elements waiting to be processed by the write behind writer. -1 if no write-behind
244 */
245 public long getWriterQueueLength() {
246 updateIfNeeded();
247 return statistics.getWriterQueueSize();
248 }
249
250 /***
251 * {@inheritDoc}
252 */
253 public int getWriterMaxQueueSize() {
254 return ehcache.getCacheConfiguration().getCacheWriterConfiguration().getWriteBehindMaxQueueSize();
255 }
256
257 /***
258 * Gets the number of objects in the MemoryStore
259 * @return the MemoryStore size which is always a count unadjusted for duplicates or expiries
260 */
261 public long getMemoryStoreObjectCount() {
262 updateIfNeeded();
263 return statistics.getMemoryStoreObjectCount();
264 }
265
266 /***
267 * {@inheritDoc}
268 */
269 public long getOffHeapStoreObjectCount() {
270 updateIfNeeded();
271 return statistics.getOffHeapStoreObjectCount();
272 }
273
274 /***
275 * Gets the number of objects in the DiskStore
276 * @return the DiskStore size which is always a count unadjusted for duplicates or expiries
277 */
278 public long getDiskStoreObjectCount() {
279 updateIfNeeded();
280 return statistics.getDiskStoreObjectCount();
281 }
282
283
284 /***
285 * @return the object name for this MBean
286 */
287 ObjectName getObjectName() {
288 return objectName;
289 }
290
291 /***
292 * Return the backing cache.
293 * @return the backing cache, if one is connected. On Serialization
294 * the transient Ehcache reference is dropped.
295 */
296 public Ehcache getEhcache() {
297 return ehcache;
298 }
299
300 private static double getPercentage(long number, long total) {
301 if (total == 0) {
302 return 0.0;
303 } else {
304 return number / (double)total;
305 }
306 }
307
308 /***
309 * {@inheritDoc}
310 */
311 public double getCacheHitPercentage() {
312 updateIfNeeded();
313 long hits = statistics.getCacheHits();
314 long misses = statistics.getCacheMisses();
315
316 long total = hits + misses;
317 return getPercentage(hits, total);
318 }
319
320 /***
321 * {@inheritDoc}
322 */
323 public double getCacheMissPercentage() {
324 updateIfNeeded();
325 long hits = statistics.getCacheHits();
326 long misses = statistics.getCacheMisses();
327
328 long total = hits + misses;
329 return getPercentage(misses, total);
330 }
331
332 /***
333 * {@inheritDoc}
334 */
335 public double getInMemoryHitPercentage() {
336 updateIfNeeded();
337 long hits = statistics.getInMemoryHits();
338 long misses = statistics.getInMemoryMisses();
339
340 long total = hits + misses;
341 return getPercentage(hits, total);
342 }
343
344 /***
345 * {@inheritDoc}
346 */
347 public double getOffHeapHitPercentage() {
348 updateIfNeeded();
349 long hits = statistics.getOffHeapHits();
350 long misses = statistics.getOffHeapMisses();
351
352 long total = hits + misses;
353 return getPercentage(hits, total);
354 }
355
356 /***
357 * {@inheritDoc}
358 */
359 public double getOnDiskHitPercentage() {
360 updateIfNeeded();
361 long hits = statistics.getOnDiskHits();
362 long misses = statistics.getOnDiskMisses();
363
364 long total = hits + misses;
365 return getPercentage(hits, total);
366 }
367 }