blob: 85be05e385a2b0982dc0f3e0d4e98c38845327f4 [file] [log] [blame]
/*
* 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.internal.cache.eviction;
import org.apache.geode.StatisticsFactory;
import org.apache.geode.cache.EvictionAction;
import org.apache.geode.cache.EvictionAlgorithm;
import org.apache.geode.cache.EvictionAttributes;
import org.apache.geode.cache.util.ObjectSizer;
import org.apache.geode.internal.cache.BucketRegion;
/**
* Eviction controllers that extend this class evict the least recently used (LRU) entry in the
* region whose capacity they controller. In order to provide an efficient computation of the LRU
* entry, GemFire uses special internal data structures for managing the contents of a region. As a
* result, there are several restrictions that are placed on regions whose capacity is governed by
* an LRU algorithm.
*
* <ul>
* <li>If the capacity of a region is to be controlled by an LRU algorithm, then the region must be
* <b>created</b> with {@link EvictionAttributes}
* <li>The eviction controller of a region governed by an LRU algorithm cannot be changed.</li>
* <li>An LRU algorithm cannot be applied to a region after the region has been created.</li>
* </ul>
*
* <p>
* LRU algorithms also specify what {@linkplain EvictionAction action} should be performed upon the
* least recently used entry when the capacity is reached. Currently, there are two supported
* actions: {@linkplain EvictionAction#LOCAL_DESTROY locally destroying} the entry (which is the
* {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION default}), thus freeing up space in the VM,
* and {@linkplain EvictionAction#OVERFLOW_TO_DISK overflowing} the value of the entry to disk.
*
* <p>
* {@link EvictionAttributes Eviction controllers} that use an LRU algorithm maintain certain
* region-dependent state (such as the maximum number of entries allowed in the region). As a
* result, an instance of {@code AbstractEvictionController} cannot be shared among multiple
* regions. Attempts to create a region with a LRU-based capacity controller that has already been
* used to create another region will result in an {@link IllegalStateException} being thrown.
*
* @since GemFire 3.2
*/
public abstract class AbstractEvictionController implements EvictionController {
/**
* Create and return the appropriate eviction controller using the attributes provided.
*/
public static EvictionController create(EvictionAttributes evictionAttributes, boolean isOffHeap,
StatisticsFactory statsFactory, String statsName) {
EvictionAlgorithm algorithm = evictionAttributes.getAlgorithm();
EvictionAction action = evictionAttributes.getAction();
ObjectSizer sizer = evictionAttributes.getObjectSizer();
int maximum = evictionAttributes.getMaximum();
EvictionStats evictionStats;
EvictionCounters evictionCounters;
if (algorithm == EvictionAlgorithm.LRU_HEAP) {
evictionStats = new HeapLRUStatistics(statsFactory, statsName);
evictionCounters = new EvictionCountersImpl(evictionStats);
return new HeapLRUController(evictionCounters, action, sizer, algorithm);
}
if (algorithm == EvictionAlgorithm.LRU_MEMORY || algorithm == EvictionAlgorithm.LIFO_MEMORY) {
evictionStats = new MemoryLRUStatistics(statsFactory, statsName);
evictionCounters = new EvictionCountersImpl(evictionStats);
return new MemoryLRUController(evictionCounters, maximum, sizer, action, isOffHeap,
algorithm);
}
if (algorithm == EvictionAlgorithm.LRU_ENTRY || algorithm == EvictionAlgorithm.LIFO_ENTRY) {
evictionStats = new CountLRUStatistics(statsFactory, statsName);
evictionCounters = new EvictionCountersImpl(evictionStats);
return new CountLRUEviction(evictionCounters, maximum, action, algorithm);
}
throw new IllegalStateException("Unhandled algorithm " + algorithm);
}
/**
* What to do upon eviction
*/
private final EvictionAction evictionAction;
/**
* Used to dynamically track the changing region limit.
*/
private final EvictionCounters counters;
private final EvictionAlgorithm algorithm;
/**
* Creates a new {@code AbstractEvictionController} with the given {@linkplain EvictionAction
* eviction action}.
*
*/
protected AbstractEvictionController(EvictionCounters evictionCounters,
EvictionAction evictionAction, EvictionAlgorithm algorithm) {
this.counters = evictionCounters;
this.evictionAction = evictionAction;
this.algorithm = algorithm;
}
/**
* Force subclasses to have a reasonable {@code toString}
*
* @since GemFire 4.0
*/
@Override
public abstract String toString();
/**
* Gets the action that is performed on the least recently used entry when it is evicted from the
* VM.
*
* @return one of the following constants: {@link EvictionAction#LOCAL_DESTROY},
* {@link EvictionAction#OVERFLOW_TO_DISK}
*/
@Override
public EvictionAction getEvictionAction() {
return this.evictionAction;
}
@Override
public EvictionCounters getCounters() {
return this.counters;
}
@Override
public EvictionAlgorithm getEvictionAlgorithm() {
return this.algorithm;
}
@Override
public long limit() {
return getCounters().getLimit();
}
@Override
public void close() {
getCounters().close();
}
@Override
public void closeBucket(BucketRegion bucketRegion) {
getCounters().decrementCounter(bucketRegion.getCounter());
}
@Override
public void setPerEntryOverhead(int entryOverhead) {
// nothing needed by default
}
}