Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* Copyright 2003-2009 Terracotta, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.ehcache;
import java.io.IOException;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.rmi.server.UID;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sf.ehcache.bootstrap.BootstrapCacheLoader;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.config.DiskStoreConfiguration;
import net.sf.ehcache.config.TerracottaConfiguration;
import net.sf.ehcache.event.CacheEventListener;
import net.sf.ehcache.event.RegisteredEventListeners;
import net.sf.ehcache.exceptionhandler.CacheExceptionHandler;
import net.sf.ehcache.extension.CacheExtension;
import net.sf.ehcache.loader.CacheLoader;
import net.sf.ehcache.statistics.CacheUsageListener;
import net.sf.ehcache.statistics.LiveCacheStatistics;
import net.sf.ehcache.statistics.LiveCacheStatisticsData;
import net.sf.ehcache.statistics.LiveCacheStatisticsWrapper;
import net.sf.ehcache.statistics.sampled.SampledCacheStatistics;
import net.sf.ehcache.statistics.sampled.SampledCacheStatisticsWrapper;
import net.sf.ehcache.store.DiskStore;
import net.sf.ehcache.store.LruMemoryStore;
import net.sf.ehcache.store.MemoryStore;
import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
import net.sf.ehcache.store.Policy;
import net.sf.ehcache.store.Store;
import net.sf.ehcache.util.TimeUtil;
/**
* Cache is the central class in ehcache. Caches have {@link Element}s and are managed
* by the {@link CacheManager}. The Cache performs logical actions. It delegates physical
* implementations to its {@link net.sf.ehcache.store.Store}s.
*
* A reference to a Cache can be obtained through the {@link CacheManager}. A Cache thus obtained
* is guaranteed to have status {@link Status#STATUS_ALIVE}. This status is checked for any method which
* throws {@link IllegalStateException} and the same thrown if it is not alive. This would normally
* happen if a call is made after {@link CacheManager#shutdown} is invoked.
*
* Cache is threadsafe.
*
* Statistics on cache usage are collected and made available through the {@link #getStatistics()} methods.
*
* Various decorators are available for Cache, such as BlockingCache, SelfPopulatingCache and the dynamic proxy
* ExceptionHandlingDynamicCacheProxy. See each class for details.
*
* @author Greg Luck
* @version $Id: Cache.java 1471 2009-11-30 22:15:50Z jvoegele $
*/
public class Cache implements Ehcache {
/**
* A reserved word for cache names. It denotes a default configuration
* which is applied to caches created without configuration.
*/
public static final String DEFAULT_CACHE_NAME = "default";
/**
* System Property based method of disabling ehcache. If disabled no elements will be added to a cache.
*
* Set the property "net.sf.ehcache.disabled=true" to disable ehcache.
*
* This can easily be done using java -Dnet.sf.ehcache.disabled=true in the command line.
*/
public static final String NET_SF_EHCACHE_DISABLED = "net.sf.ehcache.disabled";
/**
* System Property based method of selecting the LruMemoryStore in use up to ehcache 1.5. This is provided
* for ease of migration.
*
* Set the property "net.sf.ehcache.use.classic.lru=true" to use the older LruMemoryStore implementation
* when LRU is selected as the eviction policy.
*
* This can easily be done using java -Dnet.sf.ehcache.use.classic.lru=true in the command line.
*/
public static final String NET_SF_EHCACHE_USE_CLASSIC_LRU = "net.sf.ehcache.use.classic.lru";
/**
* The default interval between runs of the expiry thread.
*/
public static final long DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS = 120;
/**
* Set a buffer size for the spool of approx 30MB
*/
private static final int DEFAULT_SPOOL_BUFFER_SIZE = 30;
private static final Logger LOG = LoggerFactory.getLogger(Cache.class.getName());
private static final MemoryStoreEvictionPolicy DEFAULT_MEMORY_STORE_EVICTION_POLICY = MemoryStoreEvictionPolicy.LRU;
private static InetAddress localhost;
/**
* The amount of time to wait if a store gets backed up
*/
private static final int BACK_OFF_TIME_MILLIS = 50;
private static final int EXECUTOR_KEEP_ALIVE_TIME = 60000;
private static final int EXECUTOR_MAXIMUM_POOL_SIZE = Math.min(10, Runtime.getRuntime().availableProcessors());
private static final int EXECUTOR_CORE_POOL_SIZE = 1;
static {
try {
localhost = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
LOG.error("Unable to set localhost. This prevents creation of a GUID. Cause was: " + e.getMessage(), e);
} catch (java.lang.NoClassDefFoundError e) {
LOG.debug("InetAddress is being blocked by your runtime environment. e.g. Google App Engine." +
" Ehcache will work as a local cache.");
}
}
private volatile boolean disabled = Boolean.getBoolean(NET_SF_EHCACHE_DISABLED);
private final boolean useClassicLru = Boolean.getBoolean(NET_SF_EHCACHE_USE_CLASSIC_LRU);
private volatile Store diskStore;
private volatile String diskStorePath;
private volatile Status status;
private volatile CacheConfiguration configuration;
/**
* The {@link MemoryStore} of this {@link Cache}. All caches have a memory store.
*/
private volatile Store memoryStore;
private volatile RegisteredEventListeners registeredEventListeners;
private volatile List registeredCacheExtensions;
private volatile String guid;
private volatile CacheManager cacheManager;
private volatile BootstrapCacheLoader bootstrapCacheLoader;
private volatile CacheExceptionHandler cacheExceptionHandler;
private volatile List registeredCacheLoaders;
/**
* A ThreadPoolExecutor which uses a thread pool to schedule loads in the order in which they are requested.
*
* Each cache has its own one of these, if required. Because the Core Thread Pool is zero, no threads
* are used until actually needed. Threads are added to the pool up to a maximum of 10. The keep alive
* time is 60 seconds, after which, if they are not required they will be stopped and collected.
*
* The executorService is only used for cache loading, and is created lazily on demand to avoid unnecessary resource
* usage.
*
* Use {@link #getExecutorService()} to ensure that it is initialised.
*/
private volatile ExecutorService executorService;
private volatile LiveCacheStatisticsData liveCacheStatisticsData;
private volatile SampledCacheStatisticsWrapper sampledCacheStatistics;
/**
* 1.0 Constructor.
*
* The {@link net.sf.ehcache.config.ConfigurationFactory} and clients can create these.
*
* A client can specify their own settings here and pass the {@link Cache} object
* into {@link CacheManager#addCache} to specify parameters other than the defaults.
*
* Only the CacheManager can initialise them.
*
* This constructor creates disk stores, if specified, that do not persist between restarts.
*
* The default expiry thread interval of 120 seconds is used. This is the interval between runs
* of the expiry thread, where it checks the disk store for expired elements. It is not the
* the timeToLiveSeconds.
*
* @param name the name of the cache. Note that "default" is a reserved name for the defaultCache.
* @param maxElementsInMemory the maximum number of elements in memory, before they are evicted
* @param overflowToDisk whether to use the disk store
* @param eternal whether the elements in the cache are eternal, i.e. never expire
* @param timeToLiveSeconds the default amount of time to live for an element from its creation date
* @param timeToIdleSeconds the default amount of time to live for an element from its last accessed or modified date
* @since 1.0
*/
public Cache(String name, int maxElementsInMemory, boolean overflowToDisk,
boolean eternal, long timeToLiveSeconds, long timeToIdleSeconds) {
this(name, maxElementsInMemory, DEFAULT_MEMORY_STORE_EVICTION_POLICY, overflowToDisk,
null, eternal, timeToLiveSeconds, timeToIdleSeconds, false, DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS, null, null);
}
/**
* 1.1 Constructor.
*
* The {@link net.sf.ehcache.config.ConfigurationFactory} and clients can create these.
*
* A client can specify their own settings here and pass the {@link Cache} object
* into {@link CacheManager#addCache} to specify parameters other than the defaults.
*
* Only the CacheManager can initialise them.
*
* @param name the name of the cache. Note that "default" is a reserved name for the defaultCache.
* @param maxElementsInMemory the maximum number of elements in memory, before they are evicted
* @param overflowToDisk whether to use the disk store
* @param eternal whether the elements in the cache are eternal, i.e. never expire
* @param timeToLiveSeconds the default amount of time to live for an element from its creation date
* @param timeToIdleSeconds the default amount of time to live for an element from its last accessed or modified date
* @param diskPersistent whether to persist the cache to disk between JVM restarts
* @param diskExpiryThreadIntervalSeconds
* how often to run the disk store expiry thread. A large number of 120 seconds plus is recommended
* @since 1.1
*/
public Cache(String name,
int maxElementsInMemory,
boolean overflowToDisk,
boolean eternal,
long timeToLiveSeconds,
long timeToIdleSeconds,
boolean diskPersistent,
long diskExpiryThreadIntervalSeconds) {
this(name, maxElementsInMemory, DEFAULT_MEMORY_STORE_EVICTION_POLICY, overflowToDisk, null,
eternal, timeToLiveSeconds, timeToIdleSeconds, diskPersistent, diskExpiryThreadIntervalSeconds, null, null);
LOG.warn("An API change between ehcache-1.1 and ehcache-1.2 results in the persistence path being set to " +
DiskStoreConfiguration.getDefaultPath() + " when the ehcache-1.1 constructor is used. " +
"Please change to the 1.2 constructor.");
}
/**
* 1.2 Constructor
*
* The {@link net.sf.ehcache.config.ConfigurationFactory} and clients can create these.
*
* A client can specify their own settings here and pass the {@link Cache} object
* into {@link CacheManager#addCache} to specify parameters other than the defaults.
*
* Only the CacheManager can initialise them.
*
* @param name the name of the cache. Note that "default" is a reserved name for the defaultCache.
* @param maxElementsInMemory the maximum number of elements in memory, before they are evicted
* @param memoryStoreEvictionPolicy one of LRU, LFU and FIFO. Optionally null, in which case it will be set to LRU.
* @param overflowToDisk whether to use the disk store
* @param diskStorePath this parameter is ignored. CacheManager sets it using setter injection.
* @param eternal whether the elements in the cache are eternal, i.e. never expire
* @param timeToLiveSeconds the default amount of time to live for an element from its creation date
* @param timeToIdleSeconds the default amount of time to live for an element from its last accessed or modified date
* @param diskPersistent whether to persist the cache to disk between JVM restarts
* @param diskExpiryThreadIntervalSeconds
* how often to run the disk store expiry thread. A large number of 120 seconds plus is recommended
* @param registeredEventListeners a notification service. Optionally null, in which case a new
* one with no registered listeners will be created.
* @since 1.2
*/
public Cache(String name,
int maxElementsInMemory,
MemoryStoreEvictionPolicy memoryStoreEvictionPolicy,
boolean overflowToDisk,
String diskStorePath,
boolean eternal,
long timeToLiveSeconds,
long timeToIdleSeconds,
boolean diskPersistent,
long diskExpiryThreadIntervalSeconds,
RegisteredEventListeners registeredEventListeners) {
this(name,
maxElementsInMemory,
memoryStoreEvictionPolicy,
overflowToDisk,
diskStorePath,
eternal,
timeToLiveSeconds,
timeToIdleSeconds,
diskPersistent,
diskExpiryThreadIntervalSeconds,
registeredEventListeners,
null);
}
/**
* 1.2.1 Constructor
*
* The {@link net.sf.ehcache.config.ConfigurationFactory} and clients can create these.
*
* A client can specify their own settings here and pass the {@link Cache} object
* into {@link CacheManager#addCache} to specify parameters other than the defaults.
*
* Only the CacheManager can initialise them.
*
* @param name the name of the cache. Note that "default" is a reserved name for the defaultCache.
* @param maxElementsInMemory the maximum number of elements in memory, before they are evicted
* @param memoryStoreEvictionPolicy one of LRU, LFU and FIFO. Optionally null, in which case it will be set to LRU.
* @param overflowToDisk whether to use the disk store
* @param diskStorePath this parameter is ignored. CacheManager sets it using setter injection.
* @param eternal whether the elements in the cache are eternal, i.e. never expire
* @param timeToLiveSeconds the default amount of time to live for an element from its creation date
* @param timeToIdleSeconds the default amount of time to live for an element from its last accessed or modified date
* @param diskPersistent whether to persist the cache to disk between JVM restarts
* @param diskExpiryThreadIntervalSeconds
* how often to run the disk store expiry thread. A large number of 120 seconds plus is recommended
* @param registeredEventListeners a notification service. Optionally null, in which case a new one with no registered listeners will be created.
* @param bootstrapCacheLoader the BootstrapCacheLoader to use to populate the cache when it is first initialised. Null if none is required.
* @since 1.2.1
*/
public Cache(String name,
int maxElementsInMemory,
MemoryStoreEvictionPolicy memoryStoreEvictionPolicy,
boolean overflowToDisk,
String diskStorePath,
boolean eternal,
long timeToLiveSeconds,
long timeToIdleSeconds,
boolean diskPersistent,
long diskExpiryThreadIntervalSeconds,
RegisteredEventListeners registeredEventListeners,
BootstrapCacheLoader bootstrapCacheLoader) {
this(name,
maxElementsInMemory,
memoryStoreEvictionPolicy,
overflowToDisk,
diskStorePath,
eternal,
timeToLiveSeconds,
timeToIdleSeconds,
diskPersistent,
diskExpiryThreadIntervalSeconds,
registeredEventListeners,
bootstrapCacheLoader,
0);
}
/**
* 1.2.4 Constructor
*
* The {@link net.sf.ehcache.config.ConfigurationFactory} and clients can create these.
*
* A client can specify their own settings here and pass the {@link Cache} object
* into {@link CacheManager#addCache} to specify parameters other than the defaults.
*
* Only the CacheManager can initialise them.
*
* @param name the name of the cache. Note that "default" is a reserved name for the defaultCache.
* @param maxElementsInMemory the maximum number of elements in memory, before they are evicted
* @param memoryStoreEvictionPolicy one of LRU, LFU and FIFO. Optionally null, in which case it will be set to LRU.
* @param overflowToDisk whether to use the disk store
* @param diskStorePath this parameter is ignored. CacheManager sets it using setter injection.
* @param eternal whether the elements in the cache are eternal, i.e. never expire
* @param timeToLiveSeconds the default amount of time to live for an element from its creation date
* @param timeToIdleSeconds the default amount of time to live for an element from its last accessed or modified date
* @param diskPersistent whether to persist the cache to disk between JVM restarts
* @param diskExpiryThreadIntervalSeconds
* how often to run the disk store expiry thread. A large number of 120 seconds plus is recommended
* @param registeredEventListeners a notification service. Optionally null, in which case a new one with no registered listeners will be created.
* @param bootstrapCacheLoader the BootstrapCacheLoader to use to populate the cache when it is first initialised. Null if none is required.
* @param maxElementsOnDisk the maximum number of Elements to allow on the disk. 0 means unlimited.
* @since 1.2.4
*/
public Cache(String name,
int maxElementsInMemory,
MemoryStoreEvictionPolicy memoryStoreEvictionPolicy,
boolean overflowToDisk,
String diskStorePath,
boolean eternal,
long timeToLiveSeconds,
long timeToIdleSeconds,
boolean diskPersistent,
long diskExpiryThreadIntervalSeconds,
RegisteredEventListeners registeredEventListeners,
BootstrapCacheLoader bootstrapCacheLoader,
int maxElementsOnDisk) {
this(name,
maxElementsInMemory,
memoryStoreEvictionPolicy,
overflowToDisk,
diskStorePath,
eternal,
timeToLiveSeconds,
timeToIdleSeconds,
diskPersistent,
diskExpiryThreadIntervalSeconds,
registeredEventListeners,
bootstrapCacheLoader,
maxElementsOnDisk,
0,
true,
false,
null,
true);
}
/**
* 1.3 Constructor
*
* The {@link net.sf.ehcache.config.ConfigurationFactory} and clients can create these.
*
* A client can specify their own settings here and pass the {@link Cache} object
* into {@link CacheManager#addCache} to specify parameters other than the defaults.
*
* Only the CacheManager can initialise them.
*
* @param name the name of the cache. Note that "default" is a reserved name for the defaultCache.
* @param maxElementsInMemory the maximum number of elements in memory, before they are evicted
* @param memoryStoreEvictionPolicy one of LRU, LFU and FIFO. Optionally null, in which case it will be set to LRU.
* @param overflowToDisk whether to use the disk store
* @param diskStorePath this parameter is ignored. CacheManager sets it using setter injection.
* @param eternal whether the elements in the cache are eternal, i.e. never expire
* @param timeToLiveSeconds the default amount of time to live for an element from its creation date
* @param timeToIdleSeconds the default amount of time to live for an element from its last accessed or modified date
* @param diskPersistent whether to persist the cache to disk between JVM restarts
* @param diskExpiryThreadIntervalSeconds
* how often to run the disk store expiry thread. A large number of 120 seconds plus is recommended
* @param registeredEventListeners a notification service. Optionally null, in which case a new one with no registered listeners will be created.
* @param bootstrapCacheLoader the BootstrapCacheLoader to use to populate the cache when it is first initialised. Null if none is required.
* @param maxElementsOnDisk the maximum number of Elements to allow on the disk. 0 means unlimited.
* @param diskSpoolBufferSizeMB the amount of memory to allocate the write buffer for puts to the DiskStore.
* @since 1.3
*/
public Cache(String name,
int maxElementsInMemory,
MemoryStoreEvictionPolicy memoryStoreEvictionPolicy,
boolean overflowToDisk,
String diskStorePath,
boolean eternal,
long timeToLiveSeconds,
long timeToIdleSeconds,
boolean diskPersistent,
long diskExpiryThreadIntervalSeconds,
RegisteredEventListeners registeredEventListeners,
BootstrapCacheLoader bootstrapCacheLoader,
int maxElementsOnDisk,
int diskSpoolBufferSizeMB) {
this(name,
maxElementsInMemory,
memoryStoreEvictionPolicy,
overflowToDisk,
diskStorePath,
eternal,
timeToLiveSeconds,
timeToIdleSeconds,
diskPersistent,
diskExpiryThreadIntervalSeconds,
registeredEventListeners,
bootstrapCacheLoader,
maxElementsOnDisk,
diskSpoolBufferSizeMB,
true,
false,
null,
true);
}
/**
* 1.6.0 Constructor
*
* The {@link net.sf.ehcache.config.ConfigurationFactory} and clients can create these.
*
* A client can specify their own settings here and pass the {@link Cache} object
* into {@link CacheManager#addCache} to specify parameters other than the defaults.
*
* Only the CacheManager can initialise them.
*
* @param name the name of the cache. Note that "default" is a reserved name for the defaultCache.
* @param maxElementsInMemory the maximum number of elements in memory, before they are evicted
* @param memoryStoreEvictionPolicy one of LRU, LFU and FIFO. Optionally null, in which case it will be set to LRU.
* @param overflowToDisk whether to use the disk store
* @param diskStorePath this parameter is ignored. CacheManager sets it using setter injection.
* @param eternal whether the elements in the cache are eternal, i.e. never expire
* @param timeToLiveSeconds the default amount of time to live for an element from its creation date
* @param timeToIdleSeconds the default amount of time to live for an element from its last accessed or modified date
* @param diskPersistent whether to persist the cache to disk between JVM restarts
* @param diskExpiryThreadIntervalSeconds
* how often to run the disk store expiry thread. A large number of 120 seconds plus is recommended
* @param registeredEventListeners a notification service. Optionally null, in which case a new one with no registered listeners will be created.
* @param bootstrapCacheLoader the BootstrapCacheLoader to use to populate the cache when it is first initialised. Null if none is required.
* @param maxElementsOnDisk the maximum number of Elements to allow on the disk. 0 means unlimited.
* @param diskSpoolBufferSizeMB the amount of memory to allocate the write buffer for puts to the DiskStore.
* @param clearOnFlush whether the MemoryStore should be cleared when {@link #flush flush()} is called on the cache
* @since 1.6.0
*/
public Cache(String name,
int maxElementsInMemory,
MemoryStoreEvictionPolicy memoryStoreEvictionPolicy,
boolean overflowToDisk,
String diskStorePath,
boolean eternal,
long timeToLiveSeconds,
long timeToIdleSeconds,
boolean diskPersistent,
long diskExpiryThreadIntervalSeconds,
RegisteredEventListeners registeredEventListeners,
BootstrapCacheLoader bootstrapCacheLoader,
int maxElementsOnDisk,
int diskSpoolBufferSizeMB,
boolean clearOnFlush) {
this(name, maxElementsInMemory, memoryStoreEvictionPolicy, overflowToDisk, diskStorePath, eternal, timeToLiveSeconds,
timeToIdleSeconds, diskPersistent, diskExpiryThreadIntervalSeconds, registeredEventListeners,
bootstrapCacheLoader, maxElementsOnDisk, diskSpoolBufferSizeMB, clearOnFlush, false, null, true);
}
/**
* 1.7.0 Constructor
*
* The {@link net.sf.ehcache.config.ConfigurationFactory} and clients can create these.
*
* A client can specify their own settings here and pass the {@link Cache} object
* into {@link CacheManager#addCache} to specify parameters other than the defaults.
*
* Only the CacheManager can initialise them.
*
* @param name the name of the cache. Note that "default" is a reserved name for the defaultCache.
* @param maxElementsInMemory the maximum number of elements in memory, before they are evicted
* @param memoryStoreEvictionPolicy one of LRU, LFU and FIFO. Optionally null, in which case it will be set to LRU.
* @param overflowToDisk whether to use the disk store
* @param diskStorePath this parameter is ignored. CacheManager sets it using setter injection.
* @param eternal whether the elements in the cache are eternal, i.e. never expire
* @param timeToLiveSeconds the default amount of time to live for an element from its creation date
* @param timeToIdleSeconds the default amount of time to live for an element from its last accessed or modified date
* @param diskPersistent whether to persist the cache to disk between JVM restarts
* @param diskExpiryThreadIntervalSeconds
* how often to run the disk store expiry thread. A large number of 120 seconds plus is recommended
* @param registeredEventListeners a notification service. Optionally null, in which case a new one with no registered listeners will be created.
* @param bootstrapCacheLoader the BootstrapCacheLoader to use to populate the cache when it is first initialised. Null if none is required.
* @param maxElementsOnDisk the maximum number of Elements to allow on the disk. 0 means unlimited.
* @param diskSpoolBufferSizeMB the amount of memory to allocate the write buffer for puts to the DiskStore.
* @param clearOnFlush whether the MemoryStore should be cleared when {@link #flush flush()} is called on the cache
* @param isTerracottaClustered whether to cluster this cache with Terracotta
* @param terracottaValueMode either "SERIALIZATION" or "IDENTITY" mode, only used if isTerracottaClustered=true
* @param terracottaCoherentReads whether this cache should use coherent reads (usually should be true) unless optimizing for read-only
* @since 1.7.0
*/
public Cache(String name,
int maxElementsInMemory,
MemoryStoreEvictionPolicy memoryStoreEvictionPolicy,
boolean overflowToDisk,
String diskStorePath,
boolean eternal,
long timeToLiveSeconds,
long timeToIdleSeconds,
boolean diskPersistent,
long diskExpiryThreadIntervalSeconds,
RegisteredEventListeners registeredEventListeners,
BootstrapCacheLoader bootstrapCacheLoader,
int maxElementsOnDisk,
int diskSpoolBufferSizeMB,
boolean clearOnFlush,
boolean isTerracottaClustered,
String terracottaValueMode,
boolean terracottaCoherentReads) {
changeStatus(Status.STATUS_UNINITIALISED);
configuration = new CacheConfiguration();
configuration.setName(name);
configuration.setMaxElementsInMemory(maxElementsInMemory);
configuration.setMemoryStoreEvictionPolicyFromObject(memoryStoreEvictionPolicy);
configuration.setOverflowToDisk(overflowToDisk);
configuration.setEternal(eternal);
configuration.setTimeToLiveSeconds(timeToLiveSeconds);
configuration.setTimeToIdleSeconds(timeToIdleSeconds);
configuration.setDiskPersistent(diskPersistent);
configuration.setMaxElementsOnDisk(maxElementsOnDisk);
configuration.setClearOnFlush(clearOnFlush);
guid = createGuid();
if (diskStorePath == null) {
this.diskStorePath = DiskStoreConfiguration.getDefaultPath();
} else {
this.diskStorePath = diskStorePath;
}
if (registeredEventListeners == null) {
this.registeredEventListeners = new RegisteredEventListeners(this);
} else {
this.registeredEventListeners = registeredEventListeners;
}
registeredCacheExtensions = new CopyOnWriteArrayList();
registeredCacheLoaders = new CopyOnWriteArrayList();
//Set this to a safe value.
if (diskExpiryThreadIntervalSeconds == 0) {
configuration.setDiskExpiryThreadIntervalSeconds(DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS);
} else {
configuration.setDiskExpiryThreadIntervalSeconds(diskExpiryThreadIntervalSeconds);
}
if (diskSpoolBufferSizeMB == 0) {
configuration.setDiskSpoolBufferSizeMB(DEFAULT_SPOOL_BUFFER_SIZE);
} else {
configuration.setDiskSpoolBufferSizeMB(diskSpoolBufferSizeMB);
}
// For backward compatibility with 1.1 and earlier
if (memoryStoreEvictionPolicy == null) {
configuration.setMemoryStoreEvictionPolicyFromObject(DEFAULT_MEMORY_STORE_EVICTION_POLICY);
}
this.bootstrapCacheLoader = bootstrapCacheLoader;
TerracottaConfiguration tcConfig = new TerracottaConfiguration();
tcConfig.setClustered(isTerracottaClustered);
if (terracottaValueMode != null) {
tcConfig.setValueMode(terracottaValueMode);
}
tcConfig.setCoherentReads(terracottaCoherentReads);
configuration.addTerracotta(tcConfig);
//initialize statistics
liveCacheStatisticsData = new LiveCacheStatisticsWrapper(this);
sampledCacheStatistics = new SampledCacheStatisticsWrapper();
}
/**
* Newly created caches do not have a {@link net.sf.ehcache.store.MemoryStore} or a {@link net.sf.ehcache.store.DiskStore}.
*
* This method creates those and makes the cache ready to accept elements
*/
public void initialise() {
synchronized (this) {
if (!status.equals(Status.STATUS_UNINITIALISED)) {
throw new IllegalStateException("Cannot initialise the " + configuration.getName()
+ " cache because its status is not STATUS_UNINITIALISED");
}
if (configuration.getMaxElementsInMemory() == 0) {
LOG.warn("Cache: " + configuration.getName()
+ " has a maxElementsInMemory of 0. It is strongly recommended to " +
"have a maximumSize of at least 1. Performance is halved by not using a MemoryStore.");
}
this.diskStore = createDiskStore();
if (isTerracottaClustered()) {
memoryStore = cacheManager.createTerracottaStore(this);
} else {
if (useClassicLru && configuration.getMemoryStoreEvictionPolicy().equals(MemoryStoreEvictionPolicy.LRU)) {
memoryStore = new LruMemoryStore(this, diskStore);
} else {
memoryStore = MemoryStore.create(this, diskStore);
}
}
changeStatus(Status.STATUS_ALIVE);
initialiseRegisteredCacheExtensions();
initialiseRegisteredCacheLoaders();
// initialize live statistics
// register to get notifications of
// put/update/remove/expiry/eviction
getCacheEventNotificationService().registerListener(
liveCacheStatisticsData);
// set up default values
liveCacheStatisticsData
.setStatisticsAccuracy(Statistics.STATISTICS_ACCURACY_BEST_EFFORT);
liveCacheStatisticsData.setStatisticsEnabled(true);
// register the sampled cache statistics
this.registerCacheUsageListener(sampledCacheStatistics);
}
if (LOG.isDebugEnabled()) {
LOG.debug("Initialised cache: " + configuration.getName());
}
if (disabled) {
LOG.warn("Cache: " + configuration.getName() + " is disabled because the " + NET_SF_EHCACHE_DISABLED
+ " property was set to true. No elements will be added to the cache.");
}
}
/**
* Creates a disk store when either:
*
*
overflowToDisk is enabled
*
diskPersistent is enabled
*
*
* @return the disk store
*/
protected Store createDiskStore() {
if (isDiskStore()) {
return new DiskStore(this, diskStorePath);
} else {
return null;
}
}
/**
* Whether this cache uses a disk store
*
* @return true if the cache either overflows to disk or is disk persistent
*/
protected boolean isDiskStore() {
return configuration.isOverflowToDisk() || configuration.isDiskPersistent();
}
/**
* Indicates whether this cache is clustered by Terracotta
*
* @return {@code true} when the cache is clustered by Terracotta; or {@code false} otherwise
*/
protected boolean isTerracottaClustered() {
return configuration.isTerracottaClustered();
}
/**
* Bootstrap command. This must be called after the Cache is initialised, during
* CacheManager initialisation. If loads are synchronous, they will complete before the CacheManager
* initialise completes, otherwise they will happen in the background.
*/
public void bootstrap() {
if (!disabled && bootstrapCacheLoader != null) {
bootstrapCacheLoader.load(this);
}
}
private void changeStatus(Status status) {
this.status = status;
}
/**
* Put an element in the cache.
*
* Resets the access statistics on the element, which would be the case if it has previously been
* gotten from a cache, and is now being put back.
*
* Also notifies the CacheEventListener that:
*
*
the element was put, but only if the Element was actually put.
*
if the element exists in the cache, that an update has occurred, even if the element would be expired
* if it was requested
*
*
* Caches which use synchronous replication can throw RemoteCacheException here if the replication to the cluster fails.
* This exception should be caught in those circumstances.
*
* @param element A cache Element. If Serializable it can fully participate in replication and the DiskStore. If it is
* null or the key is null, it is ignored as a NOOP.
* @throws IllegalStateException if the cache is not {@link Status#STATUS_ALIVE}
* @throws CacheException
*/
public final void put(Element element) throws IllegalArgumentException, IllegalStateException,
CacheException {
put(element, false);
}
/**
* Put an element in the cache.
*
* Resets the access statistics on the element, which would be the case if it has previously been
* gotten from a cache, and is now being put back.
*
* Also notifies the CacheEventListener that:
*
*
the element was put, but only if the Element was actually put.
*
if the element exists in the cache, that an update has occurred, even if the element would be expired
* if it was requested
*
* Caches which use synchronous replication can throw RemoteCacheException here if the replication to the cluster fails.
* This exception should be caught in those circumstances.
*
* @param element A cache Element. If Serializable it can fully participate in replication and the DiskStore. If it is
* null or the key is null, it is ignored as a NOOP.
* @param doNotNotifyCacheReplicators whether the put is coming from a doNotNotifyCacheReplicators cache peer, in which case this put should not initiate a
* further notification to doNotNotifyCacheReplicators cache peers
* @throws IllegalStateException if the cache is not {@link Status#STATUS_ALIVE}
* @throws IllegalArgumentException if the element is null
*/
public final void put(Element element, boolean doNotNotifyCacheReplicators) throws IllegalArgumentException,
IllegalStateException,
CacheException {
checkStatus();
if (disabled) {
return;
}
if (element == null) {
if (doNotNotifyCacheReplicators) {
LOG.debug("Element from replicated put is null. This happens because the element is a SoftReference" +
" and it has been collected.Increase heap memory on the JVM or set -Xms to be the same as " +
"-Xmx to avoid this problem.");
}
//nulls are ignored
return;
}
if (element.getObjectKey() == null) {
//nulls are ignored
return;
}
element.resetAccessStatistics();
boolean elementExists;
Object key = element.getObjectKey();
elementExists = isElementInMemory(key) || isElementOnDisk(key);
if (elementExists) {
element.updateUpdateStatistics();
}
applyDefaultsToElementWithoutLifespanSet(element);
backOffIfDiskSpoolFull();
memoryStore.put(element);
if (elementExists) {
registeredEventListeners.notifyElementUpdated(element, doNotNotifyCacheReplicators);
} else {
registeredEventListeners.notifyElementPut(element, doNotNotifyCacheReplicators);
}
}
/**
* wait outside of synchronized block so as not to block readers
* If the disk store spool is full wait a short time to give it a chance to
* catch up.
* todo maybe provide a warning if this is continually happening or monitor via JMX
*/
private void backOffIfDiskSpoolFull() {
if (diskStore != null && diskStore.bufferFull()) {
//back off to avoid OutOfMemoryError
try {
Thread.sleep(BACK_OFF_TIME_MILLIS);
} catch (InterruptedException e) {
//do not care if this happens
}
}
}
private void applyDefaultsToElementWithoutLifespanSet(Element element) {
if (!element.isLifespanSet()) {
//Setting with Cache defaults
element.setTimeToLive(TimeUtil.convertTimeToInt(configuration.getTimeToLiveSeconds()));
element.setTimeToIdle(TimeUtil.convertTimeToInt(configuration.getTimeToIdleSeconds()));
element.setEternal(configuration.isEternal());
}
}
/**
* Put an element in the cache, without updating statistics, or updating listeners. This is meant to be used
* in conjunction with {@link #getQuiet}.
* Synchronization is handled within the method.
*
* Caches which use synchronous replication can throw RemoteCacheException here if the replication to the cluster fails.
* This exception should be caught in those circumstances.
*
*
* @param element A cache Element. If Serializable it can fully participate in replication and the DiskStore. If it is
* null or the key is null, it is ignored as a NOOP.
* @throws IllegalStateException if the cache is not {@link Status#STATUS_ALIVE}
* @throws IllegalArgumentException if the element is null
*/
public final void putQuiet(Element element) throws IllegalArgumentException, IllegalStateException,
CacheException {
checkStatus();
if (disabled) {
return;
}
if (element == null || element.getObjectKey() == null) {
//nulls are ignored
return;
}
applyDefaultsToElementWithoutLifespanSet(element);
memoryStore.put(element);
}
/**
* Gets an element from the cache. Updates Element Statistics
*
* 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
*
* Synchronization is handled within the method.
*
* @param key a serializable value. Null keys are not stored so get(null) always returns null
* @return the element, or null, if it does not exist.
* @throws IllegalStateException if the cache is not {@link Status#STATUS_ALIVE}
* @see #isExpired
*/
public final Element get(Serializable key) throws IllegalStateException, CacheException {
return get((Object) key);
}
/**
* Gets an element from the cache. Updates Element Statistics
*
* 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
*
* Synchronization is handled within the method.
*
* @param key an Object value
* @return the element, or null, if it does not exist.
* @throws IllegalStateException if the cache is not {@link Status#STATUS_ALIVE}
* @see #isExpired
* @since 1.2
*/
public final Element get(Object key) throws IllegalStateException, CacheException {
checkStatus();
Element element;
long start = System.currentTimeMillis();
element = searchInMemoryStore(key, true, true);
if (element == null && isDiskStore()) {
element = searchInDiskStore(key, true, true);
}
if (element == null) {
liveCacheStatisticsData.cacheMissNotFound();
if (LOG.isDebugEnabled()) {
LOG.debug(configuration.getName() + " cache - Miss");
}
}
//todo is this expensive. Maybe ditch.
long end = System.currentTimeMillis();
liveCacheStatisticsData.addGetTimeMillis(end - start);
return element;
}
/**
* This method will return, from the cache, the Element associated with the argument "key".
*
* If the Element is not in the cache, the associated cache loader will be called. That is either the CacheLoader passed in, or if null,
* the one associated with the cache. If both are null, no load is performed and null is returned.
*
* If the loader decides to assign a null value to the Element, an Element with a null value is created and stored in the cache.
*
* Because this method may take a long time to complete, it is not synchronized. The underlying cache operations
* are synchronized.
*
* @param key key whose associated value is to be returned.
* @param loader the override loader to use. If null, the cache's default loader will be used
* @param loaderArgument an argument to pass to the CacheLoader.
* @return an element if it existed or could be loaded, otherwise null
* @throws CacheException
*/
public Element getWithLoader(Object key, CacheLoader loader, Object loaderArgument) throws CacheException {
Element element = get(key);
if (element != null) {
return element;
}
if (registeredCacheLoaders.size() == 0 && loader == null) {
return null;
}
try {
//check again in case the last thread loaded it
element = getQuiet(key);
if (element != null) {
return element;
}
Future future = asynchronousLoad(key, loader, loaderArgument);
//wait for result
future.get();
} catch (Exception e) {
throw new CacheException("Exception on load for key " + key, e);
}
return getQuiet(key);
}
/**
* The load method provides a means to "pre load" the cache. This method will, asynchronously, load the specified
* object into the cache using the associated CacheLoader. If the object already exists in the cache, no action is
* taken. If no loader is associated with the object, no object will be loaded into the cache. If a problem is
* encountered during the retrieving or loading of the object, an exception should be logged. If the "arg" argument
* is set, the arg object will be passed to the CacheLoader.load method. The cache will not dereference the object.
* If no "arg" value is provided a null will be passed to the load method. The storing of null values in the cache
* is permitted, however, the get method will not distinguish returning a null stored in the cache and not finding
* the object in the cache. In both cases a null is returned.
*
* The Ehcache native API provides similar functionality to loaders using the
* decorator {@link net.sf.ehcache.constructs.blocking.SelfPopulatingCache}
*
* @param key key whose associated value to be loaded using the associated CacheLoader if this cache doesn't contain it.
* @throws CacheException
*/
public void load(final Object key) throws CacheException {
if (registeredCacheLoaders.size() == 0) {
LOG.debug("The CacheLoader is null. Returning.");
return;
}
boolean existsOnCall = isKeyInCache(key);
if (existsOnCall) {
LOG.debug("The key {} exists in the cache. Returning.", key);
return;
}
asynchronousLoad(key, null, null);
}
/**
* The getAll method will return, from the cache, a Map of the objects associated with the Collection of keys in argument "keys".
* If the objects are not in the cache, the associated cache loader will be called. If no loader is associated with an object,
* a null is returned. If a problem is encountered during the retrieving or loading of the objects, an exception will be thrown.
* If the "arg" argument is set, the arg object will be passed to the CacheLoader.loadAll method. The cache will not dereference
* the object. If no "arg" value is provided a null will be passed to the loadAll method. The storing of null values in the cache
* is permitted, however, the get method will not distinguish returning a null stored in the cache and not finding the object in
* the cache. In both cases a null is returned.
*
*
* Note. If the getAll exceeds the maximum cache size, the returned map will necessarily be less than the number specified.
*
* Because this method may take a long time to complete, it is not synchronized. The underlying cache operations
* are synchronized.
*
* The constructs package provides similar functionality using the
* decorator {@link net.sf.ehcache.constructs.blocking.SelfPopulatingCache}
*
* @param keys a collection of keys to be returned/loaded
* @param loaderArgument an argument to pass to the CacheLoader.
* @return a Map populated from the Cache. If there are no elements, an empty Map is returned.
* @throws CacheException
*/
public Map getAllWithLoader(Collection keys, Object loaderArgument) throws CacheException {
if (keys == null) {
return new HashMap(0);
}
Map