View Javadoc

1   /**
2    *  Copyright 2003-2007 Greg Luck
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.constructs.blocking;
18  
19  import net.sf.ehcache.CacheException;
20  import net.sf.ehcache.CacheManager;
21  import net.sf.ehcache.Ehcache;
22  import net.sf.ehcache.Element;
23  import net.sf.ehcache.Statistics;
24  import net.sf.ehcache.Status;
25  import net.sf.ehcache.config.CacheConfiguration;
26  import net.sf.ehcache.bootstrap.BootstrapCacheLoader;
27  import net.sf.ehcache.constructs.concurrent.ConcurrencyUtil;
28  import net.sf.ehcache.constructs.concurrent.Mutex;
29  import net.sf.ehcache.event.RegisteredEventListeners;
30  import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  
34  import java.io.Serializable;
35  import java.util.List;
36  
37  
38  /**
39   * A blocking decorator for an Ehcache, backed by a {@link Ehcache}.
40   * <p/>
41   * It allows concurrent read access to elements already in the cache. If the element is null, other
42   * reads will block until an element with the same key is put into the cache.
43   * <p/>
44   * This is useful for constructing read-through or self-populating caches.
45   * <p/>
46   * This implementation uses the {@link Mutex} class from Doug Lea's concurrency package. If you wish to use
47   * this class, you will need the concurrent package in your class path.
48   * <p/>
49   * It features:
50   * <ul>
51   * <li>Excellent liveness.
52   * <li>Fine-grained locking on each element, rather than the cache as a whole.
53   * <li>Scalability to a large number of threads.
54   * </ul>
55   * <p/>
56   * This class has been updated to use Lock striping. The Mutex implementation gives scalability but creates
57   * many Mutex objects of 24 bytes each. Lock striping limits their number to 100.
58   * <p/>
59   * A version of this class is planned which will dynamically use JDK5's concurrency package, which is
60   * based on Doug Lea's, so as to avoid a dependency on his package for JDK5 systems. This will not
61   * be implemented until JDK5 is released on MacOSX and Linux, as JDK5 will be required to compile
62   * it, though any version from JDK1.2 up will be able to run the code, falling back to Doug
63   * Lea's concurrency package, if the JDK5 package is not found in the classpath.
64   * <p/>
65   * The <code>Mutex</code> class does not appear in the JDK5 concurrency package. Doug Lea has
66   * generously offered the following advice:
67   * <p/>
68   * "You should just be able to use ReentrantLock here.  We supply
69   * ReentrantLock, but not Mutex because the number of cases where a
70   * non-reentrant mutex is preferable is small, and most people are more
71   * familiar with reentrant seamantics. If you really need a non-reentrant
72   * one, the javadocs for class AbstractQueuedSynchronizer include sample
73   * code for them."
74   * <p/>
75   * -Doug
76   * <p/>
77   * "Hashtable / synchronizedMap uses the "one big fat lock" approach to guard the mutable state of the map.
78   * That works, but is a big concurrency bottleneck, as you've observed.  You went to the opposite extreme, one lock per key.
79   * That works (as long as you've got sufficient synchronization in the cache itself to protect its own data structures.)
80   * <p/>
81   * Lock striping is a middle ground, partitioning keys into a fixed number of subsets, like the trick used at large
82   * theaters for will-call ticket pickup -- there are separate lines for "A-F, G-M, N-R, and S-Z".
83   * This way, there are a fixed number of locks, each guarding (hopefully) 1/Nth of the keys."
84   * - Brian Goetz
85   * <p/>
86   * Further improvements to hashing suggested by Joe Bowbeer.
87   *
88   * @author Greg Luck
89   * @version $Id: BlockingCache.java 512 2007-07-10 09:18:45Z gregluck $
90   */
91  public class BlockingCache implements Ehcache {
92  
93      /**
94       * The default number of locks to use. Must be a power of 2
95       */
96      public static final int LOCK_NUMBER = 2048;
97  
98      private static final Log LOG = LogFactory.getLog(BlockingCache.class.getName());
99  
100     /**
101      * Based on the lock striping concept from Brian Goetz. See Java Concurrency in Practice 11.4.3
102      */
103     protected final Mutex[] locks = new Mutex[LOCK_NUMBER];
104 
105     {
106         for (int i = 0; i < LOCK_NUMBER; i++) {
107             locks[i] = new Mutex();
108         }
109     }
110 
111 
112     /**
113      * The backing Cache
114      */
115     protected final Ehcache cache;
116 
117     /**
118      * The amount of time to block a thread before a LockTimeoutException is thrown
119      */
120     protected int timeoutMillis;
121 
122     /**
123      * Creates a BlockingCache which decorates the supplied cache.
124      *
125      * @param cache a backing ehcache.
126      * @throws CacheException
127      * @since 1.2
128      */
129     public BlockingCache(final Ehcache cache) throws CacheException {
130         this.cache = cache;
131     }
132 
133     /**
134      * Retrieve the EHCache backing cache
135      */
136     protected Ehcache getCache() {
137         return cache;
138     }
139 
140     /**
141      * Returns this cache's name
142      */
143     public String getName() {
144         return cache.getName();
145     }
146 
147     /**
148      * Sets the cache name which will name.
149      *
150      * @param name the name of the cache. Should not be null.
151      */
152     public void setName(String name) {
153         cache.setName(name);
154     }
155 
156     /**
157      * Gets timeToIdleSeconds.
158      */
159     public long getTimeToIdleSeconds() {
160         return cache.getTimeToIdleSeconds();
161     }
162 
163     /**
164      * Gets timeToLiveSeconds.
165      */
166     public long getTimeToLiveSeconds() {
167         return cache.getTimeToLiveSeconds();
168     }
169 
170     /**
171      * Are elements eternal.
172      */
173     public boolean isEternal() {
174         return cache.isEternal();
175     }
176 
177     /**
178      * Does the overflow go to disk.
179      */
180     public boolean isOverflowToDisk() {
181         return cache.isOverflowToDisk();
182     }
183 
184     /**
185      * Gets the maximum number of elements to hold in memory.
186      */
187     public int getMaxElementsInMemory() {
188         return cache.getMaxElementsInMemory();
189     }
190 
191     /**
192      * @return the maximum number of elements on Disk, or 0 if unlimited
193      * @see net.sf.ehcache.Cache#getMaxElementsOnDisk
194      */
195     public int getMaxElementsOnDisk() {
196         return cache.getMaxElementsOnDisk();
197     }
198 
199     /**
200      * The policy used to evict elements from the {@link net.sf.ehcache.store.MemoryStore}.
201      * This can be one of:
202      * <ol>
203      * <li>LRU - least recently used
204      * <li>LFU - least frequently used
205      * <li>FIFO - first in first out, the oldest element by creation time
206      * </ol>
207      * The default value is LRU
208      *
209      * @since 1.2
210      */
211     public MemoryStoreEvictionPolicy getMemoryStoreEvictionPolicy() {
212         return cache.getMemoryStoreEvictionPolicy();
213     }
214 
215     /**
216      * Checks whether this cache element has expired.
217      * <p/>
218      * The element is expired if:
219      * <ol>
220      * <li> the idle time is non-zero and has elapsed, unless the cache is eternal; or
221      * <li> the time to live is non-zero and has elapsed, unless the cache is eternal; or
222      * <li> the value of the element is null.
223      * </ol>
224      *
225      * @return true if it has expired
226      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
227      * @throws NullPointerException  if the element is null
228      */
229     public boolean isExpired(Element element) throws IllegalStateException, NullPointerException {
230         return cache.isExpired(element);
231     }
232 
233     /**
234      * Clones a cache. This is only legal if the cache has not been
235      * initialized. At that point only primitives have been set and no
236      * {@link net.sf.ehcache.store.LruMemoryStore} or {@link net.sf.ehcache.store.DiskStore} has been created.
237      * <p/>
238      * A new, empty, RegisteredEventListeners is created on clone.
239      * <p/>
240      *
241      * @return an object of type {@link net.sf.ehcache.Cache}
242      * @throws CloneNotSupportedException
243      */
244     public Object clone() throws CloneNotSupportedException {
245         return super.clone();
246     }
247 
248     /**
249      * @return true if the cache overflows to disk and the disk is persistent between restarts
250      */
251     public boolean isDiskPersistent() {
252         return cache.isDiskPersistent();
253     }
254 
255     /**
256      * @return the interval between runs
257      *         of the expiry thread, where it checks the disk store for expired elements. It is not the
258      *         the timeToLiveSeconds.
259      */
260     public long getDiskExpiryThreadIntervalSeconds() {
261         return cache.getDiskExpiryThreadIntervalSeconds();
262     }
263 
264     /**
265      * Use this to access the service in order to register and unregister listeners
266      *
267      * @return the RegisteredEventListeners instance for this cache.
268      */
269     public RegisteredEventListeners getCacheEventNotificationService() {
270         return cache.getCacheEventNotificationService();
271     }
272 
273     /**
274      * Whether an Element is stored in the cache in Memory, indicating a very low cost of retrieval.
275      *
276      * @return true if an element matching the key is found in memory
277      */
278     public boolean isElementInMemory(Serializable key) {
279         return cache.isElementInMemory(key);
280     }
281 
282     /**
283      * Whether an Element is stored in the cache in Memory, indicating a very low cost of retrieval.
284      *
285      * @return true if an element matching the key is found in memory
286      * @since 1.2
287      */
288     public boolean isElementInMemory(Object key) {
289         return cache.isElementInMemory(key);
290     }
291 
292     /**
293      * Whether an Element is stored in the cache on Disk, indicating a higher cost of retrieval.
294      *
295      * @return true if an element matching the key is found in the diskStore
296      */
297     public boolean isElementOnDisk(Serializable key) {
298         return cache.isElementOnDisk(key);
299     }
300 
301     /**
302      * Whether an Element is stored in the cache on Disk, indicating a higher cost of retrieval.
303      *
304      * @return true if an element matching the key is found in the diskStore
305      * @since 1.2
306      */
307     public boolean isElementOnDisk(Object key) {
308         return cache.isElementOnDisk(key);
309     }
310 
311     /**
312      * The GUID for this cache instance can be used to determine whether two cache instance references
313      * are pointing to the same cache.
314      *
315      * @return the globally unique identifier for this cache instance. This is guaranteed to be unique.
316      * @since 1.2
317      */
318     public String getGuid() {
319         return cache.getGuid();
320     }
321 
322     /**
323      * Gets the CacheManager managing this cache. For a newly created cache this will be null until
324      * it has been added to a CacheManager.
325      *
326      * @return the manager or null if there is none
327      */
328     public CacheManager getCacheManager() {
329         return cache.getCacheManager();
330     }
331 
332     /**
333      * Resets statistics counters back to 0.
334      */
335     public void clearStatistics() {
336         cache.clearStatistics();
337     }
338 
339     /**
340      * Accurately measuring statistics can be expensive. Returns the current accuracy setting.
341      *
342      * @return one of {@link net.sf.ehcache.Statistics#STATISTICS_ACCURACY_BEST_EFFORT}, {@link net.sf.ehcache.Statistics#STATISTICS_ACCURACY_GUARANTEED}, {@link net.sf.ehcache.Statistics#STATISTICS_ACCURACY_NONE}
343      */
344     public int getStatisticsAccuracy() {
345         return cache.getStatisticsAccuracy();
346     }
347 
348     /**
349      * Sets the statistics accuracy.
350      *
351      * @param statisticsAccuracy one of {@link net.sf.ehcache.Statistics#STATISTICS_ACCURACY_BEST_EFFORT}, {@link net.sf.ehcache.Statistics#STATISTICS_ACCURACY_GUARANTEED}, {@link net.sf.ehcache.Statistics#STATISTICS_ACCURACY_NONE}
352      */
353     public void setStatisticsAccuracy(int statisticsAccuracy) {
354         cache.setStatisticsAccuracy(statisticsAccuracy);
355     }
356 
357     /**
358      * Causes all elements stored in the Cache to be synchronously checked for expiry, and if expired, evicted.
359      */
360     public void evictExpiredElements() {
361         cache.evictExpiredElements();
362     }
363 
364     /**
365      * An inexpensive check to see if the key exists in the cache.
366      *
367      * @param key the key to check for
368      * @return true if an Element matching the key is found in the cache. No assertions are made about the state of the Element.
369      */
370     public boolean isKeyInCache(Object key) {
371         return cache.isKeyInCache(key);
372     }
373 
374     /**
375      * An extremely expensive check to see if the value exists in the cache.
376      *
377      * @param value to check for
378      * @return true if an Element matching the key is found in the cache. No assertions are made about the state of the Element.
379      */
380     public boolean isValueInCache(Object value) {
381         return cache.isValueInCache(value);
382     }
383 
384     /**
385      * Gets an immutable Statistics object representing the Cache statistics at the time. How the statistics are calculated
386      * depends on the statistics accuracy setting. The only aspect of statistics sensitive to the accuracy setting is
387      * object size. How that is calculated is discussed below.
388      * <h3>Best Effort Size</h3>
389      * This result is returned when the statistics accuracy setting is {@link net.sf.ehcache.Statistics#STATISTICS_ACCURACY_BEST_EFFORT}.
390      * <p/>
391      * The size is the number of {@link net.sf.ehcache.Element}s in the {@link net.sf.ehcache.store.MemoryStore} plus
392      * the number of {@link net.sf.ehcache.Element}s in the {@link net.sf.ehcache.store.DiskStore}.
393      * <p/>
394      * This number is the actual number of elements, including expired elements that have
395      * not been removed. Any duplicates between stores are accounted for.
396      * <p/>
397      * Expired elements are removed from the the memory store when
398      * getting an expired element, or when attempting to spool an expired element to
399      * disk.
400      * <p/>
401      * Expired elements are removed from the disk store when getting an expired element,
402      * or when the expiry thread runs, which is once every five minutes.
403      * <p/>
404      * <h3>Guaranteed Accuracy Size</h3>
405      * This result is returned when the statistics accuracy setting is {@link net.sf.ehcache.Statistics#STATISTICS_ACCURACY_GUARANTEED}.
406      * <p/>
407      * This method accounts for elements which might be expired or duplicated between stores. It take approximately
408      * 200ms per 1000 elements to execute.
409      * <h3>Fast but non-accurate Size</h3>
410      * This result is returned when the statistics accuracy setting is {@link net.sf.ehcache.Statistics#STATISTICS_ACCURACY_NONE}.
411      * <p/>
412      * The number given may contain expired elements. In addition if the DiskStore is used it may contain some double
413      * counting of elements. It takes 6ms for 1000 elements to execute. Time to execute is O(log n). 50,000 elements take
414      * 36ms.
415      *
416      * @return the number of elements in the ehcache, with a varying degree of accuracy, depending on accuracy setting.
417      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
418      */
419     public Statistics getStatistics() throws IllegalStateException {
420         return cache.getStatistics();
421     }
422 
423     /**
424      * Sets the CacheManager
425      *
426      * @param cacheManager
427      */
428     public void setCacheManager(CacheManager cacheManager) {
429         cache.setCacheManager(cacheManager);
430     }
431 
432     /**
433      * Accessor for the BootstrapCacheLoader associated with this cache. For testing purposes.
434      */
435     public BootstrapCacheLoader getBootstrapCacheLoader() {
436         return cache.getBootstrapCacheLoader();
437     }
438 
439     /**
440      * Sets the bootstrap cache loader.
441      *
442      * @param bootstrapCacheLoader the loader to be used
443      * @throws net.sf.ehcache.CacheException if this method is called after the cache is initialized
444      */
445     public void setBootstrapCacheLoader(BootstrapCacheLoader bootstrapCacheLoader) throws CacheException {
446         cache.setBootstrapCacheLoader(bootstrapCacheLoader);
447     }
448 
449     /**
450      * DiskStore paths can conflict between CacheManager instances. This method allows the path to be changed.
451      *
452      * @param diskStorePath the new path to be used.
453      * @throws net.sf.ehcache.CacheException if this method is called after the cache is initialized
454      */
455     public void setDiskStorePath(String diskStorePath) throws CacheException {
456         cache.setDiskStorePath(diskStorePath);
457     }
458 
459     /**
460      * Newly created caches do not have a {@link net.sf.ehcache.store.MemoryStore} or a {@link net.sf.ehcache.store.DiskStore}.
461      * <p/>
462      * This method creates those and makes the cache ready to accept elements
463      */
464     public void initialise() {
465         cache.initialise();
466     }
467 
468     /**
469      * Bootstrap command. This must be called after the Cache is intialised, during
470      * CacheManager initialisation. If loads are synchronous, they will complete before the CacheManager
471      * initialise completes, otherwise they will happen in the background.
472      */
473     public void bootstrap() {
474         cache.bootstrap();
475     }
476 
477     /**
478      * Flushes all cache items from memory to auxilliary caches and close the auxilliary caches.
479      * <p/>
480      * Should be invoked only by CacheManager.
481      *
482      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
483      */
484     public void dispose() throws IllegalStateException {
485         cache.dispose();
486     }
487 
488     /**
489      * Gets the cache configuration this cache was created with.
490      * <p/>
491      * Things like listeners that are added dynamically are excluded.
492      */
493     public CacheConfiguration getCacheConfiguration() {
494         return cache.getCacheConfiguration();
495     }
496 
497     /**
498      * Looks up an entry.  Blocks if the entry is null until a call to {@link #put} is done
499      * to put an Element in.
500      * <p/>
501      * If a put is not done, the lock is never released
502      * <p/>
503      * Note. If a LockTimeoutException is thrown while doing a {@link #get} it means the lock was never acquired,
504      * therefore it is a threading error to call {@link #put}
505      * @throws LockTimeoutException if timeout millis is non zero and this method has been unable to
506      * acquire a lock in that time
507      */
508     public Element get(final Object key) throws LockTimeoutException {
509         Mutex lock = getLockForKey(key);
510         try {
511             if (timeoutMillis == 0) {
512                 lock.acquire();
513             } else {
514                 boolean acquired = lock.attempt(timeoutMillis);
515                 if (!acquired) {
516                     StringBuffer message = new StringBuffer("Lock timeout. Waited more than ")
517                             .append(timeoutMillis)
518                             .append("ms to acquire lock for key ")
519                             .append(key).append(" on blocking cache ").append(cache.getName());
520                     throw new LockTimeoutException(message.toString());
521                 }
522             }
523             final Element element = cache.get(key);
524             if (element != null) {
525                 //ok let the other threads in
526                 lock.release();
527                 return element;
528             } else {
529                 //don't release the read lock until we put
530                 return null;
531             }
532         } catch (InterruptedException e) {
533             throw new CacheException("Interrupted. Message was: " + e.getMessage());
534         }
535     }
536 
537 
538     /**
539      * Gets the Mutex to use for a given key.
540      * @param key the key
541      * @return one of a limited number of Mutexes.
542      */
543     protected Mutex getLockForKey(final Object key) {
544         int lockNumber = ConcurrencyUtil.selectLock(key, LOCK_NUMBER);
545         return locks[lockNumber];
546     }
547 
548     /**
549      * Adds an entry and unlocks it
550      */
551     public void put(Element element) {
552 
553         if (element == null) {
554             return;
555         }
556         Object key = element.getObjectKey();
557         Object value = element.getObjectValue();
558 
559         Mutex lock = getLockForKey(key);
560         try {
561             if (value != null) {
562                 cache.put(element);
563             } else {
564                 cache.remove(key);
565             }
566         } finally {
567             //Release the readlock here. This will have been acquired in the get, where the element was null
568             lock.release();
569         }
570     }
571 
572     /**
573      * Put an element in the cache.
574      * <p/>
575      * Resets the access statistics on the element, which would be the case if it has previously been
576      * gotten from a cache, and is now being put back.
577      * <p/>
578      * Also notifies the CacheEventListener that:
579      * <ul>
580      * <li>the element was put, but only if the Element was actually put.
581      * <li>if the element exists in the cache, that an update has occurred, even if the element would be expired
582      * if it was requested
583      * </ul>
584      *
585      * @param element                     An object. If Serializable it can fully participate in replication and the DiskStore.
586      * @param doNotNotifyCacheReplicators whether the put is coming from a doNotNotifyCacheReplicators cache peer, in which case this put should not initiate a
587      *                                    further notification to doNotNotifyCacheReplicators cache peers
588      * @throws IllegalStateException    if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
589      * @throws IllegalArgumentException if the element is null
590      */
591     public void put(Element element, boolean doNotNotifyCacheReplicators) throws IllegalArgumentException,
592             IllegalStateException, CacheException {
593         cache.put(element, doNotNotifyCacheReplicators);
594     }
595 
596     /**
597      * Put an element in the cache, without updating statistics, or updating listeners. This is meant to be used
598      * in conjunction with {@link #getQuiet}
599      *
600      * @param element An object. If Serializable it can fully participate in replication and the DiskStore.
601      * @throws IllegalStateException    if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
602      * @throws IllegalArgumentException if the element is null
603      */
604     public void putQuiet(Element element) throws IllegalArgumentException, IllegalStateException, CacheException {
605         cache.putQuiet(element);
606     }
607 
608     /**
609      * Gets an element from the cache. Updates Element Statistics
610      * <p/>
611      * Note that the Element's lastAccessTime is always the time of this get.
612      * Use {@link #getQuiet(Object)} to peak into the Element to see its last access time with get
613      *
614      * @param key a serializable value
615      * @return the element, or null, if it does not exist.
616      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
617      * @see #isExpired
618      */
619     public Element get(Serializable key) throws IllegalStateException, CacheException {
620         return this.get((Object) key);
621     }
622 
623 
624     /**
625      * Gets an element from the cache, without updating Element statistics. Cache statistics are
626      * still updated.
627      * <p/>
628      *
629      * @param key a serializable value
630      * @return the element, or null, if it does not exist.
631      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
632      * @see #isExpired
633      */
634     public Element getQuiet(Serializable key) throws IllegalStateException, CacheException {
635         return cache.getQuiet(key);
636     }
637 
638     /**
639      * Gets an element from the cache, without updating Element statistics. Cache statistics are
640      * still updated.
641      * <p/>
642      *
643      * @param key a serializable value
644      * @return the element, or null, if it does not exist.
645      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
646      * @see #isExpired
647      * @since 1.2
648      */
649     public Element getQuiet(Object key) throws IllegalStateException, CacheException {
650         return cache.getQuiet(key);
651     }
652 
653     /**
654      * Returns the keys for this cache.
655      *
656      * @return The keys of this cache.  This is not a live set, so it will not track changes to the key set.
657      */
658     public List getKeys() throws CacheException {
659         return cache.getKeys();
660     }
661 
662     /**
663      * Returns a list of all elements in the cache. Only keys of non-expired
664      * elements are returned.
665      * <p/>
666      * The returned keys are unique and can be considered a set.
667      * <p/>
668      * The List returned is not live. It is a copy.
669      * <p/>
670      * The time taken is O(n), where n is the number of elements in the cache. On
671      * a 1.8Ghz P4, the time taken is approximately 200ms per 1000 entries. This method
672      * is not synchronized, because it relies on a non-live list returned from {@link #getKeys()}
673      * , which is synchronised, and which takes 8ms per 1000 entries. This way
674      * cache liveness is preserved, even if this method is very slow to return.
675      * <p/>
676      * Consider whether your usage requires checking for expired keys. Because
677      * this method takes so long, depending on cache settings, the list could be
678      * quite out of date by the time you get it.
679      *
680      * @return a list of {@link Object} keys
681      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
682      */
683     public List getKeysWithExpiryCheck() throws IllegalStateException, CacheException {
684         return cache.getKeysWithExpiryCheck();
685     }
686 
687     /**
688      * Returns a list of all elements in the cache, whether or not they are expired.
689      * <p/>
690      * The returned keys are not unique and may contain duplicates. If the cache is only
691      * using the memory store, the list will be unique. If the disk store is being used
692      * as well, it will likely contain duplicates, because of the internal store design.
693      * <p/>
694      * The List returned is not live. It is a copy.
695      * <p/>
696      * The time taken is O(log n). On a single cpu 1.8Ghz P4, approximately 6ms is required
697      * for 1000 entries and 36 for 50000.
698      * <p/>
699      * This is the fastest getKeys method
700      *
701      * @return a list of {@link Object} keys
702      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
703      */
704     public List getKeysNoDuplicateCheck() throws IllegalStateException {
705         return cache.getKeysNoDuplicateCheck();
706     }
707 
708     /**
709      * Removes an {@link net.sf.ehcache.Element} from the Cache. This also removes it from any
710      * stores it may be in.
711      * <p/>
712      * Also notifies the CacheEventListener after the element was removed, but only if an Element
713      * with the key actually existed.
714      *
715      * @param key
716      * @return true if the element was removed, false if it was not found in the cache
717      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
718      */
719     public boolean remove(Serializable key) throws IllegalStateException {
720         return cache.remove(key);
721     }
722 
723     /**
724      * Removes an {@link net.sf.ehcache.Element} from the Cache. This also removes it from any
725      * stores it may be in.
726      * <p/>
727      * Also notifies the CacheEventListener after the element was removed, but only if an Element
728      * with the key actually existed.
729      *
730      * @param key
731      * @return true if the element was removed, false if it was not found in the cache
732      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
733      * @since 1.2
734      */
735     public boolean remove(Object key) throws IllegalStateException {
736         return cache.remove(key);
737     }
738 
739     /**
740      * Removes an {@link net.sf.ehcache.Element} from the Cache. This also removes it from any
741      * stores it may be in.
742      * <p/>
743      * Also notifies the CacheEventListener after the element was removed, but only if an Element
744      * with the key actually existed.
745      *
746      * @param key
747      * @param doNotNotifyCacheReplicators whether the put is coming from a doNotNotifyCacheReplicators cache peer, in which case this put should not initiate a
748      *                                    further notification to doNotNotifyCacheReplicators cache peers
749      * @return true if the element was removed, false if it was not found in the cache
750      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
751      * @noinspection SameParameterValue
752      */
753     public boolean remove(Serializable key, boolean doNotNotifyCacheReplicators) throws IllegalStateException {
754         return cache.remove(key, doNotNotifyCacheReplicators);
755     }
756 
757     /**
758      * Removes an {@link net.sf.ehcache.Element} from the Cache. This also removes it from any
759      * stores it may be in.
760      * <p/>
761      * Also notifies the CacheEventListener after the element was removed, but only if an Element
762      * with the key actually existed.
763      *
764      * @param key
765      * @param doNotNotifyCacheReplicators whether the put is coming from a doNotNotifyCacheReplicators cache peer, in which case this put should not initiate a
766      *                                    further notification to doNotNotifyCacheReplicators cache peers
767      * @return true if the element was removed, false if it was not found in the cache
768      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
769      */
770     public boolean remove(Object key, boolean doNotNotifyCacheReplicators) throws IllegalStateException {
771         return cache.remove(key, doNotNotifyCacheReplicators);
772     }
773 
774     /**
775      * Removes an {@link net.sf.ehcache.Element} from the Cache, without notifying listeners. This also removes it from any
776      * stores it may be in.
777      * <p/>
778      *
779      * @param key
780      * @return true if the element was removed, false if it was not found in the cache
781      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
782      */
783     public boolean removeQuiet(Serializable key) throws IllegalStateException {
784         return cache.removeQuiet(key);
785     }
786 
787     /**
788      * Removes an {@link net.sf.ehcache.Element} from the Cache, without notifying listeners. This also removes it from any
789      * stores it may be in.
790      * <p/>
791      *
792      * @param key
793      * @return true if the element was removed, false if it was not found in the cache
794      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
795      * @since 1.2
796      */
797     public boolean removeQuiet(Object key) throws IllegalStateException {
798         return cache.removeQuiet(key);
799     }
800 
801     /**
802      * Removes all cached items.
803      *
804      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
805      */
806     public void removeAll() throws IllegalStateException, CacheException {
807         cache.removeAll();
808     }
809 
810     /**
811      * Removes all cached items.
812      *
813      * @param doNotNotifyCacheReplicators whether the put is coming from a doNotNotifyCacheReplicators cache peer,
814      *                                    in which case this put should not initiate a further notification to doNotNotifyCacheReplicators cache peers
815      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
816      */
817     public void removeAll(boolean doNotNotifyCacheReplicators) throws IllegalStateException, CacheException {
818         cache.removeAll(doNotNotifyCacheReplicators);
819     }
820 
821     /**
822      * Flushes all cache items from memory to the disk store, and from the DiskStore to disk.
823      *
824      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
825      */
826     public void flush() throws IllegalStateException, CacheException {
827         cache.flush();
828     }
829 
830     /**
831      * Gets the size of the cache. This is a subtle concept. See below.
832      * <p/>
833      * The size is the number of {@link net.sf.ehcache.Element}s in the {@link net.sf.ehcache.store.MemoryStore} plus
834      * the number of {@link net.sf.ehcache.Element}s in the {@link net.sf.ehcache.store.DiskStore}.
835      * <p/>
836      * This number is the actual number of elements, including expired elements that have
837      * not been removed.
838      * <p/>
839      * Expired elements are removed from the the memory store when
840      * getting an expired element, or when attempting to spool an expired element to
841      * disk.
842      * <p/>
843      * Expired elements are removed from the disk store when getting an expired element,
844      * or when the expiry thread runs, which is once every five minutes.
845      * <p/>
846      * To get an exact size, which would exclude expired elements, use {@link #getKeysWithExpiryCheck()}.size(),
847      * although see that method for the approximate time that would take.
848      * <p/>
849      * To get a very fast result, use {@link #getKeysNoDuplicateCheck()}.size(). If the disk store
850      * is being used, there will be some duplicates.
851      *
852      * @return The size value
853      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
854      */
855     public int getSize() throws IllegalStateException, CacheException {
856         return cache.getSize();
857     }
858 
859     /**
860      * Gets the size of the memory store for this cache
861      * <p/>
862      * Warning: This method can be very expensive to run. Allow approximately 1 second
863      * per 1MB of entries. Running this method could create liveness problems
864      * because the object lock is held for a long period
865      * <p/>
866      *
867      * @return the approximate size of the memory store in bytes
868      * @throws IllegalStateException
869      */
870     public long calculateInMemorySize() throws IllegalStateException, CacheException {
871         return cache.calculateInMemorySize();
872     }
873 
874     /**
875      * Returns the number of elements in the memory store.
876      *
877      * @return the number of elements in the memory store
878      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
879      */
880     public long getMemoryStoreSize() throws IllegalStateException {
881         return cache.getMemoryStoreSize();
882     }
883 
884     /**
885      * Returns the number of elements in the disk store.
886      *
887      * @return the number of elements in the disk store.
888      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
889      */
890     public int getDiskStoreSize() throws IllegalStateException {
891         return cache.getDiskStoreSize();
892     }
893 
894     /**
895      * Gets the status attribute of the Cache.
896      *
897      * @return The status value from the Status enum class
898      */
899     public Status getStatus() {
900         return cache.getStatus();
901     }
902 
903     /**
904      * Synchronized version of getName to test liveness of the object lock.
905      * <p/>
906      * The time taken for this method to return is a useful measure of runtime contention on the cache.
907      */
908     public synchronized String liveness() {
909         return getName();
910     }
911 
912     /**
913      * Sets the time to wait to acquire a lock. This may be modified at any time.
914      * <p/>
915      * The consequences of setting a timeout are:
916      * <ol>
917      * <li>if a lock cannot be acquired in the given time a LockTimeoutException is thrown.
918      * <li>if there is a queue of threads waiting for the first thread to complete, but it does not complete within
919      * the time out period, the successive threads may find that they have exceeded their lock timeouts and fail. This
920      * is usually a good thing because it stops a build up of threads from overwhelming a busy resource, but it does
921      * need to be considered in the design of user interfaces. The timeout should be set no greater than the time a user
922      * would be expected to wait before considering the action will never return
923      * <li>it will be common to see a number of threads timeout trying to get the same lock. This is a normal and desired
924      * consequence.
925      * </ol>
926      * The consequences of not setting a timeout (or setting it to 0) are:
927      * <ol>
928      * <li>There are no partial failures in the system. But there is a greater possibility that a temporary overload
929      * in one part of the system can cause a back up that may take a long time to recover from.
930      * <li>A failing method that perhaps fails because a resource is overloaded will be hit by each thread in turn, no matter whether there is a still a user who
931      * cares about getting a response.
932      * </ol>
933      *
934      * @param timeoutMillis the time in ms. Must be a positive number. 0 means wait forever.
935      */
936     public void setTimeoutMillis(int timeoutMillis) {
937         if (timeoutMillis < 0) {
938             throw new CacheException("The lock timeout must be a positive number of ms. Value was " + timeoutMillis);
939         }
940         this.timeoutMillis = timeoutMillis;
941     }
942 
943     /**
944      * Gets the time to wait to acquire a lock.
945      *
946      * @return the time in ms.
947      */
948     public int getTimeoutMillis() {
949         return timeoutMillis;
950     }
951 
952 
953 }
954 
955 
956