/** * Decorate the given Cache, if necessary. * @param cache the raw Cache object, based on the configuration of this FactoryBean * @return the (potentially decorated) cache object to be registered with the CacheManager */ protected Ehcache decorateCache(Ehcache cache) { if (this.cacheEntryFactory != null) { if (this.cacheEntryFactory instanceof UpdatingCacheEntryFactory) { return new UpdatingSelfPopulatingCache(cache, (UpdatingCacheEntryFactory) this.cacheEntryFactory); } else { return new SelfPopulatingCache(cache, this.cacheEntryFactory); } } if (this.blocking) { return new BlockingCache(cache); } return cache; }
@Override public void putWithWriter(final Element element) throws IllegalArgumentException, IllegalStateException, CacheException { doAndReleaseWriteLock(new PutAction<Void>(element) { @Override public Void put() { underlyingCache.putWithWriter(element); return null; } }); }
/** * Refresh a single element. * * @param element the Element to refresh * @param backingCache the underlying {@link Ehcache}. * @throws Exception */ protected void refreshElement(final Element element, Ehcache backingCache) throws Exception { refreshElement(element, backingCache, true); }
/** * Looks up an entry. creating it if not found. */ @Override public Element get(final Object key) throws LockTimeoutException { Element element = super.get(key); if (element == null) { try { // Value not cached - fetch it Object value = factory.createEntry(key); element = makeAndCheckElement(key, value); } catch (final Throwable throwable) { // Could not fetch - Ditch the entry from the cache and rethrow // release the lock you acquired element = new Element(key, null); throw new CacheException("Could not fetch object for cache entry with key \"" + key + "\".", throwable); } finally { put(element); } } return element; }
public void setCache(Ehcache cache) { BlockingCache ref; if (!(cache instanceof BlockingCache)) { ref = new BlockingCache(cache); cache.getCacheManager().replaceCacheWithDecoratedCache(cache, new BlockingCache(cache)); } else { ref = (BlockingCache)cache; } this.cache = ref; }
/** * Gets an element from the cache. Updates Element Statistics * <p> * Note that the Element's lastAccessTime is always the time of this get. * Use {@link #getQuiet(Object)} to peak into the Element to see its last access time with get * * @param key a serializable value * @return the element, or null, if it does not exist. * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE} * @see #isExpired */ @Override public Element get(Serializable key) throws IllegalStateException, CacheException { return this.get((Object) key); }
private <V> V doAndReleaseWriteLock(PutAction<V> putAction) { if (putAction.element == null) { return null; } Object key = putAction.element.getObjectKey(); Sync lock = getLockForKey(key); if (!lock.isHeldByCurrentThread(LockType.WRITE)) { lock.lock(LockType.WRITE); } try { return putAction.put(); } finally { //Release the writelock here. This will have been acquired in the get, where the element was null lock.unlock(LockType.WRITE); } }
/** * Synchronized version of getName to test liveness of the object lock. * <p> * The time taken for this method to return is a useful measure of runtime contention on the cache. * * @return the name of the cache. */ public synchronized String liveness() { return getName(); }
/** * Refresh a single element. * <p> * Refreshes bypass the {@link BlockingCache} and act directly on the backing {@link Ehcache}. * This way, {@link BlockingCache} gets can continue to return stale data while the refresh, which * might be expensive, takes place. * <p> * If the element is absent it is created * <p> * Quiet methods are used, so that statistics are not affected. * Note that the refreshed element will not be replicated to any cache peers. * * @param key * @return the refreshed Element * @throws CacheException * @since 1.6.1 */ public Element refresh(Object key) throws CacheException { return refresh(key, true); }
@Override public StoreEntry create(Long key, int timeToLive) { StoreEntryImpl result = new StoreEntryImpl(timeToLive); Element element = new Element(key, result); element.setTimeToLive(timeToLive); cache.put(element); return result; }
@Override public void resetCounters() { cache.removeAll(); }
private CacheLockProvider getCacheLockProvider() { CacheLockProvider provider = cacheLockProviderReference.get(); while (provider == null) { cacheLockProviderReference.compareAndSet(null, createCacheLockProvider()); provider = cacheLockProviderReference.get(); } return provider; }
/** * Gets the Sync to use for a given key. * * @param key the key * @return one of a limited number of Sync's. */ protected Sync getLockForKey(final Object key) { return getCacheLockProvider().getSyncForKey(key); }
/** * Decorate the given Cache, if necessary. * @param cache the raw Cache object, based on the configuration of this FactoryBean * @return the (potentially decorated) cache object to be registered with the CacheManager */ protected Ehcache decorateCache(Ehcache cache) { if (this.cacheEntryFactory != null) { if (this.cacheEntryFactory instanceof UpdatingCacheEntryFactory) { return new UpdatingSelfPopulatingCache(cache, (UpdatingCacheEntryFactory) this.cacheEntryFactory); } else { return new SelfPopulatingCache(cache, this.cacheEntryFactory); } } if (this.blocking) { return new BlockingCache(cache); } return cache; }
@Override public Element putIfAbsent(final Element element) throws NullPointerException { return doAndReleaseWriteLock(new PutAction<Element>(element) { @Override public Element put() { return underlyingCache.putIfAbsent(element); } }); }
/** * Refresh the elements of this cache. * <p> * Refreshes bypass the {@link BlockingCache} and act directly on the backing {@link Ehcache}. * This way, {@link BlockingCache} gets can continue to return stale data while the refresh, which * might be expensive, takes place. * <p> * Quiet methods are used, so that statistics are not affected. * Note that the refreshed elements will not be replicated to any cache peers. * <p> * Configure ehcache.xml to stop elements from being refreshed forever: * <ul> * <li>use timeToIdle to discard elements unused for a period of time * <li>use timeToLive to discard elmeents that have existed beyond their allotted lifespan * </ul> * * @throws CacheException */ public void refresh() throws CacheException { refresh(true); }
@Override public void putQuiet(final Element element) throws IllegalArgumentException, IllegalStateException, CacheException { doAndReleaseWriteLock(new PutAction<Void>(element) { @Override public Void put() { underlyingCache.putQuiet(element); return null; } }); }
@Override public Element putIfAbsent(final Element element, final boolean doNotNotifyCacheReplicators) throws NullPointerException { return doAndReleaseWriteLock(new PutAction<Element>(element) { @Override public Element put() { return underlyingCache.putIfAbsent(element, doNotNotifyCacheReplicators); } }); }
@Override public void put(final Element element, final boolean doNotNotifyCacheReplicators) throws IllegalArgumentException, IllegalStateException, CacheException { doAndReleaseWriteLock(new PutAction<Void>(element) { @Override public Void put() { underlyingCache.put(element, doNotNotifyCacheReplicators); return null; } }); }
/** * Adds an entry and unlocks it */ @Override public void put(final Element element) { doAndReleaseWriteLock(new PutAction<Void>(element) { @Override public Void put() { if (element.getObjectValue() != null) { underlyingCache.put(element); } else { underlyingCache.remove(element.getObjectKey()); } return null; } }); }