All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.ehcache.config.CacheConfiguration Maven / Gradle / Ivy

There is a newer version: 2.10.9.2
Show newest version
/**
 *  Copyright 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.config;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.EhcacheDefaultClassLoader;
import net.sf.ehcache.Element;
import net.sf.ehcache.config.PersistenceConfiguration.Strategy;
import net.sf.ehcache.config.PinningConfiguration.Store;
import net.sf.ehcache.config.TerracottaConfiguration.Consistency;
import net.sf.ehcache.event.NotificationScope;
import net.sf.ehcache.search.attribute.DynamicAttributesExtractor;
import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
import net.sf.ehcache.store.compound.ReadWriteCopyStrategy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import static net.sf.ehcache.config.Configuration.getAllActiveCaches;

/**
 * A value object used to represent cache configuration.
 * 

Construction Patterns

* The recommended way of creating a Cache in Ehcache 2.0 and above is to create a CacheConfiguration object * and pass it to the Cache constructor. See {@link net.sf.ehcache.Cache#Cache(CacheConfiguration)}. *

* This class supports setter injection and also the fluent builder pattern. * e.g. * Cache cache = new Cache(new CacheConfiguration("test2", 1000).eternal(true).memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.FIFO)); *

* Rather than proliferation of new constructors as new versions of Ehcache come out, it intended to add the new configuration to this * class. *

* Another way to set configuration is declaratively in the ehcache.xml configuration file. * e.g. *

{@code
 * 
 * }
*

*

Dynamic Configuration

* CacheConfiguration instances retrieved from Cache instances allow the dynamic * modification of certain configuration properties. Currently the dynamic * properties are: *
    *
  • Time To Idle
  • *
  • Time To Live
  • *
  • Max Entries in Local Heap
  • *
  • Max Entries on Local Disk
  • *
* Dynamic changes are however not persistent across cache restarts. On restart * the cache configuration will be reloaded from its original source, erasing any * changes made previously at runtime. *

* Users should also take care of synchronizing threads externally, if a CacheConfiguration instance is * going to be mutated by multiple threads concurrently. While CacheConfiguration instances will * make changes properly visible to all threads, logic within individual methods (e.g. validation) isn't * trying to provide any "thread safeness". * * @author Greg Luck * @author Chris Dennis * @version $Id: CacheConfiguration.java 10789 2018-04-26 02:08:13Z adahanne $ */ public class CacheConfiguration implements Cloneable { /** * Default value for clearOnFlush */ public static final boolean DEFAULT_CLEAR_ON_FLUSH = true; /** * 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. */ public static final int DEFAULT_SPOOL_BUFFER_SIZE = 30; /** * Default number of diskAccessStripes. */ public static final int DEFAULT_DISK_ACCESS_STRIPES = 1; /** * Logging is off by default. */ public static final boolean DEFAULT_LOGGING = false; /** * The default memory store eviction policy is LRU. */ public static final MemoryStoreEvictionPolicy DEFAULT_MEMORY_STORE_EVICTION_POLICY = MemoryStoreEvictionPolicy.LRU; /** * The default cacheWriterConfiguration */ public static final CacheWriterConfiguration DEFAULT_CACHE_WRITER_CONFIGURATION = new CacheWriterConfiguration(); /** * Default value for copyOnRead */ public static final boolean DEFAULT_COPY_ON_READ = false; /** * Default value for copyOnRead */ public static final boolean DEFAULT_COPY_ON_WRITE = false; /** * Default value for ttl */ public static final long DEFAULT_TTL = 0; /** * Default value for tti */ public static final long DEFAULT_TTI = 0; /** * Default value for maxElementsOnDisk */ public static final int DEFAULT_MAX_ELEMENTS_ON_DISK = 0; /** * Default value for maxEntriesInCache */ public static final long DEFAULT_MAX_ENTRIES_IN_CACHE = 0; /** * Default value for transactionalMode */ public static final TransactionalMode DEFAULT_TRANSACTIONAL_MODE = TransactionalMode.OFF; /** * Default value for statistics */ public static final boolean DEFAULT_STATISTICS = true; /** * Default value for diskPersistent * * @deprecated The {@code diskPersistent} attribute has been replaced with {@link #persistence(PersistenceConfiguration)}. */ @Deprecated public static final boolean DEFAULT_DISK_PERSISTENT = false; /** * Default copyStrategyConfiguration */ public static final CopyStrategyConfiguration DEFAULT_COPY_STRATEGY_CONFIGURATION = new CopyStrategyConfiguration(); /** * Default maxBytesOnHeap value */ public static final long DEFAULT_MAX_BYTES_ON_HEAP = 0; /** * Default maxBytesOffHeap value */ public static final long DEFAULT_MAX_BYTES_OFF_HEAP = 0; /** * Default maxBytesOnDisk value */ public static final long DEFAULT_MAX_BYTES_ON_DISK = 0; /** * Default eternal value */ public static final boolean DEFAULT_ETERNAL_VALUE = false; private static final Logger LOG = LoggerFactory.getLogger(CacheConfiguration.class.getName()); private static final int HUNDRED_PERCENT = 100; private static final int MINIMUM_RECOMMENDED_IN_MEMORY = 100; /** * the name of the cache. */ protected volatile String name; /** * Timeout in milliseconds for CacheLoader related calls */ protected volatile long cacheLoaderTimeoutMillis; /** * the maximum objects to be held in the {@link net.sf.ehcache.store.MemoryStore}. *

* 0 translates to no-limit. */ protected volatile Integer maxEntriesLocalHeap; /** * the maximum objects to be held in the {@link net.sf.ehcache.store.disk.DiskStore}. *

* 0 translates to no-limit. */ protected volatile int maxElementsOnDisk = DEFAULT_MAX_ELEMENTS_ON_DISK; /** * the maximum entries to be held in the cache */ protected volatile long maxEntriesInCache = DEFAULT_MAX_ENTRIES_IN_CACHE; /** * The policy used to evict elements from the {@link net.sf.ehcache.store.MemoryStore}. * This can be one of: *

    *
  1. LRU - least recently used *
  2. LFU - Less frequently used *
  3. FIFO - first in first out, the oldest element by creation time *
* The default value is LRU * * @since 1.2 */ protected volatile MemoryStoreEvictionPolicy memoryStoreEvictionPolicy = DEFAULT_MEMORY_STORE_EVICTION_POLICY; /** * Sets whether the MemoryStore should be cleared when * {@link net.sf.ehcache.Ehcache#flush flush()} is called on the cache - true by default. */ protected volatile boolean clearOnFlush = DEFAULT_CLEAR_ON_FLUSH; /** * Sets whether elements are eternal. If eternal, timeouts are ignored and the element * is never expired. */ protected volatile boolean eternal = DEFAULT_ETERNAL_VALUE; /** * the time to idle for an element before it expires. Is only used * if the element is not eternal.A value of 0 means do not check for idling. */ protected volatile long timeToIdleSeconds = DEFAULT_TTI; /** * Sets the time to idle for an element before it expires. Is only used * if the element is not eternal. This attribute is optional in the configuration. * A value of 0 means do not check time to live. */ protected volatile long timeToLiveSeconds = DEFAULT_TTL; /** * whether elements can overflow to disk when the in-memory cache * has reached the set limit. * * @deprecated The {@code overflowToDisk} attribute has been replaced with {@link Strategy#LOCALTEMPSWAP}. */ @Deprecated protected volatile Boolean overflowToDisk; /** * For caches that overflow to disk, whether the disk cache persists between CacheManager instances. * * @deprecated The {@code diskPersistent} attribute has been replaced with {@link #persistence(PersistenceConfiguration)}. */ @Deprecated protected volatile Boolean diskPersistent; /** * The size of the disk spool used to buffer writes */ protected volatile int diskSpoolBufferSizeMB = DEFAULT_SPOOL_BUFFER_SIZE; /** * The number of concurrent disk access stripes. */ protected volatile int diskAccessStripes = DEFAULT_DISK_ACCESS_STRIPES; /** * The interval in seconds between runs of the disk expiry thread. *

* 2 minutes is the default. * This is not the same thing as time to live or time to idle. When the thread runs it checks * these things. So this value is how often we check for expiry. */ protected volatile long diskExpiryThreadIntervalSeconds = DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS; /** * Indicates whether logging is enabled or not. False by default. * Only used when cache is clustered with Terracotta. */ protected volatile boolean logging = DEFAULT_LOGGING; /** * whether elements can overflow to off heap memory when the in-memory cache * has reached the set limit. */ protected volatile Boolean overflowToOffHeap; /** * The event listener factories added by BeanUtils. */ protected volatile List cacheEventListenerConfigurations = new ArrayList(); /** * The cache extension factories added by BeanUtils. */ protected volatile List cacheExtensionConfigurations = new ArrayList(); /** * The BootstrapCacheLoaderFactoryConfiguration. */ protected BootstrapCacheLoaderFactoryConfiguration bootstrapCacheLoaderFactoryConfiguration; /** * The CacheExceptionHandlerFactoryConfiguration. */ protected CacheExceptionHandlerFactoryConfiguration cacheExceptionHandlerFactoryConfiguration; /** * The TerracottaConfiguration. */ protected TerracottaConfiguration terracottaConfiguration; /** * The PinningConfiguration. */ protected volatile PinningConfiguration pinningConfiguration; /** * The CacheWriterConfiguration. */ protected CacheWriterConfiguration cacheWriterConfiguration = DEFAULT_CACHE_WRITER_CONFIGURATION; /** * The cache loader factories added by BeanUtils. */ protected volatile List cacheLoaderConfigurations = new ArrayList(); /** * The cache decorator factories added by BeanUtils. */ protected volatile List cacheDecoratorConfigurations = new ArrayList(); /** * The listeners for this configuration. */ protected volatile Set listeners = new CopyOnWriteArraySet(); private volatile Set dynamicSearchListeners = new CopyOnWriteArraySet(); private DynamicAttributesExtractor flexIndexer; private volatile boolean frozen; private volatile TransactionalMode transactionalMode; private volatile boolean statistics = DEFAULT_STATISTICS; private volatile CopyStrategyConfiguration copyStrategyConfiguration = DEFAULT_COPY_STRATEGY_CONFIGURATION.copy(); private volatile SizeOfPolicyConfiguration sizeOfPolicyConfiguration; private volatile PersistenceConfiguration persistenceConfiguration; private volatile ElementValueComparatorConfiguration elementValueComparatorConfiguration = new ElementValueComparatorConfiguration(); private volatile Boolean copyOnRead; private volatile Boolean copyOnWrite; private volatile boolean conflictingEternalValuesWarningLogged; private volatile Searchable searchable; private String maxBytesLocalHeapInput; private String maxBytesLocalOffHeapInput; private String maxBytesLocalDiskInput; private Long maxBytesLocalHeap; private Long maxBytesLocalOffHeap; private Long maxBytesLocalDisk; private Integer maxBytesLocalHeapPercentage; private Integer maxBytesLocalOffHeapPercentage; private Integer maxBytesLocalDiskPercentage; private PoolUsage onHeapPoolUsage; private PoolUsage offHeapPoolUsage; private PoolUsage onDiskPoolUsage; private volatile boolean maxEntriesLocalDiskExplicitlySet; private volatile boolean maxBytesLocalDiskExplicitlySet; private volatile boolean maxBytesLocalOffHeapExplicitlySet; private volatile ClassLoader classLoader = EhcacheDefaultClassLoader.getInstance(); /** * Default constructor. *

* Note that an empty Cache is not valid and must have extra configuration added which can be done * through the fluent methods in this class. Call validateConfiguration() to check your configuration. * * @see #validateCompleteConfiguration */ public CacheConfiguration() { // empty constructor } /** * Create a new cache configuration. *

* Extra configuration can added after construction via the fluent methods in this class. * Call validateConfiguration() to check your configuration. * * @param name the name of the cache. Note that "default" is a reserved name for the defaultCache. * @param maxEntriesLocalHeap the maximum number of elements in memory, before they are evicted (0 == no limit) * @see #validateCompleteConfiguration() */ public CacheConfiguration(String name, int maxEntriesLocalHeap) { this.name = name; verifyGreaterThanOrEqualToZero((long) maxEntriesLocalHeap, "maxEntriesLocalHeap"); this.maxEntriesLocalHeap = maxEntriesLocalHeap; } /** * Clones this object, following the usual contract. * * @return a copy, which independent other than configurations than cannot change. */ @Override public CacheConfiguration clone() { CacheConfiguration config; try { config = (CacheConfiguration) super.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } cloneCacheEventListenerConfigurations(config); cloneCacheExtensionConfigurations(config); if (bootstrapCacheLoaderFactoryConfiguration != null) { config.bootstrapCacheLoaderFactoryConfiguration = bootstrapCacheLoaderFactoryConfiguration.clone(); } if (cacheExceptionHandlerFactoryConfiguration != null) { config.cacheExceptionHandlerFactoryConfiguration = cacheExceptionHandlerFactoryConfiguration.clone(); } if (terracottaConfiguration != null) { config.terracottaConfiguration = terracottaConfiguration.clone(); } if (cacheWriterConfiguration != null) { config.cacheWriterConfiguration = cacheWriterConfiguration.clone(); } cloneCacheLoaderConfigurations(config); cloneCacheDecoratorConfigurations(config); config.listeners = new CopyOnWriteArraySet(); config.dynamicSearchListeners = new CopyOnWriteArraySet(); return config; } private void cloneCacheEventListenerConfigurations(CacheConfiguration config) { List copy = new ArrayList(); for (CacheEventListenerFactoryConfiguration item : cacheEventListenerConfigurations) { copy.add(item.clone()); } config.cacheEventListenerConfigurations = copy; } private void cloneCacheExtensionConfigurations(CacheConfiguration config) { List copy = new ArrayList(); for (CacheConfiguration.CacheExtensionFactoryConfiguration item : cacheExtensionConfigurations) { copy.add(item.clone()); } config.cacheExtensionConfigurations = copy; } private void cloneCacheLoaderConfigurations(CacheConfiguration config) { List copy = new ArrayList(); for (CacheConfiguration.CacheLoaderFactoryConfiguration item : cacheLoaderConfigurations) { copy.add(item.clone()); } config.cacheLoaderConfigurations = copy; } private void cloneCacheDecoratorConfigurations(CacheConfiguration config) { List copy = new ArrayList(); for (CacheDecoratorFactoryConfiguration item : cacheDecoratorConfigurations) { copy.add(item.clone()); } config.cacheDecoratorConfigurations = copy; } private void assertArgumentNotNull(String name, Object object) { if (object == null) { throw new IllegalArgumentException(name + " cannot be null"); } } /** * Sets the name of the cache. *

* Cache names have constraints on the characters they can use: *

    *
  • the '/' character is illegal,
  • *
  • the '#' character does not work with RMI replication,
  • *
  • caches that are registered as MBeans must obey the {@link javax.management.ObjectName} rules for unquoted value. * This means the following characters are illegal: ',', '=', ':', '"', '*' and '?'.
  • *
* Note that caches inside a clustered cache manager are by default registered as MBean. * * @param name the cache name. This must be unique. */ public final void setName(String name) { checkDynamicChange(); assertArgumentNotNull("Cache name", name); this.name = name; } /** * Builder to set the name of the cache. *

* Cache names have constraints on the characters they can use: *

    *
  • the '/' character is illegal,
  • *
  • the '#' character does not work with RMI replication,
  • *
  • caches that are registered as MBeans must obey the {@link javax.management.ObjectName} rules for unquoted value. * This means the following characters are illegal: ',', '=', ':', '"', '*' and '?'.
  • *
* Note that caches inside a clustered cache manager are by default registered as MBean. * * @param name the cache name. This must be unique. * @return this configuration instance * @see #setName(String) */ public final CacheConfiguration name(String name) { setName(name); return this; } /** * Enables or disables logging for the cache *

* This property can be modified dynamically while the cache is operating. * Only used when cache is clustered with Terracotta * * @param enable If true, enables logging otherwise disables logging */ public final void setLogging(boolean enable) { checkDynamicChange(); boolean oldLoggingEnabled = this.logging; this.logging = enable; fireLoggingChanged(oldLoggingEnabled, enable); } /** * Enables or disables offheap store for the cache. * * @param overflowToOffHeap If true, enables offheap store otherwise disables it. */ public final void setOverflowToOffHeap(boolean overflowToOffHeap) { checkDynamicChange(); this.overflowToOffHeap = overflowToOffHeap; } /** * Builder to enable or disable offheap store for the cache. * * @param overflowToOffHeap If true, enables offheap store otherwise disables it. * @return this configuration instance * @see #setOverflowToOffHeap(boolean) */ public CacheConfiguration overflowToOffHeap(boolean overflowToOffHeap) { setOverflowToOffHeap(overflowToOffHeap); return this; } /** * Sets the SizeOfPolicyConfiguration for this cache. * * @param sizeOfPolicyConfiguration the SizeOfPolicy Configuration */ public void addSizeOfPolicy(SizeOfPolicyConfiguration sizeOfPolicyConfiguration) { this.sizeOfPolicyConfiguration = sizeOfPolicyConfiguration; } /** * Builder to set the SizeOfPolicyConfiguration for this cache. * * @param sizeOfPolicyConfiguration the SizeOfPolicy Configuration * @return this configuration instance * @see #addSizeOfPolicy(SizeOfPolicyConfiguration) */ public CacheConfiguration sizeOfPolicy(SizeOfPolicyConfiguration sizeOfPolicyConfiguration) { addSizeOfPolicy(sizeOfPolicyConfiguration); return this; } /** * Sets the PersistenceConfiguration for this cache. * * @param persistenceConfiguration the Persistence Configuration */ public void addPersistence(PersistenceConfiguration persistenceConfiguration) { if (diskPersistent != null) { throw new InvalidConfigurationException("Cannot use both and diskPersistent in a single cache configuration."); } if (Boolean.TRUE.equals(overflowToDisk)) { throw new InvalidConfigurationException("Cannot use both and overflowToDisk in a single cache configuration."); } this.persistenceConfiguration = persistenceConfiguration; } /** * Builder to set the PersistenceConfiguration for this cache. * * @param persistenceConfiguration the Persistence Configuration * @return this configuration instance * @see #addPersistence(PersistenceConfiguration) */ public CacheConfiguration persistence(PersistenceConfiguration persistenceConfiguration) { addPersistence(persistenceConfiguration); return this; } /** * Sets the max off heap memory size allocated for this cache. * * @param maxMemoryOffHeap the max off heap memory size allocated for this cache. * @deprecated See {@link #setMaxBytesLocalOffHeap(java.lang.String)} */ @Deprecated public final void setMaxMemoryOffHeap(String maxMemoryOffHeap) { checkDynamicChange(); assertArgumentNotNull("Cache maxMemoryOffHeap", maxMemoryOffHeap); setMaxBytesLocalOffHeap(maxMemoryOffHeap); } /** * Builder to set the max off heap memory size allocated for this cache. * * @param maxMemoryOffHeap the max off heap memory size allocated for this cache. * @return this configuration instance * @deprecated See {@link #maxBytesLocalOffHeap(long, net.sf.ehcache.config.MemoryUnit)} */ @Deprecated public CacheConfiguration maxMemoryOffHeap(String maxMemoryOffHeap) { setMaxMemoryOffHeap(maxMemoryOffHeap); return this; } /** * Builder to enable or disable logging for the cache *

* This property can be modified dynamically while the cache is operating. * Only used when cache is clustered with Terracotta * * @param enable If true, enables logging otherwise disables logging * @return this configuration instance * @see #setLogging(boolean) */ public final CacheConfiguration logging(boolean enable) { setLogging(enable); return this; } /** * Sets the maximum objects to be held in memory (0 = no limit). *

* This property can be modified dynamically while the cache is operating. * * @param maxElementsInMemory The maximum number of elements in memory, before they are evicted (0 == no limit) * @deprecated use {@link #setMaxEntriesLocalHeap(long)} */ @Deprecated public final void setMaxElementsInMemory(int maxElementsInMemory) { setMaxEntriesLocalHeap(maxElementsInMemory); } /** * Sets the maximum objects to be held in local heap memory (0 = no limit). *

* This property can be modified dynamically while the cache is operating. * * @param maxEntriesLocalHeap The maximum number of elements in memory, before they are evicted (0 == no limit) */ public final void setMaxEntriesLocalHeap(long maxEntriesLocalHeap) { verifyGreaterThanOrEqualToZero(maxEntriesLocalHeap, "maxEntriesLocalHeap"); if (maxEntriesLocalHeap > Integer.MAX_VALUE) { throw new IllegalArgumentException("Values larger than Integer.MAX_VALUE are not currently supported."); } checkDynamicChange(); if (onHeapPoolUsage != null && onHeapPoolUsage != PoolUsage.None) { throw new InvalidConfigurationException("MaxEntriesLocalHeap is not compatible with " + "MaxBytesLocalHeap set on cache"); } int oldCapacity = this.maxEntriesLocalHeap == null ? 0 : this.maxEntriesLocalHeap; int newCapacity = (int) maxEntriesLocalHeap; this.maxEntriesLocalHeap = (int) maxEntriesLocalHeap; fireMemoryCapacityChanged(oldCapacity, newCapacity); } /** * Builder that sets the maximum objects to be held in memory (0 = no limit). *

* This property can be modified dynamically while the cache is operating. * * @param maxElementsInMemory The maximum number of elements in memory, before they are evicted (0 == no limit) * @return this configuration instance * @deprecated use {@link #maxEntriesLocalHeap(int)} */ @Deprecated public final CacheConfiguration maxElementsInMemory(int maxElementsInMemory) { setMaxElementsInMemory(maxElementsInMemory); return this; } /** * Builder that sets the maximum objects to be held in memory (0 = no limit). *

* This property can be modified dynamically while the cache is operating. * * @param maxElementsInMemory The maximum number of elements in memory, before they are evicted (0 == no limit) * @return this configuration instance */ public final CacheConfiguration maxEntriesLocalHeap(int maxElementsInMemory) { setMaxEntriesLocalHeap(maxElementsInMemory); return this; } /** * Sets the timeout for CacheLoader execution (0 = no timeout). * * @param cacheLoaderTimeoutMillis the timeout in milliseconds. */ public final void setCacheLoaderTimeoutMillis(long cacheLoaderTimeoutMillis) { checkDynamicChange(); this.cacheLoaderTimeoutMillis = cacheLoaderTimeoutMillis; } /** * Builder that sets the timeout for CacheLoader execution (0 = no timeout). * @param timeoutMillis the timeout in milliseconds. * @return this configuration instance */ public CacheConfiguration timeoutMillis(long timeoutMillis) { setCacheLoaderTimeoutMillis(timeoutMillis); return this; } /** * Sets the eviction policy. An invalid argument will set it to LRU. * * @param memoryStoreEvictionPolicy a String representation of the policy. One of "LRU", "LFU" or "FIFO". */ public final void setMemoryStoreEvictionPolicy(String memoryStoreEvictionPolicy) { assertArgumentNotNull("Cache memoryStoreEvictionPolicy", memoryStoreEvictionPolicy); setMemoryStoreEvictionPolicyFromObject(MemoryStoreEvictionPolicy.fromString(memoryStoreEvictionPolicy)); } /** * Builder that sets the eviction policy. An invalid argument will set it to null. * * @param memoryStoreEvictionPolicy a String representation of the policy. One of "LRU", "LFU" or "FIFO". * @return this configuration instance * @see #setMemoryStoreEvictionPolicy(String) */ public final CacheConfiguration memoryStoreEvictionPolicy(String memoryStoreEvictionPolicy) { setMemoryStoreEvictionPolicy(memoryStoreEvictionPolicy); return this; } /** * Sets the eviction policy. This method has a strange name to workaround a problem with XML parsing. */ public final void setMemoryStoreEvictionPolicyFromObject(MemoryStoreEvictionPolicy memoryStoreEvictionPolicy) { checkDynamicChange(); if (null == memoryStoreEvictionPolicy) { this.memoryStoreEvictionPolicy = DEFAULT_MEMORY_STORE_EVICTION_POLICY; } else { this.memoryStoreEvictionPolicy = memoryStoreEvictionPolicy; } } /** * Builder which Sets the eviction policy. An invalid argument will set it to null. * * @return this configuration instance * @see #setMemoryStoreEvictionPolicyFromObject(MemoryStoreEvictionPolicy) */ public final CacheConfiguration memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy memoryStoreEvictionPolicy) { setMemoryStoreEvictionPolicyFromObject(memoryStoreEvictionPolicy); return this; } /** * Sets whether the MemoryStore should be cleared when * {@link net.sf.ehcache.Ehcache#flush flush()} is called on the cache - true by default. * * @param clearOnFlush true to clear on flush */ public final void setClearOnFlush(boolean clearOnFlush) { checkDynamicChange(); this.clearOnFlush = clearOnFlush; } /** * Builder which sets whether the MemoryStore should be cleared when * {@link net.sf.ehcache.Ehcache#flush flush()} is called on the cache - true by default. * * @param clearOnFlush true to clear on flush * @return this configuration instance * @see #setClearOnFlush(boolean) */ public final CacheConfiguration clearOnFlush(boolean clearOnFlush) { setClearOnFlush(clearOnFlush); return this; } /** * Sets whether elements are eternal. If eternal, timeouts are ignored and the element is never expired. False by default. * * @param eternal true for eternal */ public final void setEternal(boolean eternal) { checkDynamicChange(); isEternalValueConflictingWithTTIOrTTL(eternal, getTimeToLiveSeconds(), getTimeToIdleSeconds()); this.eternal = eternal; if (eternal) { setTimeToIdleSeconds(0); setTimeToLiveSeconds(0); } } private boolean isEternalValueConflictingWithTTIOrTTL(boolean newEternalValue, long newTTLValue, long newTTIValue) { boolean conflicting = false; if (newEternalValue && (newTTLValue != 0 || newTTIValue != 0)) { conflicting = true; } if (conflicting && !conflictingEternalValuesWarningLogged) { conflictingEternalValuesWarningLogged = true; LOG.warn("Cache '" + getName() + "' is set to eternal but also has TTI/TTL set. " + " To avoid this warning, clean up the config " + "removing conflicting values of eternal," + " TTI and TTL. Effective configuration for Cache '" + getName() + "' will be eternal='" + newEternalValue + "', timeToIdleSeconds='0', timeToLiveSeconds='0'."); } return conflicting; } /** * Builder which sets whether elements are eternal. If eternal, timeouts are ignored and the element is never expired. False by default. * * @param eternal true for eternal * @return this configuration instance * @see #setEternal(boolean) */ public final CacheConfiguration eternal(boolean eternal) { setEternal(eternal); return this; } /** * Sets the time to idle for an element before it expires. Is only used if the element is not eternal. This can be overidden in * {@link net.sf.ehcache.Element} *

* This property can be modified dynamically while the cache is operating. * * @param timeToIdleSeconds the default amount of time to live for an element from its last accessed or modified date */ public final void setTimeToIdleSeconds(long timeToIdleSeconds) { checkDynamicChange(); verifyGreaterThanOrEqualToZero(timeToIdleSeconds, "timeToIdleSeconds"); if (!isEternalValueConflictingWithTTIOrTTL(eternal, 0, timeToIdleSeconds)) { long oldTti = this.timeToIdleSeconds; long newTti = timeToIdleSeconds; this.timeToIdleSeconds = timeToIdleSeconds; fireTtiChanged(oldTti, newTti); } } /** * Builder which sets the time to idle for an element before it expires. Is only used if the element is not eternal. * This default can be overridden in {@link net.sf.ehcache.Element} *

* This property can be modified dynamically while the cache is operating. * * @param timeToIdleSeconds the default amount of time to live for an element from its last accessed or modified date * @return this configuration instance * @see #setTimeToIdleSeconds(long) */ public final CacheConfiguration timeToIdleSeconds(long timeToIdleSeconds) { setTimeToIdleSeconds(timeToIdleSeconds); return this; } /** * Sets the time to idle for an element before it expires. Is only used if the element is not eternal. * This default can be overridden in {@link net.sf.ehcache.Element} *

* This property can be modified dynamically while the cache is operating. * * @param timeToLiveSeconds the default amount of time to live for an element from its creation date */ public final void setTimeToLiveSeconds(long timeToLiveSeconds) { checkDynamicChange(); verifyGreaterThanOrEqualToZero(timeToLiveSeconds, "timeToLiveSeconds"); if (!isEternalValueConflictingWithTTIOrTTL(eternal, timeToLiveSeconds, 0)) { long oldTtl = this.timeToLiveSeconds; long newTtl = timeToLiveSeconds; this.timeToLiveSeconds = timeToLiveSeconds; fireTtlChanged(oldTtl, newTtl); } } /** * Builder which sets the time to idle for an element before it expires. Is only used if the element is not eternal. * This default can be overridden in {@link net.sf.ehcache.Element} *

* This property can be modified dynamically while the cache is operating. * * @param timeToLiveSeconds the default amount of time to live for an element from its creation date * @return this configuration instance * @see #setTimeToLiveSeconds(long) */ public final CacheConfiguration timeToLiveSeconds(long timeToLiveSeconds) { setTimeToLiveSeconds(timeToLiveSeconds); return this; } /** * Sets whether elements can overflow to disk when the in-memory cache has reached the set limit. * * @param overflowToDisk whether to use the disk store * @deprecated The {@code overflowToDisk} attribute has been replaced with {@link Strategy#LOCALTEMPSWAP}. */ @Deprecated public final void setOverflowToDisk(boolean overflowToDisk) { checkDynamicChange(); if (persistenceConfiguration != null && Boolean.TRUE.equals(overflowToDisk)) { throw new InvalidConfigurationException("Cannot use both and overflowToDisk in a single cache configuration."); } this.overflowToDisk = overflowToDisk; validateConfiguration(); } /** * Builder which sets whether elements can overflow to disk when the in-memory cache has reached the set limit. * * @param overflowToDisk whether to use the disk store * @return this configuration instance * @see #setOverflowToDisk(boolean) * @deprecated The {@code overflowToDisk} attribute has been replaced with {@link Strategy#LOCALTEMPSWAP}. */ @Deprecated public final CacheConfiguration overflowToDisk(boolean overflowToDisk) { setOverflowToDisk(overflowToDisk); return this; } /** * Sets whether the disk store persists between CacheManager instances. Note that this operates independently of {@link #overflowToDisk}. * * @param diskPersistent whether to persist the cache to disk between JVM restarts * @deprecated The {@code diskPersistent} attribute has been replaced with {@link #persistence(PersistenceConfiguration)}. */ @Deprecated public final void setDiskPersistent(boolean diskPersistent) { checkDynamicChange(); if (persistenceConfiguration != null) { throw new InvalidConfigurationException("Cannot use both and diskPersistent in a single cache configuration."); } this.diskPersistent = diskPersistent; validateConfiguration(); } /** * Builder which sets whether the disk store persists between CacheManager instances. Note that this operates independently of {@link #overflowToDisk}. * * @param diskPersistent whether to persist the cache to disk between JVM restarts. * @return this configuration instance * @see #setDiskPersistent(boolean) * @deprecated The {@code diskPersistent} attribute has been replaced with {@link #persistence(PersistenceConfiguration)}. */ @Deprecated public final CacheConfiguration diskPersistent(boolean diskPersistent) { setDiskPersistent(diskPersistent); return this; } /** * Sets the disk spool size, which is used to buffer writes to the DiskStore. * If not set it defaults to {@link #DEFAULT_SPOOL_BUFFER_SIZE} * * @param diskSpoolBufferSizeMB a positive number */ public void setDiskSpoolBufferSizeMB(int diskSpoolBufferSizeMB) { checkDynamicChange(); if (diskSpoolBufferSizeMB <= 0) { this.diskSpoolBufferSizeMB = DEFAULT_SPOOL_BUFFER_SIZE; } else { this.diskSpoolBufferSizeMB = diskSpoolBufferSizeMB; } } /** * Builder which sets the disk spool size, which is used to buffer writes to the DiskStore. * If not set it defaults to {@link #DEFAULT_SPOOL_BUFFER_SIZE} * * @param diskSpoolBufferSizeMB a positive number * @return this configuration instance * @see #setDiskSpoolBufferSizeMB(int) */ public final CacheConfiguration diskSpoolBufferSizeMB(int diskSpoolBufferSizeMB) { setDiskSpoolBufferSizeMB(diskSpoolBufferSizeMB); return this; } /** * Sets the number of disk stripes. RandomAccessFiles used to access the data file. By default there * is one stripe. * * @param stripes number of stripes (rounded up to a power-of-2) */ public void setDiskAccessStripes(int stripes) { checkDynamicChange(); if (stripes <= 0) { this.diskAccessStripes = DEFAULT_DISK_ACCESS_STRIPES; } else { this.diskAccessStripes = stripes; } } /** * Builder which sets the number of disk stripes. RandomAccessFiles used to access the data file. By default there * is one stripe. * * @return this configuration instance * @see #setDiskAccessStripes(int) */ public final CacheConfiguration diskAccessStripes(int stripes) { setDiskAccessStripes(stripes); return this; } /** * Sets the maximum number elements on Disk. 0 means unlimited. *

* This property can be modified dynamically while the cache is operating. * * @param maxElementsOnDisk the maximum number of Elements to allow on the disk. 0 means unlimited. * @deprecated use {@link #setMaxEntriesLocalDisk(long)} for unclustered caches and {@link #setMaxEntriesInCache(long)} for clustered caches. */ public void setMaxElementsOnDisk(int maxElementsOnDisk) { if (onDiskPoolUsage != null && onDiskPoolUsage != PoolUsage.None) { throw new InvalidConfigurationException("MaxEntriesLocalDisk is not compatible with " + "MaxBytesLocalDisk set on cache"); } verifyGreaterThanOrEqualToZero((long) maxElementsOnDisk, "maxElementsOnDisk"); checkDynamicChange(); int oldCapacity = this.maxElementsOnDisk; this.maxElementsOnDisk = maxElementsOnDisk; fireDiskCapacityChanged(oldCapacity, this.maxElementsOnDisk); } /** * Sets the maximum number of entries in the cache. Only applies to terracotta clustered caches. *

* The values for maxEntriesInCache must be equal or superior to 0 and are interpreted as follows: *

    *
  • {@code maxEntriesInCache == 0} means no capacity based eviction, but resource based eviction can happen.
  • *
  • {@code maxEntriesInCache > 0} means both capacity based and resource based eviction can happen *
*

* This property can be modified dynamically while the cache is operating. * * @param maxEntriesInCache maximum number of entries in cache */ public void setMaxEntriesInCache(long maxEntriesInCache) { checkDynamicChange(); verifyGreaterThanOrEqualToZero((long)maxEntriesInCache, "maxEntriesInCache"); checkIfCachePinned(maxEntriesInCache); long oldValue = this.maxEntriesInCache; this.maxEntriesInCache = maxEntriesInCache; fireMaxEntriesInCacheChanged(oldValue, this.maxEntriesInCache); } private void checkIfCachePinned(long maxEntriesInCache) { if (maxEntriesInCache != DEFAULT_MAX_ENTRIES_IN_CACHE && getPinningConfiguration() != null && Store.INCACHE.equals(getPinningConfiguration().getStore())) { throw new InvalidConfigurationException("Setting maxEntriesInCache on an in-cache pinned cache is not legal"); } } /** * Sets the maximum number elements on Disk. 0 means unlimited. *

* This property can be modified dynamically while the cache is operating. * * @param maxEntriesLocalDisk the maximum number of Elements to allow on the disk. 0 means unlimited. */ public void setMaxEntriesLocalDisk(long maxEntriesLocalDisk) { if (isTerracottaClustered()) { throw new InvalidConfigurationException("MaxEntriesLocalDisk is not applicable for Terracotta clustered caches"); } verifyGreaterThanOrEqualToZero(maxEntriesLocalDisk, "maxEntriesLocalDisk"); if (maxEntriesLocalDisk > Integer.MAX_VALUE) { throw new IllegalArgumentException("Values greater than Integer.MAX_VALUE are not currently supported."); } // This check against pool usage is only there to see if this configuration backs up a running cache if (onDiskPoolUsage != null && isTerracottaClustered()) { throw new IllegalStateException("Can't use local disks with Terracotta clustered caches!"); } maxEntriesLocalDiskExplicitlySet = true; setMaxElementsOnDisk((int)maxEntriesLocalDisk); } /** * Builder which sets the maximum number elements on Disk. 0 means unlimited. *

* This property can be modified dynamically while the cache is operating. * * @param maxElementsOnDisk the maximum number of Elements to allow on the disk. 0 means unlimited. * @return this configuration instance * @see #setMaxElementsOnDisk(int) * @deprecated use {@link #maxEntriesLocalDisk(int)} for unclustered caches and {@link #maxEntriesInCache(long)} for clustered caches. */ public final CacheConfiguration maxElementsOnDisk(int maxElementsOnDisk) { setMaxElementsOnDisk(maxElementsOnDisk); return this; } /** * Builder which sets the maximum number entries in cache. *

* This property can be modified dynamically while the cache is operating. * * @param maxEntriesInCache the maximum number of entries to allow in the cache. * @return this configuration instance * @see #setMaxEntriesInCache(long) */ public final CacheConfiguration maxEntriesInCache(long maxEntriesInCache) { setMaxEntriesInCache(maxEntriesInCache); return this; } /** * Builder which sets the maximum number elements on Disk. 0 means unlimited. *

* This property can be modified dynamically while the cache is operating. * * @param maxElementsOnDisk the maximum number of Elements to allow on the disk. 0 means unlimited. * @return this configuration instance * @see #setMaxElementsOnDisk(int) */ public final CacheConfiguration maxEntriesLocalDisk(int maxElementsOnDisk) { setMaxEntriesLocalDisk(maxElementsOnDisk); return this; } /** * Sets the interval in seconds between runs of the disk expiry thread. *

* 2 minutes is the default. * This is not the same thing as time to live or time to idle. When the thread runs it checks * these things. So this value is how often we check for expiry. */ public final void setDiskExpiryThreadIntervalSeconds(long diskExpiryThreadIntervalSeconds) { checkDynamicChange(); if (diskExpiryThreadIntervalSeconds <= 0) { this.diskExpiryThreadIntervalSeconds = DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS; } else { this.diskExpiryThreadIntervalSeconds = diskExpiryThreadIntervalSeconds; } } /** * Builder which sets the interval in seconds between runs of the disk expiry thread. *

* 2 minutes is the default. * This is not the same thing as time to live or time to idle. When the thread runs it checks * these things. So this value is how often we check for expiry. * * @return this configuration instance * @see #setDiskExpiryThreadIntervalSeconds(long) */ public final CacheConfiguration diskExpiryThreadIntervalSeconds(long diskExpiryThreadIntervalSeconds) { setDiskExpiryThreadIntervalSeconds(diskExpiryThreadIntervalSeconds); return this; } /** * Freeze this configuration. Any subsequent changes will throw a CacheException */ public void freezeConfiguration() { frozen = true; if (searchable != null) { searchable.freezeConfiguration(); } } /** * @return true is this configuration is frozen - it cannot be changed dynamically. */ public boolean isFrozen() { return frozen; } /** * Getter to the configured ReadWriteCopyStrategy. * This will always return the same unique instance per cache * * @return the {@link ReadWriteCopyStrategy} for instance for this cache */ public ReadWriteCopyStrategy getCopyStrategy() { // todo really make this pluggable through config! return copyStrategyConfiguration.getCopyStrategyInstance(getClassLoader()); } /** * Whether the Cache should copy elements it returns * * @param copyOnRead true, if copyOnRead */ public CacheConfiguration copyOnRead(boolean copyOnRead) { this.setCopyOnRead(copyOnRead); return this; } /** * Whether the Cache should copy elements it returns * * @return true, is copyOnRead */ public boolean isCopyOnRead() { validateTransactionalSettings(); return copyOnRead; } /** * Whether the Cache should copy elements it returns * * @param copyOnRead true, if copyOnRead */ public void setCopyOnRead(final boolean copyOnRead) { this.copyOnRead = copyOnRead; } /** * Whether the Cache should copy elements it gets * * @param copyOnWrite true, if copyOnWrite */ public CacheConfiguration copyOnWrite(boolean copyOnWrite) { this.copyOnWrite = copyOnWrite; return this; } /** * Whether the Cache should copy elements it gets * * @return true, if copyOnWrite */ public boolean isCopyOnWrite() { validateTransactionalSettings(); return copyOnWrite; } /** * Whether the Cache should copy elements it gets * * @param copyOnWrite true, if copyOnWrite */ public void setCopyOnWrite(final boolean copyOnWrite) { this.copyOnWrite = copyOnWrite; } /** * Sets the CopyStrategyConfiguration for this cache * * @param copyStrategyConfiguration the CopyStrategy Configuration */ public void addCopyStrategy(CopyStrategyConfiguration copyStrategyConfiguration) { this.copyStrategyConfiguration = copyStrategyConfiguration; } /** * Sets the ElementValueComparatorConfiguration for this cache * The default configuration will setup a {@link net.sf.ehcache.store.DefaultElementValueComparator} * * @param elementValueComparatorConfiguration the ElementComparator Configuration */ public void addElementValueComparator(ElementValueComparatorConfiguration elementValueComparatorConfiguration) { this.elementValueComparatorConfiguration = elementValueComparatorConfiguration; } /** * Add configuration to make this cache searchable * * @param searchable search config to add */ public final void addSearchable(Searchable searchable) { checkDynamicChange(); this.searchable = searchable; } /** * The maximum amount of bytes the cache should occupy on heap * @return value in bytes, 0 if none set */ public long getMaxBytesLocalHeap() { return maxBytesLocalHeap == null ? DEFAULT_MAX_BYTES_ON_HEAP : maxBytesLocalHeap; } /** * Setter for maxBytesLocalHeap as a String. Value can have a one char unit suffix or be a percentage (ending in %) *

* This property can be modified dynamically while the cache is operating. * * @param maxBytesHeap String representation of the size, can be relative (in %) */ public void setMaxBytesLocalHeap(final String maxBytesHeap) { assertArgumentNotNull("Cache maxBytesLocalHeap", maxBytesHeap); if (isPercentage(maxBytesHeap)) { maxBytesLocalHeapPercentage = parsePercentage(maxBytesHeap); } else { setMaxBytesLocalHeap(MemoryUnit.parseSizeInBytes(maxBytesHeap)); } maxBytesLocalHeapInput = maxBytesHeap; } /** * Setter for maxBytesLocalHeap in bytes *

* This property can be modified dynamically while the cache is operating. * * @param maxBytesHeap max bytes in heap in bytes */ public void setMaxBytesLocalHeap(final Long maxBytesHeap) { if (onHeapPoolUsage != null && getMaxEntriesLocalHeap() > 0) { throw new InvalidConfigurationException("MaxEntriesLocalHeap is not compatible with " + "MaxBytesLocalHeap set on cache"); } if (onHeapPoolUsage != null && onHeapPoolUsage != PoolUsage.Cache) { throw new IllegalStateException("A Cache can't switch memory pool!"); } checkDynamicChange(); verifyGreaterThanZero(maxBytesHeap, "maxBytesLocalHeap"); Long oldValue = this.maxBytesLocalHeap; this.maxBytesLocalHeap = maxBytesHeap; fireMaxBytesOnLocalHeapChanged(oldValue, maxBytesHeap); } private void fireMaxBytesOnLocalHeapChanged(final Long oldValue, final Long newValue) { if ((oldValue != null && !oldValue.equals(newValue)) || (newValue != null && !newValue.equals(oldValue))) { for (CacheConfigurationListener listener : listeners) { listener.maxBytesLocalHeapChanged(oldValue != null ? oldValue : 0, newValue); } } } private void fireMaxBytesOnLocalDiskChanged(final Long oldValue, final Long newValue) { if ((oldValue != null && !oldValue.equals(newValue)) || (newValue != null && !newValue.equals(oldValue))) { for (CacheConfigurationListener listener : listeners) { listener.maxBytesLocalDiskChanged(oldValue != null ? oldValue : 0, newValue); } } } private void fireDynamicAttributesExtractorAdded(DynamicAttributesExtractor oldValue, DynamicAttributesExtractor newValue) { if (oldValue != newValue) { for (DynamicSearchListener lsnr : dynamicSearchListeners) { lsnr.extractorChanged(oldValue, newValue); } } } /** * Sets the maxOnHeap size * @param amount the amount of unit * @param memoryUnit the actual unit * @return this */ public CacheConfiguration maxBytesLocalHeap(final long amount, final MemoryUnit memoryUnit) { setMaxBytesLocalHeap(memoryUnit.toBytes(amount)); return this; } /** * The maximum amount of bytes the cache should occupy off heap * @return value in bytes, 0 if none set */ public long getMaxBytesLocalOffHeap() { return maxBytesLocalOffHeap == null ? DEFAULT_MAX_BYTES_OFF_HEAP : maxBytesLocalOffHeap; } /** * The string form of the maximum amount of bytes the cache should occupy off heap * @return value as string in bytes */ public String getMaxBytesLocalOffHeapAsString() { return maxBytesLocalOffHeapInput != null ? maxBytesLocalOffHeapInput : Long.toString(getMaxBytesLocalOffHeap()); } /** * Setter for maximum bytes off heap as a String. Value can have a one char unit suffix or be a percentage (ending in %) *

* Changes to this property once the cache is operating will have no effect. * * @param maxBytesOffHeap String representation of the size, can be relative (in %) */ public void setMaxBytesLocalOffHeap(final String maxBytesOffHeap) { assertArgumentNotNull("Cache maxBytesLocalOffHeap", maxBytesOffHeap); if (isPercentage(maxBytesOffHeap)) { maxBytesLocalOffHeapPercentage = parsePercentage(maxBytesOffHeap); } else { setMaxBytesLocalOffHeap(MemoryUnit.parseSizeInBytes(maxBytesOffHeap)); } maxBytesLocalOffHeapInput = maxBytesOffHeap; maxBytesLocalOffHeapExplicitlySet = true; } /** * Getter for maximum bytes off heap expressed as a percentage * @return percentage (between 0 and 100) */ public Integer getMaxBytesLocalOffHeapPercentage() { return maxBytesLocalOffHeapPercentage; } /** * Getter for maximum bytes on heap expressed as a percentage * @return percentage (between 0 and 100) */ public Integer getMaxBytesLocalHeapPercentage() { return maxBytesLocalHeapPercentage; } /** * The string form of the maximum amount of bytes the cache should occupy on heap * @return value as string in bytes */ public String getMaxBytesLocalHeapAsString() { return maxBytesLocalHeapInput != null ? maxBytesLocalHeapInput : Long.toString(getMaxBytesLocalHeap()); } /** * Getter for maximum bytes on disk expressed as a percentage * @return percentage (between 0 and 100) */ public Integer getMaxBytesLocalDiskPercentage() { return maxBytesLocalDiskPercentage; } private int parsePercentage(final String stringValue) { String trimmed = stringValue.trim(); int percentage = Integer.parseInt(trimmed.substring(0, trimmed.length() - 1)); if (percentage > HUNDRED_PERCENT || percentage < 0) { throw new IllegalArgumentException("Percentage need values need to be between 0 and 100 inclusive, but got : " + percentage); } return percentage; } private boolean isPercentage(final String stringValue) { String trimmed = stringValue.trim(); return trimmed.charAt(trimmed.length() - 1) == '%'; } /** * Sets the maximum amount of bytes the cache being configured will use on the OffHeap tier *

* Changes to this property once the cache is operating will have no effect. * * @param maxBytesOffHeap max bytes on disk in bytes */ public void setMaxBytesLocalOffHeap(final Long maxBytesOffHeap) { if (offHeapPoolUsage != null) { throw new IllegalStateException("OffHeap can't be set dynamically!"); } verifyGreaterThanZero(maxBytesOffHeap, "maxBytesLocalOffHeap"); this.maxBytesLocalOffHeapExplicitlySet = true; this.maxBytesLocalOffHeap = maxBytesOffHeap; } /** * Sets the maxOffHeap tier size *

* Changes to this property once the cache is operating will have no effect. * * @param amount the amount of unit * @param memoryUnit the actual unit * @return this */ public CacheConfiguration maxBytesLocalOffHeap(final long amount, final MemoryUnit memoryUnit) { setMaxBytesLocalOffHeap(memoryUnit.toBytes(amount)); return this; } /** * The maximum amount of bytes the cache should occupy on disk * @return value in bytes, 0 if none set */ public long getMaxBytesLocalDisk() { return maxBytesLocalDisk == null ? DEFAULT_MAX_BYTES_ON_DISK : maxBytesLocalDisk; } /** * The string form of the maximum amount of bytes the cache should occupy on disk * @return value as string in bytes */ public String getMaxBytesLocalDiskAsString() { return maxBytesLocalDiskInput != null ? maxBytesLocalDiskInput : Long.toString(getMaxBytesLocalDisk()); } /** * Setter for maxBytesOnDisk as a String. Value can have a one char unit suffix or be a percentage (ending in %) *

* This property can be modified dynamically while the cache is operating. * * @param maxBytesDisk String representation of the size, can be relative (in %) */ public void setMaxBytesLocalDisk(final String maxBytesDisk) { assertArgumentNotNull("Cache maxBytesLocalDisk", maxBytesDisk); if (isPercentage(maxBytesDisk)) { maxBytesLocalDiskPercentage = parsePercentage(maxBytesDisk); } else { setMaxBytesLocalDisk(MemoryUnit.parseSizeInBytes(maxBytesDisk)); } maxBytesLocalDiskExplicitlySet = true; maxBytesLocalDiskInput = maxBytesDisk; } /** * Sets the maximum amount of bytes the cache being configured will use on the OnDisk tier *

* This property can be modified dynamically while the cache is operating. * * @param maxBytesDisk max bytes on disk in bytes */ public void setMaxBytesLocalDisk(final Long maxBytesDisk) { if (isTerracottaClustered()) { throw new InvalidConfigurationException("MaxBytesLocalDisk is not applicable for Terracotta clustered caches"); } if (onDiskPoolUsage != null && getMaxEntriesLocalDisk() > 0) { throw new InvalidConfigurationException("MaxEntriesLocalDisk is not compatible with " + "MaxBytesLocalDisk set on cache"); } if (onDiskPoolUsage != null && onDiskPoolUsage != PoolUsage.Cache) { throw new IllegalStateException("A Cache can't switch disk pool!"); } checkDynamicChange(); verifyGreaterThanZero(maxBytesDisk, "maxBytesLocalDisk"); maxBytesLocalDiskExplicitlySet = true; Long oldValue = this.maxBytesLocalDisk; this.maxBytesLocalDisk = maxBytesDisk; fireMaxBytesOnLocalDiskChanged(oldValue, maxBytesDisk); } /** * Sets the maxOnDisk size *

* This property can be modified dynamically while the cache is operating. * * @param amount the amount of unit * @param memoryUnit the actual unit * @return this */ public CacheConfiguration maxBytesLocalDisk(final long amount, final MemoryUnit memoryUnit) { setMaxBytesLocalDisk(memoryUnit.toBytes(amount)); return this; } /** * Sets dynamic search attributes extractor * @param extractor extractor to use */ public void setDynamicAttributesExtractor(DynamicAttributesExtractor extractor) { if (searchable == null || !searchable.isDynamicIndexingAllowed()) { throw new IllegalArgumentException("Dynamic search attribute extraction not supported"); } if (extractor == null && this.flexIndexer != null) { throw new IllegalArgumentException("Dynamic search attributes extractor cannot be set to null by user"); } DynamicAttributesExtractor old = this.flexIndexer; this.flexIndexer = extractor; fireDynamicAttributesExtractorAdded(old, this.flexIndexer); } /** * Sets dynamic search attributes extractor * @param extractor extractor to use * @return this */ public CacheConfiguration dynamicAttributeExtractor(DynamicAttributesExtractor extractor) { setDynamicAttributesExtractor(extractor); return this; } private void verifyGreaterThanZero(final Long fieldVal, final String fieldName) { if (fieldVal != null && fieldVal < 1) { throw new IllegalArgumentException("Illegal value " + fieldVal + " for " + fieldName + ": has to be larger than 0"); } } private void verifyGreaterThanOrEqualToZero(final Long fieldVal, final String fieldName) { if (fieldVal != null && fieldVal < 0) { throw new IllegalArgumentException("Illegal value " + fieldVal + " for " + fieldName + ": has to be larger than or equal to 0"); } } /** * Returns the copyStrategyConfiguration * * @return the copyStrategyConfiguration */ public CopyStrategyConfiguration getCopyStrategyConfiguration() { return this.copyStrategyConfiguration; } /** * Returns the elementComparatorConfiguration * * @return the elementComparatorConfiguration */ public ElementValueComparatorConfiguration getElementValueComparatorConfiguration() { return elementValueComparatorConfiguration; } /** * Checks whether the user explicitly set the maxBytesOnHeapPercentage * @return true if set by user, false otherwise * @see #setMaxBytesLocalHeap(String) */ public boolean isMaxBytesLocalHeapPercentageSet() { return maxBytesLocalHeapPercentage != null; } /** * Checks whether the user explicitly set the maxBytesOffHeapPercentage * @return true if set by user, false otherwise * @see #setMaxBytesLocalOffHeap(String) */ public boolean isMaxBytesLocalOffHeapPercentageSet() { return maxBytesLocalOffHeapPercentage != null; } /** * Checks whether the user explicitly set the maxBytesOnDiskPercentage * @return true if set by user, false otherwise * @see #setMaxBytesLocalDisk(String) */ public boolean isMaxBytesLocalDiskPercentageSet() { return maxBytesLocalDiskPercentage != null; } /** * Sets up the CacheConfiguration for runtime consumption, also registers this cache configuration with the cache manager's configuration * @param cacheManager The CacheManager as part of which the cache is being setup */ public void setupFor(final CacheManager cacheManager) { setupFor(cacheManager, true, null); } /** * Sets up the CacheConfiguration for runtime consumption * @param cacheManager The CacheManager as part of which the cache is being setup * @param register true to register this cache configuration with the cache manager. */ public void setupFor(final CacheManager cacheManager, final boolean register, final String parentCache) { final Collection errors = validate(cacheManager.getConfiguration()); configCachePools(cacheManager.getConfiguration()); errors.addAll(verifyPoolAllocationsBeforeAddingTo(cacheManager, cacheManager.getConfiguration().getMaxBytesLocalHeap(), cacheManager.getConfiguration().getMaxBytesLocalOffHeap(), cacheManager.getConfiguration().getMaxBytesLocalDisk(), parentCache)); if (!errors.isEmpty()) { throw new InvalidConfigurationException(errors); } if (!isTerracottaClustered()) { updateCacheManagerPoolSizes(cacheManager); } if (register) { registerCacheConfiguration(cacheManager); } if (cacheManager.getConfiguration().isMaxBytesLocalHeapSet() || cacheManager.getConfiguration().isMaxBytesLocalDiskSet()) { /*Adding Ourself as the first listener the order of the listener is important as DefaultCacheConfigurationListener does validation checking on pool sizes*/ addConfigurationListener(new DefaultCacheConfigurationListener(cacheManager)); } consolidatePersistenceSettings(cacheManager); if (overflowToOffHeap == null && (cacheManager.getConfiguration().isMaxBytesLocalOffHeapSet() || getMaxBytesLocalOffHeap() > 0)) { overflowToOffHeap = true; } if ((persistenceConfiguration != null && Strategy.LOCALTEMPSWAP.equals(persistenceConfiguration.getStrategy()))) { overflowToDisk = true; } if (overflowToDisk == null && cacheManager.getConfiguration().isMaxBytesLocalDiskSet() || getMaxBytesLocalDisk() > 0) { if (persistenceConfiguration != null && Strategy.LOCALRESTARTABLE.equals(persistenceConfiguration.getStrategy())) { throw new InvalidConfigurationException("Cannot use localRestartable persistence and disk overflow in the same cache"); } else if (!isTerracottaClustered()) { overflowToDisk = true; } else { LOG.warn("Clustered cache " + getName() + " will not use the local disk pool defined at cache manager level."); } } warnMaxEntriesLocalHeap(register, cacheManager); warnMaxEntriesForOverflowToOffHeap(register); warnSizeOfPolicyConfiguration(); freezePoolUsages(cacheManager); warnTieredSizing(); } private void consolidatePersistenceSettings(CacheManager manager) { if (persistenceConfiguration == null) { if (diskPersistent == Boolean.TRUE) { persistenceConfiguration = new PersistenceConfiguration().strategy(Strategy.LOCALTEMPSWAP); } } else { switch (persistenceConfiguration.getStrategy()) { case DISTRIBUTED: case NONE: diskPersistent = Boolean.FALSE; break; case LOCALTEMPSWAP: if (diskPersistent == null) { diskPersistent = Boolean.FALSE; } break; case LOCALRESTARTABLE: diskPersistent = Boolean.TRUE; break; default: break; } } if (persistenceConfiguration != null && persistenceConfiguration.getSynchronousWrites()) { switch (persistenceConfiguration.getStrategy()) { case NONE: case LOCALTEMPSWAP: throw new InvalidConfigurationException("Persistence: synchronousWrites=\"true\" is not supported " + "with strategy \"localTempSwap\" or \"none\""); default: break; } } } private void warnMaxEntriesForOverflowToOffHeap(final boolean register) { if (overflowToOffHeap != null && overflowToOffHeap && register) { if (getMaxEntriesLocalHeap() > 0 && getMaxEntriesLocalHeap() < MINIMUM_RECOMMENDED_IN_MEMORY) { LOG.warn("The " + getName() + " cache is configured for off-heap and has a maxEntriesLocalHeap/maxElementsInMemory of " + getMaxEntriesLocalHeap() + ". It is recommended to set maxEntriesLocalHeap/maxElementsInMemory to at least " + MINIMUM_RECOMMENDED_IN_MEMORY + " elements when using an off-heap store, otherwise performance " + "will be seriously degraded."); } } } private void warnMaxEntriesLocalHeap(final boolean register, CacheManager cacheManager) { if (getMaxEntriesLocalHeap() == 0 && register) { if (getMaxBytesLocalHeap() == 0 && (!cacheManager.getConfiguration().isMaxBytesLocalHeapSet())) { LOG.warn("Cache: " + getName() + " has a maxElementsInMemory of 0. This might lead to performance degradation or OutOfMemoryError at Terracotta client." + "From Ehcache 2.0 onwards this has been changed to mean a store" + " with no capacity limit. Set it to 1 if you want" + " no elements cached in memory"); } } } private void warnSizeOfPolicyConfiguration() { if (isTerracottaClustered() && getSizeOfPolicyConfiguration() != null) { LOG.warn("Terracotta clustered cache: " + getName() + " has a sizeOf policy configuration specificed. " + "SizeOfPolicyConfiguration is unsupported for Terracotta clustered caches."); } } private void freezePoolUsages(final CacheManager cacheManager) { if (getMaxBytesLocalHeap() > 0) { onHeapPoolUsage = CacheConfiguration.PoolUsage.Cache; } else if (cacheManager.getConfiguration().isMaxBytesLocalHeapSet()) { onHeapPoolUsage = CacheConfiguration.PoolUsage.CacheManager; } else { onHeapPoolUsage = CacheConfiguration.PoolUsage.None; } if (getMaxBytesLocalOffHeap() > 0) { offHeapPoolUsage = CacheConfiguration.PoolUsage.Cache; } else if (cacheManager.getConfiguration().isMaxBytesLocalOffHeapSet()) { offHeapPoolUsage = CacheConfiguration.PoolUsage.CacheManager; } else { offHeapPoolUsage = CacheConfiguration.PoolUsage.None; } if (isTerracottaClustered()) { onDiskPoolUsage = CacheConfiguration.PoolUsage.None; } else { if (getMaxBytesLocalDisk() > 0) { onDiskPoolUsage = CacheConfiguration.PoolUsage.Cache; } else if (cacheManager.getConfiguration().isMaxBytesLocalDiskSet()) { onDiskPoolUsage = CacheConfiguration.PoolUsage.CacheManager; } else { onDiskPoolUsage = CacheConfiguration.PoolUsage.None; } } } private void warnTieredSizing() { if (isOverflowToOffHeap()) { if (getMaxBytesLocalHeap() >= getMaxBytesLocalOffHeap() && getMaxBytesLocalOffHeap() != 0) { LOG.warn("Configuration problem for cache " + getName() + ": MaxBytesLocalHeap equal or greater than MaxBytesLocalOffHeap. " + "This will result in useless off heap storage."); } if (isOverflowToDisk()) { if (getMaxBytesLocalOffHeap() >= getMaxBytesLocalDisk() && getMaxBytesLocalDisk() != 0) { LOG.warn("Configuration problem for cache " + getName() + ": MaxBytesLocalOffHeap equal or greater than MaxBytesLocalDisk. " + "This will result in useless disk storage."); } } } if (isOverflowToDisk()) { if (getMaxEntriesLocalHeap() >= getMaxEntriesLocalDisk() && getMaxEntriesLocalDisk() != 0) { LOG.warn("Configuration problem for cache " + getName() + ": MaxEntriesLocalHeap equal or greater than MaxEntriesLocalDisk. " + "This will result in useless disk storage."); } } } private void registerCacheConfiguration(final CacheManager cacheManager) { Map configMap = cacheManager.getConfiguration().getCacheConfigurations(); if (!configMap.containsKey(getName())) { cacheManager.getConfiguration().addCache(this, false); } } private void updateCacheManagerPoolSizes(final CacheManager cacheManager) { if (cacheManager.getOnHeapPool() != null) { cacheManager.getOnHeapPool().setMaxSize(cacheManager.getOnHeapPool().getMaxSize() - getMaxBytesLocalHeap()); } if (cacheManager.getOnDiskPool() != null) { cacheManager.getOnDiskPool().setMaxSize(cacheManager.getOnDiskPool().getMaxSize() - getMaxBytesLocalDisk()); } } /** * Will verify that we don't overallocate pools * @param cacheManager The cacheManager that will manage the cache * @param managerMaxBytesLocalHeap bytes for local heap * @param managerMaxBytesLocalOffHeap bytes for local offheap * @param managerMaxBytesLocalDisk bytes for local disk * @param parentCacheName cacheName for parentCache to be used when initializing shadow caches * @return a list with potential errors */ List verifyPoolAllocationsBeforeAddingTo(CacheManager cacheManager, long managerMaxBytesLocalHeap, long managerMaxBytesLocalOffHeap, long managerMaxBytesLocalDisk, String parentCacheName) { final List configErrors = new ArrayList(); long totalOnHeapAssignedMemory = 0; long totalOffHeapAssignedMemory = 0; long totalOnDiskAssignedMemory = 0; boolean isUpdate = false; for (Cache cache : getAllActiveCaches(cacheManager)) { if (cache.getName().equals(parentCacheName)) { // Do not add parent cache when calculating memory requirements for shadow cache. continue; } isUpdate = cache.getName().equals(getName()) || isUpdate; final CacheConfiguration config = cache.getCacheConfiguration(); totalOnHeapAssignedMemory += config.getMaxBytesLocalHeap(); totalOffHeapAssignedMemory += config.getMaxBytesLocalOffHeap(); totalOnDiskAssignedMemory += config.getMaxBytesLocalDisk(); } if (!isUpdate) { totalOnHeapAssignedMemory += getMaxBytesLocalHeap(); totalOffHeapAssignedMemory += getMaxBytesLocalOffHeap(); totalOnDiskAssignedMemory += getMaxBytesLocalDisk(); } verifyLocalHeap(managerMaxBytesLocalHeap, configErrors, totalOnHeapAssignedMemory); verifyLocalOffHeap(managerMaxBytesLocalOffHeap, configErrors, totalOffHeapAssignedMemory); verifyLocalDisk(managerMaxBytesLocalDisk, configErrors, totalOnDiskAssignedMemory); if (managerMaxBytesLocalHeap > 0 && managerMaxBytesLocalHeap - totalOnHeapAssignedMemory == 0) { LOG.warn("All the onHeap memory has been assigned, there is none left for dynamically added caches"); } if (Runtime.getRuntime().maxMemory() - totalOnHeapAssignedMemory < 0) { // todo this could be a nicer message (with actual values) configErrors.add(new ConfigError("You've assigned more memory to the on-heap than the VM can sustain, " + "please adjust your -Xmx setting accordingly")); } if (totalOnHeapAssignedMemory / (float) Runtime.getRuntime().maxMemory() > CacheManager.ON_HEAP_THRESHOLD) { LOG.warn("You've assigned over 80% of your VM's heap to be used by the cache!"); } return configErrors; } private void verifyLocalDisk(final long managerMaxBytesLocalDisk, final List configErrors, final long totalOnDiskAssignedMemory) { if ((isMaxBytesLocalDiskPercentageSet() || getMaxBytesLocalDisk() > 0) && managerMaxBytesLocalDisk > 0 && managerMaxBytesLocalDisk - totalOnDiskAssignedMemory < 0) { configErrors.add(new ConfigError("Cache '" + getName() + "' over-allocates CacheManager's localOnDisk limit!")); } } private void verifyLocalOffHeap(final long managerMaxBytesLocalOffHeap, final List configErrors, final long totalOffHeapAssignedMemory) { if ((isMaxBytesLocalOffHeapPercentageSet() || getMaxBytesLocalOffHeap() > 0) && managerMaxBytesLocalOffHeap > 0 && managerMaxBytesLocalOffHeap - totalOffHeapAssignedMemory < 0) { configErrors.add(new ConfigError("Cache '" + getName() + "' over-allocates CacheManager's localOffHeap limit!")); } } private void verifyLocalHeap(final long managerMaxBytesLocalHeap, final List configErrors, final long totalOnHeapAssignedMemory) { if ((isMaxBytesLocalHeapPercentageSet() || getMaxBytesLocalHeap() > 0) && managerMaxBytesLocalHeap > 0 && managerMaxBytesLocalHeap - totalOnHeapAssignedMemory < 0) { configErrors.add(new ConfigError("Cache '" + getName() + "' over-allocates CacheManager's localOnHeap limit!")); } } /** * Configures the cache pools * @param configuration the Configuration of the CacheManager managing this cache */ void configCachePools(Configuration configuration) { long cacheAssignedMem; if (getMaxBytesLocalHeapPercentage() != null) { cacheAssignedMem = configuration.getMaxBytesLocalHeap() * getMaxBytesLocalHeapPercentage() / HUNDRED_PERCENT; setMaxBytesLocalHeap(cacheAssignedMem); } if (offHeapPoolUsage == null && getMaxBytesLocalOffHeapPercentage() != null) { cacheAssignedMem = configuration.getMaxBytesLocalOffHeap() * getMaxBytesLocalOffHeapPercentage() / HUNDRED_PERCENT; setMaxBytesLocalOffHeap(cacheAssignedMem); } if (getMaxBytesLocalDiskPercentage() != null) { cacheAssignedMem = configuration.getMaxBytesLocalDisk() * getMaxBytesLocalDiskPercentage() / HUNDRED_PERCENT; setMaxBytesLocalDisk(cacheAssignedMem); } } /** * Validates the configuration * @param configuration the CacheManager configuration this is going to be used with * @return the errors in the config */ public Collection validate(final Configuration configuration) { final Collection errors = new ArrayList(); verifyClusteredCacheConfiguration(errors); if (maxEntriesLocalHeap == null && !configuration.isMaxBytesLocalHeapSet() && maxBytesLocalHeap == null) { errors.add(new CacheConfigError("If your CacheManager has no maxBytesLocalHeap set, you need to either set " + "maxEntriesLocalHeap or maxBytesLocalHeap at the Cache level", getName())); } if (configuration.isMaxBytesLocalHeapSet() && Runtime.getRuntime().maxMemory() - configuration.getMaxBytesLocalHeap() < 0) { errors.add(new ConfigError("You've assigned more memory to the on-heap than the VM can sustain, " + "please adjust your -Xmx setting accordingly")); } if (maxEntriesInCache != DEFAULT_MAX_ENTRIES_IN_CACHE) { if (!isTerracottaClustered()) { errors.add(new CacheConfigError("maxEntriesInCache is not applicable to unclustered caches.", getName())); } } //commenting this check until fixed for cachemanger is fixed //if (isOverflowToOffHeapSet() && !maxBytesLocalOffHeapExplicitlySet) { // errors.add(new CacheConfigError("\"overFlowToOffHeap\" is set, but \"maxBytesLocalOffHeap\" is not set.", getName())); //} if (persistenceConfiguration != null && persistenceConfiguration.getStrategy() == null) { errors.add(new CacheConfigError("Persistence configuration found with no strategy set.", getName())); } errors.addAll(validateCachePools(configuration)); return errors; } private void verifyClusteredCacheConfiguration(final Collection errors) { if (!isTerracottaClustered()) { return; } if (getPinningConfiguration() != null && getPinningConfiguration().getStore() == PinningConfiguration.Store.INCACHE && getMaxElementsOnDisk() != 0) { errors.add(new CacheConfigError("maxElementsOnDisk may not be used on a pinned cache.", getName())); } if (maxEntriesLocalDiskExplicitlySet) { errors.add(new CacheConfigError("You can't set maxEntriesLocalDisk when clustering your cache with Terracotta, " + "local disks won't be used! To control elements going in the cache cluster wide, " + "use maxEntriesInCache instead", getName())); } if (maxBytesLocalDiskExplicitlySet) { errors.add(new CacheConfigError("You can't set maxBytesLocalDisk when clustering your cache with Terracotta", getName())); } if (maxElementsOnDisk != DEFAULT_MAX_ELEMENTS_ON_DISK) { errors.add(new CacheConfigError("maxElementsOnDisk is not used with clustered caches. Use maxEntriesInCache " + "to set maximum cache size.", getName())); } } /** * Validates the CacheConfiguration against the CacheManager's Configuration * @param configuration The CacheManager Configuration * @return the list of errors encountered, or an empty list */ List validateCachePools(final Configuration configuration) { List errors = new ArrayList(); if (configuration.isMaxBytesLocalHeapSet() && getMaxEntriesLocalHeap() > 0) { errors.add(new CacheConfigError("maxEntriesLocalHeap is not compatible with " + "maxBytesLocalHeap set on cache manager", getName())); } if (getMaxBytesLocalHeap() > 0 && getMaxEntriesLocalHeap() > 0) { errors.add(new CacheConfigError("maxEntriesLocalHeap is not compatible with " + "maxBytesLocalHeap set on cache", getName())); } if (isMaxBytesLocalHeapPercentageSet() && !configuration.isMaxBytesLocalHeapSet()) { errors.add(new CacheConfigError("Defines a percentage maxBytesOnHeap value but no CacheManager " + "wide value was configured", getName())); } if (isMaxBytesLocalOffHeapPercentageSet() && !configuration.isMaxBytesLocalOffHeapSet()) { errors.add(new CacheConfigError("Defines a percentage maxBytesOffHeap value but no CacheManager " + "wide value was configured", getName())); } if (isMaxBytesLocalDiskPercentageSet() && !configuration.isMaxBytesLocalDiskSet()) { errors.add(new CacheConfigError("Defines a percentage maxBytesOnDisk value but no CacheManager " + "wide value was configured", getName())); } return errors; } /** * Whether this cache is Count based * @return true if maxEntries set, false otherwise */ public boolean isCountBasedTuned() { return (maxEntriesLocalHeap != null && maxEntriesLocalHeap > 0) || maxElementsOnDisk > 0; } /** * Checks whether the overflowing to off heap behavior was explicitly set * @return true if explicitly set, false otherwise */ public boolean isOverflowToOffHeapSet() { return overflowToOffHeap != null; } /** * Configuration for the CacheEventListenerFactory. */ public static final class CacheEventListenerFactoryConfiguration extends FactoryConfiguration { private NotificationScope notificationScope = NotificationScope.ALL; /** * Used by BeanHandler to set the mode during parsing. Convert listenFor string to uppercase and * look up enum constant in NotificationScope. */ public void setListenFor(String listenFor) { if (listenFor == null) { throw new IllegalArgumentException("listenFor must be non-null"); } this.notificationScope = NotificationScope.valueOf(NotificationScope.class, listenFor.toUpperCase()); } /** * @return this factory configuration instance * @see #setListenFor(String) */ public final CacheEventListenerFactoryConfiguration listenFor(String listenFor) { setListenFor(listenFor); return this; } /** * Get the value mode in terms of the mode enum */ public NotificationScope getListenFor() { return this.notificationScope; } } /** * Used by BeanUtils to add cacheEventListenerFactory elements to the cache configuration. */ public final void addCacheEventListenerFactory(CacheEventListenerFactoryConfiguration factory) { checkDynamicChange(); cacheEventListenerConfigurations.add(factory); validateConfiguration(); } /** * @return this configuration instance * @see #addCacheEventListenerFactory(CacheEventListenerFactoryConfiguration) */ public final CacheConfiguration cacheEventListenerFactory(CacheEventListenerFactoryConfiguration factory) { addCacheEventListenerFactory(factory); return this; } /** * Configuration for the CacheExtensionFactoryConfiguration. */ public static final class CacheExtensionFactoryConfiguration extends FactoryConfiguration { } /** * Used by BeanUtils to add cacheExtensionFactory elements to the cache configuration. */ public final void addCacheExtensionFactory(CacheExtensionFactoryConfiguration factory) { checkDynamicChange(); cacheExtensionConfigurations.add(factory); } /** * @return this configuration instance * @see #addCacheExtensionFactory(CacheExtensionFactoryConfiguration) */ public final CacheConfiguration cacheExtensionFactory(CacheExtensionFactoryConfiguration factory) { /** * {@inheritDoc} */ addCacheExtensionFactory(factory); return this; } /** * Configuration for the BootstrapCacheLoaderFactoryConfiguration. */ public static final class BootstrapCacheLoaderFactoryConfiguration extends FactoryConfiguration { } /** * Allows BeanHandler to add the CacheManagerEventListener to the configuration. */ public final void addBootstrapCacheLoaderFactory(BootstrapCacheLoaderFactoryConfiguration factory) { checkDynamicChange(); this.bootstrapCacheLoaderFactoryConfiguration = factory; } /** * @return this configuration instance * @see #addBootstrapCacheLoaderFactory(BootstrapCacheLoaderFactoryConfiguration) */ public final CacheConfiguration bootstrapCacheLoaderFactory(BootstrapCacheLoaderFactoryConfiguration factory) { addBootstrapCacheLoaderFactory(factory); return this; } /** * Configuration for the BootstrapCacheLoaderFactoryConfiguration. */ public static final class CacheExceptionHandlerFactoryConfiguration extends FactoryConfiguration { } /** * Add the CacheExceptionHandlerFactory to the configuration. *

* Note that this will not have any effect when creating a cache solely through its constructed. The exception * handler will only be taken into account when {@link ConfigurationHelper} is used, for example through * {@link net.sf.ehcache.CacheManager}. */ public final void addCacheExceptionHandlerFactory(CacheExceptionHandlerFactoryConfiguration factory) { checkDynamicChange(); this.cacheExceptionHandlerFactoryConfiguration = factory; } /** * @return this configuration instance * @see #addCacheExceptionHandlerFactory(CacheExceptionHandlerFactoryConfiguration) */ public final CacheConfiguration cacheExceptionHandlerFactory(CacheExceptionHandlerFactoryConfiguration factory) { addCacheExceptionHandlerFactory(factory); return this; } /** * Configuration for the CacheLoaderFactoryConfiguration. */ public static final class CacheLoaderFactoryConfiguration extends FactoryConfiguration { } /** * Used by BeanUtils to add each cacheLoaderFactory to the cache configuration. * * @param factory */ public final void addCacheLoaderFactory(CacheLoaderFactoryConfiguration factory) { checkDynamicChange(); cacheLoaderConfigurations.add(factory); } /** * Configuration for the CacheDecoratorFactoryConfiguration. */ public static final class CacheDecoratorFactoryConfiguration extends FactoryConfiguration { } /** * Used by BeanUtils to add each cacheDecoratorFactory to the cache configuration. * * @param factory */ public final void addCacheDecoratorFactory(CacheDecoratorFactoryConfiguration factory) { checkDynamicChange(); cacheDecoratorConfigurations.add(factory); } /** * @return this configuration instance * @see #addCacheLoaderFactory(CacheLoaderFactoryConfiguration) */ public final CacheConfiguration cacheLoaderFactory(CacheLoaderFactoryConfiguration factory) { addCacheLoaderFactory(factory); return this; } /** * Allows BeanHandler to add the TerracottaConfiguration to the configuration. */ public final void addTerracotta(TerracottaConfiguration terracottaConfiguration) { this.terracottaConfiguration = terracottaConfiguration; validateConfiguration(); } /** * Allows BeanHandler to add the PinningConfiguration to the configuration. */ public final void addPinning(PinningConfiguration pinningConfiguration) { this.pinningConfiguration = pinningConfiguration; validateConfiguration(); } /** * @return this configuration instance * @see #addPinning(PinningConfiguration) */ public final CacheConfiguration pinning(PinningConfiguration pinningConfiguration) { addPinning(pinningConfiguration); return this; } /** * @return this configuration instance * @see #addTerracotta(TerracottaConfiguration) */ public final CacheConfiguration terracotta(TerracottaConfiguration terracottaConfiguration) { addTerracotta(terracottaConfiguration); return this; } /** * @see #addSearchable(Searchable) * @param searchable * @return this */ public final CacheConfiguration searchable(Searchable searchable) { addSearchable(searchable); return this; } /** * Allows BeanHandler to add the CacheWriterConfiguration to the configuration. */ public final void addCacheWriter(CacheWriterConfiguration cacheWriterConfiguration) { if (null == cacheWriterConfiguration) { this.cacheWriterConfiguration = new CacheWriterConfiguration(); } else { this.cacheWriterConfiguration = cacheWriterConfiguration; } } /** * @return this configuration instance * @see #addCacheWriter(CacheWriterConfiguration) */ public final CacheConfiguration cacheWriter(CacheWriterConfiguration cacheWriterConfiguration) { addCacheWriter(cacheWriterConfiguration); return this; } /** * Sets the transactionalMode * * @param transactionalMode one of OFF, LOCAL, XA, XA_STRICT */ public final void setTransactionalMode(final String transactionalMode) { assertArgumentNotNull("Cache transactionalMode", transactionalMode); transactionalMode(TransactionalMode.valueOf(transactionalMode.toUpperCase())); } /** * Builder which sets the transactionalMode * * @param transactionalMode one of OFF, LOCAL, XA, XA_STRICT * @return this configuration instance * @see #setTransactionalMode(String) */ public final CacheConfiguration transactionalMode(String transactionalMode) { setTransactionalMode(transactionalMode); return this; } /** * Builder which sets the transactionalMode * * @param transactionalMode one of OFF, LOCAL, XA, XA_STRICT * @return this configuration instance * @see #setTransactionalMode(String) */ public final CacheConfiguration transactionalMode(TransactionalMode transactionalMode) { if (transactionalMode == null) { throw new IllegalArgumentException("TransactionalMode value must be non-null"); } if (this.transactionalMode != null) { throw new InvalidConfigurationException("transactionalMode cannot be changed once set"); } this.transactionalMode = transactionalMode; return this; } /** * Sets whether the cache's statistics are enabled. at startup */ @Deprecated public final void setStatistics(boolean enabled) { if (!enabled) { LOG.warn("Statistics can no longer be enabled via configuration."); return; } this.statistics = enabled; } /** * Builder which sets whether the cache's statistics are enabled. * * @return this configuration instance * @see #setStatistics(boolean) */ @Deprecated public final CacheConfiguration statistics(boolean statistics) { setStatistics(statistics); return this; } /** * Gets whether the cache's statistics will be enabled at startup */ public final boolean getStatistics() { return true; } /** * Used to validate what should be a complete Cache Configuration. */ public void validateCompleteConfiguration() { validateConfiguration(); // Extra checks that a completed cache config should have if (name == null) { throw new InvalidConfigurationException("Caches must be named."); } } /** * Used to validate a Cache Configuration. */ public void validateConfiguration() { if (terracottaConfiguration != null && terracottaConfiguration.isClustered()) { if (overflowToDisk != null && overflowToDisk) { throw new InvalidConfigurationException("overflowToDisk isn't supported for a clustered Terracotta cache"); } if (diskPersistent == Boolean.TRUE) { throw new InvalidConfigurationException("diskPersistent isn't supported for a clustered Terracotta cache"); } if (persistenceConfiguration != null && !Strategy.DISTRIBUTED.equals(persistenceConfiguration.getStrategy())) { throw new InvalidConfigurationException(persistenceConfiguration.getStrategy() + " persistence strategy isn't supported for a clustered Terracotta cache"); } if (cacheEventListenerConfigurations != null) { for (CacheEventListenerFactoryConfiguration listenerConfig : cacheEventListenerConfigurations) { if (null == listenerConfig.getFullyQualifiedClassPath()) { continue; } if (!listenerConfig.getFullyQualifiedClassPath().startsWith("net.sf.ehcache.") && LOG.isWarnEnabled()) { LOG.warn("The non-standard CacheEventListenerFactory '" + listenerConfig.getFullyQualifiedClassPath() + "' is used with a clustered Terracotta cache, " + "if the purpose of this listener is replication it is not supported in a clustered context"); } } } } if (cacheWriterConfiguration != null) { if (!cacheWriterConfiguration.getWriteBatching() && cacheWriterConfiguration.getWriteBatchSize() != 1) { throw new InvalidConfigurationException("CacheWriter Batch Size !=1 and CacheWriter Batching " + "turned off"); } } } private void validateTransactionalSettings() { boolean transactional = getTransactionalMode().isTransactional(); if (copyOnRead == null) { if (terracottaConfiguration != null && terracottaConfiguration.isCopyOnReadSet()) { copyOnRead = terracottaConfiguration.isCopyOnRead(); } else { copyOnRead = transactional; } } if (copyOnWrite == null) { copyOnWrite = transactional; } if (transactional) { if (!copyOnRead || !copyOnWrite) { throw new InvalidConfigurationException("A transactional cache has to be copyOnRead and copyOnWrite!"); } } } /** * Accessor */ public String getName() { return name; } /** * Accessor * * @deprecated use {@link #getMaxEntriesLocalHeap()} */ @Deprecated public int getMaxElementsInMemory() { return (int)getMaxEntriesLocalHeap(); } /** * Accessor */ public long getCacheLoaderTimeoutMillis() { return cacheLoaderTimeoutMillis; } /** * Accessor * @deprecated use {@link #getMaxEntriesLocalDisk()} for unclustered caches and {@link #getMaxEntriesInCache()} for clustered caches. */ public int getMaxElementsOnDisk() { return maxElementsOnDisk; } /** * Accessor * */ public long getMaxEntriesInCache() { return maxEntriesInCache; } /** * Configured maximum number of entries for the local disk store. */ public long getMaxEntriesLocalDisk() { return maxElementsOnDisk; } /** * Configured maximum number of entries for the local memory heap. */ public long getMaxEntriesLocalHeap() { return maxEntriesLocalHeap == null ? 0 : maxEntriesLocalHeap; } /** * Accessor */ public MemoryStoreEvictionPolicy getMemoryStoreEvictionPolicy() { return memoryStoreEvictionPolicy; } /** * Accessor */ public boolean isClearOnFlush() { return clearOnFlush; } /** * Accessor */ public boolean isEternal() { return eternal; } /** * Accessor */ public long getTimeToIdleSeconds() { return timeToIdleSeconds; } /** * Accessor */ public long getTimeToLiveSeconds() { return timeToLiveSeconds; } /** * Accessor * * @deprecated The {@code overflowToDisk} attribute has been replaced with {@link Strategy#LOCALTEMPSWAP}. */ @Deprecated public boolean isOverflowToDisk() { return overflowToDisk == null ? false : overflowToDisk; } /** * Accessor * * @deprecated The {@code diskPersistent} attribute has been replaced with {@link #persistence(PersistenceConfiguration)}. */ @Deprecated public boolean isDiskPersistent() { Boolean persistent = diskPersistent; return diskPersistent == null ? DEFAULT_DISK_PERSISTENT : persistent; } /** * Accessor */ public boolean isSearchable() { return searchable != null; } /** * Accessor */ public int getDiskSpoolBufferSizeMB() { return diskSpoolBufferSizeMB; } /** * Accessor */ public long getDiskExpiryThreadIntervalSeconds() { return diskExpiryThreadIntervalSeconds; } /** * Accessor */ public int getDiskAccessStripes() { return diskAccessStripes; } /** * Accessor */ public DynamicAttributesExtractor getDynamicExtractor() { return flexIndexer; } /** * Only used when cache is clustered with Terracotta * * @return true if logging is enabled otherwise false */ public boolean getLogging() { return logging; } /** * Accessor * * @return true if offheap store is enabled, otherwise false. */ public boolean isOverflowToOffHeap() { return overflowToOffHeap == null ? false : overflowToOffHeap; } /** * Accessor * * @return the SizeOfPolicy Configuration for this cache. */ public SizeOfPolicyConfiguration getSizeOfPolicyConfiguration() { return sizeOfPolicyConfiguration; } /** * Accessor * * @return the persistence configuration for this cache. */ public PersistenceConfiguration getPersistenceConfiguration() { return persistenceConfiguration; } /** * Accessor * * @return the max memory of the offheap store for this cache. * @deprecated See {@link #getMaxBytesLocalOffHeapAsString()} */ @Deprecated public String getMaxMemoryOffHeap() { return maxBytesLocalOffHeapInput; } /** * Accessor * * @return the max memory of the offheap store for this cache, in bytes. * @deprecated {@link #getMaxBytesLocalOffHeap()} */ @Deprecated public long getMaxMemoryOffHeapInBytes() { return getMaxBytesLocalOffHeap(); } /** * Accessor */ public List getCacheEventListenerConfigurations() { return cacheEventListenerConfigurations; } /** * Accessor * * @return the configuration */ public List getCacheExtensionConfigurations() { return cacheExtensionConfigurations; } /** * Accessor * * @return the configuration */ public List getCacheLoaderConfigurations() { return cacheLoaderConfigurations; } /** * Accessor * * @return the configuration */ public List getCacheDecoratorConfigurations() { return cacheDecoratorConfigurations; } /** * Accessor * * @return the configuration */ public BootstrapCacheLoaderFactoryConfiguration getBootstrapCacheLoaderFactoryConfiguration() { return bootstrapCacheLoaderFactoryConfiguration; } /** * Accessor * * @return the configuration */ public CacheExceptionHandlerFactoryConfiguration getCacheExceptionHandlerFactoryConfiguration() { return cacheExceptionHandlerFactoryConfiguration; } /** * Accessor * * @return the terracotta configuration */ public TerracottaConfiguration getTerracottaConfiguration() { return terracottaConfiguration; } /** * Accessor * * @return the pinning configuration */ public PinningConfiguration getPinningConfiguration() { return pinningConfiguration; } /** * Accessor * * @return the writer configuration */ public CacheWriterConfiguration getCacheWriterConfiguration() { return cacheWriterConfiguration; } /** * Helper method to compute whether the cache is clustered or not * * @return True if the <terracotta/> element exists with {@code clustered="true"} */ public boolean isTerracottaClustered() { return terracottaConfiguration != null && terracottaConfiguration.isClustered(); } /** * Accessor * * @return the CoherenceMode if Terracotta-clustered or null */ public Consistency getTerracottaConsistency() { return terracottaConfiguration != null ? terracottaConfiguration.getConsistency() : null; } /** * To what transactionalMode was the Cache set * * @return transactionaMode */ public final TransactionalMode getTransactionalMode() { if (transactionalMode == null) { return DEFAULT_TRANSACTIONAL_MODE; } return transactionalMode; } /** * Helper method to compute whether the cache is XA transactional or not * * @return true if transactionalMode="xa_strict" */ public boolean isXaStrictTransactional() { validateTransactionalSettings(); return getTransactionalMode().equals(TransactionalMode.XA_STRICT); } /** * Helper method to compute whether the cache is local transactional or not * * @return true if transactionalMode="local" */ public boolean isLocalTransactional() { validateTransactionalSettings(); return getTransactionalMode().equals(TransactionalMode.LOCAL); } /** * Helper method to compute whether the cache is local_jta transactional or not * * @return true if transactionalMode="xa" */ public boolean isXaTransactional() { validateTransactionalSettings(); return getTransactionalMode().equals(TransactionalMode.XA); } /** * An enum to identify what pool a resource uses */ private static enum PoolUsage { CacheManager(true), Cache(true), None(false); private final boolean usingPool; private PoolUsage(final boolean poolUser) { this.usingPool = poolUser; } public boolean isUsingPool() { return usingPool; } } /** * Represents whether the Cache is transactional or not. * * @author alexsnaps */ public static enum TransactionalMode { /** * No Transactions */ OFF(false), /** * Local Transactions */ LOCAL(true), /** * XA Transactions */ XA(true), /** * XA Strict (true 2PC) Transactions */ XA_STRICT(true); private final boolean transactional; /** * @param transactional */ TransactionalMode(final boolean transactional) { this.transactional = transactional; } /** * @return transactional */ public boolean isTransactional() { return transactional; } } /** * Add a listener to this cache configuration * * @param listener listener instance to add * @return true if a listener was added */ public boolean addConfigurationListener(CacheConfigurationListener listener) { boolean added = listeners.add(listener); if (added) { listener.registered(this); } return added; } /** * Add a dynamic extractor configuration listener * @param listener * @return true if a listener was added */ public boolean addDynamicSearchListener(DynamicSearchListener listener) { return dynamicSearchListeners.add(listener); } /** * Remove the supplied cache configuration listener. * * @param listener listener to remove * @return true if a listener was removed */ public boolean removeConfigurationListener(CacheConfigurationListener listener) { boolean removed = listeners.remove(listener); if (removed) { listener.deregistered(this); } return removed; } private void fireTtiChanged(long oldTti, long newTti) { if (oldTti != newTti) { for (CacheConfigurationListener l : listeners) { l.timeToIdleChanged(oldTti, newTti); } } } private void fireTtlChanged(long oldTtl, long newTtl) { if (oldTtl != newTtl) { for (CacheConfigurationListener l : listeners) { l.timeToLiveChanged(oldTtl, newTtl); } } } private void fireLoggingChanged(boolean oldValue, boolean newValue) { if (oldValue != newValue) { for (CacheConfigurationListener l : listeners) { l.loggingChanged(oldValue, newValue); } } } private void fireDiskCapacityChanged(int oldCapacity, int newCapacity) { if (oldCapacity != newCapacity) { for (CacheConfigurationListener l : listeners) { l.diskCapacityChanged(oldCapacity, newCapacity); } } } private void fireMaxEntriesInCacheChanged(long oldCapacity, long newCapacity) { if (oldCapacity != newCapacity) { for (CacheConfigurationListener l : listeners) { l.maxEntriesInCacheChanged(oldCapacity, newCapacity); } } } private void fireMemoryCapacityChanged(int oldCapacity, int newCapacity) { if (oldCapacity != newCapacity) { for (CacheConfigurationListener l : listeners) { l.memoryCapacityChanged(oldCapacity, newCapacity); } } } private void checkDynamicChange() { if (frozen) { throw new CacheException("Dynamic configuration changes are disabled for this cache"); } } /** * Intended for internal use only, and subject to change. * This is required so that changes in store implementation's config * (probably from other nodes) can propagate up to here */ public void internalSetTimeToIdle(long timeToIdle) { this.timeToIdleSeconds = timeToIdle; } /** * Intended for internal use only, and subject to change. */ public void internalSetTimeToLive(long timeToLive) { this.timeToLiveSeconds = timeToLive; } /** * Intended for internal use only, and subject to change. */ public void internalSetEternal(boolean eternal) { this.eternal = eternal; } /** * Intended for internal use only, and subject to change. */ public void internalSetMemCapacity(int capacity) { this.maxEntriesLocalHeap = capacity; } /** * Intended for internal use only, and subject to change. */ public void internalSetMemCapacityInBytes(long capacity) { this.maxBytesLocalHeap = capacity; } /** * Intended for internal use only, and subject to change. */ public void internalSetDiskCapacity(int capacity) { this.maxElementsOnDisk = capacity; } /** * Intended for internal use only, and subject to change. */ public void internalSetMaxEntriesInCache(int entries) { this.maxEntriesInCache = entries; } /** * Intended for internal use only, and subject to change. */ public void internalSetLogging(boolean logging) { this.logging = logging; } /** * Intended for internal use only, and subject to change. */ public void internalSetMaxBytesLocalOffheap(long maxBytesLocalOffheap) { this.maxBytesLocalOffHeap = maxBytesLocalOffheap; } /** * Intended for internal use only, and subject to change. */ public void internalSetOverflowToOffheap(boolean overflowToOffHeap) { this.overflowToOffHeap = overflowToOffHeap; } /** * Get the defined search attributes indexed by attribute name * * @return search attributes */ public Map getSearchAttributes() { if (searchable == null) { return Collections.emptyMap(); } return searchable.getSearchAttributes(); } /** * Get the search configuration for this cache (if any) * * @return search config (may be null) */ public Searchable getSearchable() { return searchable; } public ClassLoader getClassLoader() { return this.classLoader; } public void setClassLoader(ClassLoader classLoader) { checkDynamicChange(); this.classLoader = classLoader; } /** * Default listener class which handles the size changes of the cache */ private class DefaultCacheConfigurationListener extends AbstractCacheConfigurationListener { private final CacheManager cacheManager; public DefaultCacheConfigurationListener(CacheManager cacheManager) { this.cacheManager = cacheManager; } @Override public void maxBytesLocalHeapChanged(final long oldValue, final long newValue) { if (getMaxBytesLocalHeap() > 0 && cacheManager.getConfiguration().getCacheConfigurations().keySet().contains(getName()) && cacheManager.getConfiguration().isMaxBytesLocalHeapSet()) { long oldCacheManagerPoolSize = cacheManager.getOnHeapPool().getMaxSize(); long newPoolFreeSize = oldCacheManagerPoolSize + oldValue - newValue; //handle case of overallocation of cache //Only resize the cache manager pool cache pool resizing will be handled by cache if (newPoolFreeSize >= 0) { cacheManager.getOnHeapPool().setMaxSize(newPoolFreeSize); } else { maxBytesLocalHeap = oldValue; throw new InvalidConfigurationException("Cannot allocate heap size more " + "than the cache pool size reverting to previous size " + maxBytesLocalHeap); } } } @Override public void maxBytesLocalDiskChanged(final long oldValue, final long newValue) { if (getMaxBytesLocalDisk() > 0 && cacheManager.getConfiguration().getCacheConfigurations().keySet().contains(getName()) && cacheManager.getConfiguration().isMaxBytesLocalDiskSet()) { long previous = cacheManager.getOnDiskPool().getMaxSize(); long newPoolFreeSize = previous + oldValue - newValue; //handle case of overallocation of cache //Only resize the cache manager pool cache pool resizing will be handled by cache if (newPoolFreeSize >= 0) { cacheManager.getOnDiskPool().setMaxSize(newPoolFreeSize); } else { LOG.warn("Cannot allocate local disk size more than cache disk size, " + "setting maxBytesLocalDisk {} to old value {}", maxBytesLocalDisk, oldValue); maxBytesLocalDisk = oldValue; throw new InvalidConfigurationException("Cannot allocate disk size more than " + "the cache pool size reverting to previous size " + maxBytesLocalHeap); } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy