/*
* 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);
}
}