/* * Licensed to the Apache Software Foundation (ASF) under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional information regarding * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.cache; import org.apache.geode.DataSerializable; import org.apache.geode.cache.control.ResourceManager; import org.apache.geode.cache.util.ObjectSizer; import org.apache.geode.internal.cache.EvictionAttributesImpl; /** * <p> * Attributes that describe how a <code>Region</code>'s size is managed through an eviction * controller. Eviction controllers are defined by an * {@link org.apache.geode.cache.EvictionAlgorithm} and a * {@link org.apache.geode.cache.EvictionAction}. Once a <code>Region</code> is created with an * eviction controller, it can not be removed, however it can be changed through an * {@link org.apache.geode.cache.EvictionAttributesMutator}. * * @see org.apache.geode.cache.AttributesFactory#setEvictionAttributes(EvictionAttributes) * @see org.apache.geode.cache.AttributesMutator * @since GemFire 5.0 */ @SuppressWarnings("serial") public abstract class EvictionAttributes implements DataSerializable { /** * The default maximum for {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU}. Currently * <code>900</code> entries. */ public static final int DEFAULT_ENTRIES_MAXIMUM = 900; /** * The default maximum for {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU}. Currently * <code>10</code> megabytes. */ public static final int DEFAULT_MEMORY_MAXIMUM = 10; /** * Creates and returns {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU} eviction attributes with * default {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action} and default * {@linkplain #DEFAULT_ENTRIES_MAXIMUM maximum}. * <p/> * {@link EvictionAttributes} cause regions to evict the least recently used (LRU) entry once the * region reaches a maximum capacity. The entry is either locally destroyed or its value overflows * to disk when evicted. * <p/> * <p/> * This is not supported when replication is enabled. * <p/> * <p/> * For a region with {@link DataPolicy#PARTITION}, the EvictionAttribute <code>maximum</code>, * indicates the number of entries allowed in the region, collectively for its primary buckets and * redundant copies for this JVM. Once there are <code>maximum</code> entries in the region's * primary buckets and redundant copies for this JVM, the least recently used entry will be * evicted from the bucket in which the subsequent put takes place. * <p/> * <p/> * If you are using a <code>cache.xml</code> file to create a Cache Region declaratively, you can * include the following to configure a region for eviction * <p/> * * <pre> * <region-attributes> * <eviction-attributes> * <lru-entry-count maximum="900" action="local-destroy"/> * </eviction-attributes> * </region-attributes> * </pre> * * @return {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU} eviction attributes with default * {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action} and default * {@linkplain #DEFAULT_ENTRIES_MAXIMUM maximum} */ public static EvictionAttributes createLRUEntryAttributes() { return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_ENTRY) .setAction(EvictionAction.DEFAULT_EVICTION_ACTION) .internalSetMaximum(DEFAULT_ENTRIES_MAXIMUM); } /** * Creates and returns {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU} eviction attributes with * default {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action} and given * <code>maximumEntries</code>. * * @param maximumEntries the number of entries to keep in the Region * @return {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU} eviction attributes with default * {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action} and * <code>maximumEntries</code> * @see #createLRUEntryAttributes() */ public static EvictionAttributes createLRUEntryAttributes(int maximumEntries) { return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_ENTRY) .setAction(EvictionAction.DEFAULT_EVICTION_ACTION).internalSetMaximum(maximumEntries); } /** * Creates and returns {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU} eviction attributes with * default {@linkplain #DEFAULT_ENTRIES_MAXIMUM maximum} and given <code>evictionAction</code>. * * @param evictionAction the action to perform when evicting an entry * @return {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU} eviction attributes with default * {@linkplain #DEFAULT_ENTRIES_MAXIMUM maximum} and given <code>evictionAction</code> * @see #createLRUEntryAttributes() * @since GemFire 8.1 */ public static EvictionAttributes createLRUEntryAttributes(EvictionAction evictionAction) { return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_ENTRY) .setAction(evictionAction).internalSetMaximum(DEFAULT_ENTRIES_MAXIMUM); } /** * Creates and returns {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU} eviction attributes with * given <code>evictionAction</code> and given <code>maximumEntries</code>. * * @param maximumEntries the number of entries to keep in the Region * @param evictionAction the action to perform when evicting an entry * @return {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU} eviction attributes with given * <code>evictionAction</code> and given <code>maximumEntries</code> * @see #createLRUEntryAttributes() */ public static EvictionAttributes createLRUEntryAttributes(int maximumEntries, EvictionAction evictionAction) { return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_ENTRY) .setAction(evictionAction).internalSetMaximum(maximumEntries); } /** * Creates and returns {@linkplain EvictionAlgorithm#LRU_HEAP heap LRU} eviction attributes with * default {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action} and default * {@linkplain ObjectSizer#DEFAULT sizer}. * <p/> * Heap LRU EvictionAttributes evict the least recently used {@link Region.Entry} when heap usage * exceeds the {@link ResourceManager} eviction heap threshold. If the eviction heap threshold is * exceeded the least recently used {@link Region.Entry}s are evicted. * <p/> * <p/> * With other LRU-based eviction controllers, only cache actions (such as * {@link Region#put(Object, Object) puts} and {@link Region#get(Object) gets}) cause the LRU * entry to be evicted. However, with heap LRU, because the JVM's heap may be effected by more * than just the GemFire cache operations, a daemon thread will perform the eviction if no * operations are being done on the region. * <p/> * The eviction attribute's {@linkplain ObjectSizer sizer} is used to estimate how much the heap * will be reduced by an eviction. * <p/> * When using Heap LRU, the JVM must be launched with the <code>-Xmx</code> and <code>-Xms</code> * switches set to the same values. Many virtual machine implementations have additional JVM * switches to control the behavior of the garbage collector. We suggest that you investigate * tuning the garbage collector when using this type of eviction controller. A collector that * frequently collects is needed to keep our heap usage up to date. In particular, on the Sun * <A href="http://java.sun.com/docs/hotspot/gc/index.html">HotSpot</a> JVM, the * <code>-XX:+UseConcMarkSweepGC</code> flag needs to be set, and * <code>-XX:CMSInitiatingOccupancyFraction=N</code> should be set with N being a percentage that * is less than the {@link ResourceManager} eviction heap threshold. * <p/> * The JRockit JVM has similar flags, <code>-Xgc:gencon</code> and <code>-XXgcTrigger:N</code>, * which are required if using this LRU algorithm. Please Note: the JRockit gcTrigger flag is * based on heap free, not heap in use like the GemFire parameter. This means you need to set * gcTrigger to 100-N. for example, if your eviction threshold is 30 percent, you will need to set * gcTrigger to 70 percent. * <p/> * On the IBM JVM, the flag to get a similar collector is <code>-Xgcpolicy:gencon</code>, but * there is no corollary to the gcTrigger/CMSInitiatingOccupancyFraction flags, so when using this * feature with an IBM JVM, the heap usage statistics might lag the true memory usage of the JVM, * and thresholds may need to be set sufficiently high that the JVM will initiate GC before the * thresholds are crossed. * <p/> * If you are using a <code>cache.xml</code> file to create a Cache Region declaratively, you can * include the following to create an LRU heap eviction controller: * <p/> * * <pre> * <region-attributes> * <eviction-attributes> * <lru-heap-percentage action="local-destroy" * </eviction-attributes> * </region-attributes> * </pre> * <p/> * * @return {@linkplain EvictionAlgorithm#LRU_HEAP heap LRU} eviction attributes with default * {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action} and default * {@linkplain ObjectSizer#DEFAULT sizer} */ public static EvictionAttributes createLRUHeapAttributes() { return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_HEAP) .setAction(EvictionAction.DEFAULT_EVICTION_ACTION).setObjectSizer(ObjectSizer.DEFAULT); } /** * Creates and returns {@linkplain EvictionAlgorithm#LRU_HEAP heap LRU} eviction attributes with * default {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action} and the given * <code>sizer</code>. * * @param sizer the sizer implementation used to determine the size of each entry in this region * @return {@linkplain EvictionAlgorithm#LRU_HEAP heap LRU} eviction attributes with default * {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action} and the given * <code>sizer</code> * @see #createLRUHeapAttributes() */ public static EvictionAttributes createLRUHeapAttributes(final ObjectSizer sizer) { return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_HEAP) .setAction(EvictionAction.DEFAULT_EVICTION_ACTION).setObjectSizer(sizer); } /** * Creates and returns {@linkplain EvictionAlgorithm#LRU_HEAP heap LRU} eviction attributes with * the given <code>evictionAction</code> and given <code>sizer</code>. * * @param sizer the sizer implementation used to determine the size of each entry in this region * @param evictionAction the way in which entries should be evicted * @return {@linkplain EvictionAlgorithm#LRU_HEAP heap LRU} eviction attributes with the given * <code>evictionAction</code> and given <code>sizer</code> * @see #createLRUHeapAttributes() */ public static EvictionAttributes createLRUHeapAttributes(final ObjectSizer sizer, final EvictionAction evictionAction) { return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_HEAP) .setAction(evictionAction).setObjectSizer(sizer); } /** * Creates and returns {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes * with default {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action}, default * {@linkplain ObjectSizer#DEFAULT sizer}, and default {@linkplain #DEFAULT_MEMORY_MAXIMUM * maximum}. * <p/> * Creates EvictionAttributes for an eviction controller that will remove the least recently used * (LRU) entry from a region once the region reaches a certain byte capacity. Capacity is * determined by monitoring the size of entries added and evicted. Capacity is specified in terms * of megabytes. GemFire uses an efficient algorithm to determine the amount of space a region * entry occupies in the JVM. However, this algorithm may not yield optimal results for all kinds * of data. The user may provide his or her own algorithm for determining the size of objects by * implementing an {@link ObjectSizer}. * <p/> * <p/> * For a region with {@link DataPolicy#PARTITION}, the EvictionAttribute <code>maximum</code>, is * always equal to {@link PartitionAttributesFactory#setLocalMaxMemory(int) " local max memory "} * specified for the {@link PartitionAttributes}. It signifies the amount of memory allowed in the * region, collectively for its primary buckets and redundant copies for this JVM. It can be * different for the same region in different JVMs. * <p/> * If you are using a <code>cache.xml</code> file to create a Cache Region declaratively, you can * include the following to create an LRU memory eviction controller: * <p/> * * <pre> * <region-attributes> * <eviction-attributes> * <lru-memory-size maximum="10" action="local-destroy"> * <class-name>com.foo.MySizer</class-name> * <parameter name="name"> * <string>Super Sizer</string> * </parameter> * </lru-memory-size> * </eviction-attributes> * </region-attributes> * </pre> * * @return {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes with default * {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action}, default * {@linkplain ObjectSizer#DEFAULT sizer}, and default {@linkplain #DEFAULT_MEMORY_MAXIMUM * maximum} */ public static EvictionAttributes createLRUMemoryAttributes() { return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_MEMORY) .setAction(EvictionAction.DEFAULT_EVICTION_ACTION) .internalSetMaximum(DEFAULT_MEMORY_MAXIMUM).setObjectSizer(ObjectSizer.DEFAULT); } /** * Creates and returns {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes * with default {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action}, default * {@linkplain ObjectSizer#DEFAULT sizer}, and given <code>maximumMegabytes</code>. * <p/> * <p/> * For a region with {@link DataPolicy#PARTITION}, even if maximumMegabytes are supplied, the * EvictionAttribute <code>maximum</code>, is always set to * {@link PartitionAttributesFactory#setLocalMaxMemory(int) " local max memory "} specified for * the {@link PartitionAttributes}. * <p/> * * @param maximumMegabytes the maximum allowed bytes in the Region * @return {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes with default * {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action}, default * {@linkplain ObjectSizer#DEFAULT sizer}, and given <code>maximumMegabytes</code> * @see #createLRUMemoryAttributes() */ public static EvictionAttributes createLRUMemoryAttributes(int maximumMegabytes) { return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_MEMORY) .setAction(EvictionAction.DEFAULT_EVICTION_ACTION).internalSetMaximum(maximumMegabytes) .setObjectSizer(null); } /** * Creates and returns {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes * with default {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action}, given * <code>sizer</code>, and given <code>maximumMegabytes</code>. * <p/> * <p> * For a region with {@link DataPolicy#PARTITION}, even if maximumMegabytes are supplied, the * EvictionAttribute <code>maximum</code>, is always set to * {@link PartitionAttributesFactory#setLocalMaxMemory(int) " local max memory "} specified for * the {@link PartitionAttributes}. * * @param maximumMegabytes the maximum allowed bytes in the Region * @param sizer calculates the size in bytes of the key and value for an entry. * @return {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes with default * {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action}, given <code>sizer</code>, * and given <code>maximumMegabytes</code> * @see #createLRUMemoryAttributes() */ public static EvictionAttributes createLRUMemoryAttributes(int maximumMegabytes, ObjectSizer sizer) { return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_MEMORY) .setAction(EvictionAction.DEFAULT_EVICTION_ACTION).internalSetMaximum(maximumMegabytes) .setObjectSizer(sizer); } /** * Creates and returns {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes * with the given <code>evictionAction</code>, given <code>sizer</code>, and given * <code>maximumMegabytes</code>. * <p/> * <p> * For a region with {@link DataPolicy#PARTITION}, even if maximumMegabytes are supplied, the * EvictionAttribute <code>maximum</code>, is always set to * {@link PartitionAttributesFactory#setLocalMaxMemory(int) " local max memory "} specified for * the {@link PartitionAttributes}. * * @param maximumMegabytes the maximum allowed bytes in the Region * @param sizer calculates the size in bytes of the key and value for an entry. * @param evictionAction the action to take when the maximum has been reached. * @return {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes with the given * <code>evictionAction</code>, given <code>sizer</code>, and given * <code>maximumMegabytes</code> * @see #createLRUMemoryAttributes() */ public static EvictionAttributes createLRUMemoryAttributes(int maximumMegabytes, ObjectSizer sizer, EvictionAction evictionAction) { return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_MEMORY) .setAction(evictionAction).internalSetMaximum(maximumMegabytes).setObjectSizer(sizer); } /** * Creates and returns {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes * with default {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action}, given * <code>sizer</code>, and default {@linkplain #DEFAULT_MEMORY_MAXIMUM maximum}. * <p/> * <p> * For a region with {@link DataPolicy#PARTITION}, even if maximumMegabytes are supplied, the * EvictionAttribute <code>maximum</code>, is always set to * {@link PartitionAttributesFactory#setLocalMaxMemory(int) " local max memory "} specified for * the {@link PartitionAttributes}. * * @param sizer calculates the size in bytes of the key and value for an entry. * @return {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes with default * {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action}, given <code>sizer</code>, * and default {@linkplain #DEFAULT_MEMORY_MAXIMUM maximum} * @see #createLRUMemoryAttributes() * @since GemFire 6.0 */ public static EvictionAttributes createLRUMemoryAttributes(ObjectSizer sizer) { return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_MEMORY) .setAction(EvictionAction.DEFAULT_EVICTION_ACTION).setObjectSizer(sizer) .internalSetMaximum(DEFAULT_MEMORY_MAXIMUM); } /** * Creates and returns {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes * with given <code>evictionAction</code>, given <code>sizer</code>, and default * {@linkplain #DEFAULT_MEMORY_MAXIMUM maximum}. * <p/> * <p> * For a region with {@link DataPolicy#PARTITION}, even if maximumMegabytes are supplied, the * EvictionAttribute <code>maximum</code>, is always set to * {@link PartitionAttributesFactory#setLocalMaxMemory(int) " local max memory "} specified for * the {@link PartitionAttributes}. * * @param sizer calculates the size in bytes of the key and value for an entry. * @param evictionAction the action to take when the maximum has been reached. * @return {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes with given * <code>evictionAction</code>, given <code>sizer</code>, and default * {@linkplain #DEFAULT_MEMORY_MAXIMUM maximum} * @see #createLRUMemoryAttributes() * @since GemFire 6.0 */ public static EvictionAttributes createLRUMemoryAttributes(ObjectSizer sizer, EvictionAction evictionAction) { return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_MEMORY) .setAction(evictionAction).setObjectSizer(sizer).internalSetMaximum(DEFAULT_MEMORY_MAXIMUM); } /** * An {@link ObjectSizer} is used by the {@link EvictionAlgorithm#LRU_MEMORY} algorithm to measure * the size of each Entry as it is entered into a Region. A default implementation is provided, * see {@link #createLRUMemoryAttributes()} for more. An {@link ObjectSizer} is used by * {@link EvictionAlgorithm#LRU_HEAP} to estimate how much heap will be saved when evicting a * region entry. * * @return the sizer used by {@link EvictionAlgorithm#LRU_MEMORY} or * {@link EvictionAlgorithm#LRU_HEAP}, for all other algorithms null is returned. */ public abstract ObjectSizer getObjectSizer(); /** * The algorithm is used to identify entries that will be evicted. * * @return a non-null EvictionAlgorithm instance reflecting the configured value or NONE when no * eviction controller has been configured. */ public abstract EvictionAlgorithm getAlgorithm(); /** * The unit of this value is determined by the definition of the {@link EvictionAlgorithm} set by * one of the creation methods e.g. {@link EvictionAttributes#createLRUEntryAttributes()} * * @return maximum value used by the {@link EvictionAlgorithm} which determines when the * {@link EvictionAction} is performed. */ public abstract int getMaximum(); /** @return action that the {@link EvictionAlgorithm} takes when the maximum value is reached. */ public abstract EvictionAction getAction(); @Override public final boolean equals(final Object obj) { if (obj == this) { return true; } if (!(obj instanceof EvictionAttributes)) { return false; } final EvictionAttributes other = (EvictionAttributes) obj; if (!this.getAlgorithm().equals(other.getAlgorithm()) || !this.getAction().equals(other.getAction())) { return false; } // LRUHeap doesn't support maximum if (!this.getAlgorithm().isLRUHeap() && this.getMaximum() != other.getMaximum()) { return false; } return true; } @Override public final int hashCode() { if (getAlgorithm().isLRUHeap()) { return getAlgorithm().hashCode(); } else { return this.getAlgorithm().hashCode() ^ this.getMaximum(); } } @Override public String toString() { final StringBuilder buffer = new StringBuilder(128); buffer.append(" algorithm=").append(this.getAlgorithm()); if (!this.getAlgorithm().isNone()) { buffer.append("; action=").append(this.getAction()); if (!getAlgorithm().isLRUHeap()) { buffer.append("; maximum=").append(this.getMaximum()); } if (this.getObjectSizer() != null) { buffer.append("; sizer=").append(this.getObjectSizer()); } } return buffer.toString(); } /** * @return an EvictionAttributes for the LIFOCapacityController * @since GemFire 5.7 */ public static EvictionAttributes createLIFOEntryAttributes(int maximumEntries, EvictionAction evictionAction) { return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LIFO_ENTRY) .setAction(evictionAction).internalSetMaximum(maximumEntries); } /** * @return an EvictionAttributes for the MemLIFOCapacityController * @since GemFire 5.7 */ public static EvictionAttributes createLIFOMemoryAttributes(int maximumMegabytes, EvictionAction evictionAction) { return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LIFO_MEMORY) .setAction(evictionAction).internalSetMaximum(maximumMegabytes).setObjectSizer(null); } }