blob: 6395476caf42661c6e25fe184ed82f87bd589a99 [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;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.logging.log4j.Logger;
import org.apache.geode.InternalGemFireException;
import org.apache.geode.cache.EvictionAction;
import org.apache.geode.cache.RegionDestroyedException;
import org.apache.geode.internal.Assert;
import org.apache.geode.internal.cache.control.InternalResourceManager;
import org.apache.geode.internal.cache.entries.DiskEntry;
import org.apache.geode.internal.cache.eviction.AbstractEvictionController;
import org.apache.geode.internal.cache.eviction.CachedDeserializableValueWrapper;
import org.apache.geode.internal.cache.eviction.EvictableEntry;
import org.apache.geode.internal.cache.eviction.EvictionController;
import org.apache.geode.internal.cache.eviction.EvictionCounters;
import org.apache.geode.internal.cache.eviction.EvictionList;
import org.apache.geode.internal.cache.eviction.EvictionListBuilder;
import org.apache.geode.internal.cache.eviction.HeapEvictor;
import org.apache.geode.internal.cache.persistence.DiskRegionView;
import org.apache.geode.internal.cache.versions.RegionVersionVector;
import org.apache.geode.internal.cache.versions.VersionSource;
import org.apache.geode.internal.logging.log4j.LogMarker;
import org.apache.geode.internal.offheap.StoredObject;
import org.apache.geode.logging.internal.log4j.api.LogService;
/**
* Internal implementation of {@link RegionMap} for regions stored in normal VM memory that maintain
* an LRU.
*
* @since GemFire 3.5.1
*/
// TODO: change back from public to package-private
public class VMLRURegionMap extends AbstractRegionMap {
private static final Logger logger = LogService.getLogger();
public VMLRURegionMap(EvictableRegion owner, Attributes attr,
InternalRegionArguments internalRegionArgs) {
this(owner, attr, internalRegionArgs, createEvictionController(owner, internalRegionArgs));
}
public VMLRURegionMap(EvictableRegion owner, Attributes attr,
InternalRegionArguments internalRegionArgs, EvictionController evictionController) {
super(internalRegionArgs);
initialize(owner, attr, internalRegionArgs);
this.evictionController = evictionController;
getEvictionController().setPerEntryOverhead(getEntryOverhead());
this.lruList = new EvictionListBuilder(getEvictionController()).create();
}
private final EvictionController evictionController;
/** The list of nodes in LRU order */
private final EvictionList lruList;
public EvictionList getEvictionList() {
return this.lruList;
}
@Override
public EvictionController getEvictionController() {
return evictionController;
}
protected void initialize(EvictableRegion evictableRegion, Attributes attr,
InternalRegionArguments internalRegionArgs) {
if (evictableRegion instanceof InternalRegion) {
initialize((InternalRegion) evictableRegion, attr, internalRegionArgs, true);
} else {
initialize((PlaceHolderDiskRegion) evictableRegion, attr, internalRegionArgs, true);
}
}
@Override
public void setEntryFactory(RegionEntryFactory f) {
super.setEntryFactory(f);
if (getEvictionController() != null) {
// any time the entry factory changes we need to recalculate the entry overhead
getEvictionController().setPerEntryOverhead(getEntryOverhead());
}
}
private static EvictionController createEvictionController(EvictableRegion owner,
InternalRegionArguments internalRegionArgs) {
EvictionController controller = owner.getExistingController(internalRegionArgs);
if (controller == null) {
controller = AbstractEvictionController.create(owner.getEvictionAttributes(),
owner.getOffHeap(), owner.getStatisticsFactory(), owner.getNameForStats());
}
return controller;
}
/**
* The delta produced during a put for activating LRU cannot be used while some outside party
* (LocalRegion) has a segment locked... so we'll keep it in a thread local for a callback after
* the segment is released.
*/
private final ThreadLocal lruDelta = new ThreadLocal();
private final ThreadLocal mustRemove = new ThreadLocal();
private final ThreadLocal callbackDisabled = new ThreadLocal();
private int getDelta() {
Object d = lruDelta.get();
lruDelta.set(null); // We only want the delta consumed once
if (d == null)
return 0;
return ((Integer) d).intValue();
}
private void setDelta(int delta) {
if (!getCallbackDisabled()) {
if (getMustRemove()) {
// after implementation of network-partition-detection we may
// run into situations where a cache listener performs a cache
// operation that needs to update LRU stats. In order to do this
// we first have to execute the previous LRU actions.
lruUpdateCallback();
}
setMustRemove(true);
}
Integer delt = (Integer) lruDelta.get();
if (delt != null) {
delta += delt.intValue();
}
lruDelta.set(Integer.valueOf(delta));
}
/**
* Used when a CachedDeserializable's value changes form. PRECONDITION: caller has le synced
*
* @param le the entry whose CachedDeserializable's value changed.
* @param cd the CachedDeserializable whose form has changed
* @param v the new form of the CachedDeserializable's value.
* @return true if finishChangeValueForm needs to be called
* @since GemFire 6.1.2.9
*/
@Override
public boolean beginChangeValueForm(EvictableEntry le, CachedDeserializable cd, Object v) {
// make sure this cached deserializable is still in the entry
{
if (getEvictionController().getEvictionAlgorithm().isLRUEntry()) {
// no need to worry about the value changing form with entry LRU.
return false;
}
Object curVal = le.getValue(); // OFFHEAP: _getValue ok
if (curVal != cd) {
if (cd instanceof StoredObject) {
if (!cd.equals(curVal)) {
return false;
}
} else {
return false;
}
}
}
boolean result = false;
int delta =
le.updateEntrySize(getEvictionController(), new CachedDeserializableValueWrapper(v));
if (delta != 0) {
result = true;
boolean disabledLURCallbacks = disableLruUpdateCallback();
// by making sure that callbacks are disabled when we call
// setDelta; it ensures that the setDelta will just inc the delta
// value and not call lruUpdateCallback which we call in
// finishChangeValueForm
setDelta(delta);
if (disabledLURCallbacks) {
enableLruUpdateCallback();
}
}
// fix for bug 42090
if (getEvictionController().getEvictionAlgorithm().isLRUHeap() && _isOwnerALocalRegion()
&& _getOwner() instanceof BucketRegion
&& HeapEvictor.EVICT_HIGH_ENTRY_COUNT_BUCKETS_FIRST) {
result = false;
}
return result;
}
/**
* @since GemFire 6.1.2.9
*/
@Override
public void finishChangeValueForm() {
lruUpdateCallback();
}
private boolean getMustRemove() {
Object d = mustRemove.get();
if (d == null)
return false;
return ((Boolean) d).booleanValue();
}
private void setMustRemove(boolean b) {
mustRemove.set(b ? Boolean.TRUE : null);
}
private boolean getCallbackDisabled() {
Object d = callbackDisabled.get();
if (d == null)
return false;
return ((Boolean) d).booleanValue();
}
private void setCallbackDisabled(boolean b) {
callbackDisabled.set(b ? Boolean.TRUE : Boolean.FALSE);
}
/**
* Evicts the given entry from the cache. Returns the total number of bytes evicted. 1. For action
* local destroy, returns size(key + value) 2. For action evict to disk, returns size(value)
*
* @return number of bytes evicted, zero if no eviction took place
*/
protected int evictEntry(EvictableEntry entry, EvictionCounters stats)
throws RegionClearedException {
EvictionAction action = getEvictionController().getEvictionAction();
LocalRegion region = _getOwner();
if (action.isLocalDestroy()) {
int size = entry.getEntrySize();
if (region.evictDestroy(entry)) {
stats.incDestroys();
return size;
} else {
return 0;
}
} else if (action.isOverflowToDisk()) {
Assert.assertTrue(entry instanceof DiskEntry);
int change = 0;
synchronized (entry) {
if (entry.isInUseByTransaction()) {
entry.unsetEvicted();
if (logger.isTraceEnabled(LogMarker.LRU_VERBOSE)) {
logger.trace(LogMarker.LRU_VERBOSE, "No eviction of transactional entry for key={}",
entry.getKey());
}
return 0;
}
// Do the following check while synchronized to fix bug 31761
Token entryVal = entry.getValueAsToken();
if (entryVal == null) {
if (logger.isTraceEnabled(LogMarker.LRU_VERBOSE)) {
logger.trace(LogMarker.LRU_VERBOSE, "no need to evict already evicted key={}",
entry.getKey());
}
return 0;
}
if (Token.isInvalidOrRemoved(entryVal)) {
// no need to evict these; it will not save any space
// and the destroyed token needs to stay in memory
if (logger.isTraceEnabled(LogMarker.LRU_VERBOSE)) {
logger.trace(LogMarker.LRU_VERBOSE, "no need to evict {} token for key={}", entryVal,
entry.getKey());
}
return 0;
}
entry.setEvicted();
change =
DiskEntry.Helper.overflowToDisk((DiskEntry) entry, region, getEvictionController());
}
boolean result = change < 0;
if (result) {
if (_getOwner() instanceof BucketRegion) {
BucketRegion bucketRegion = (BucketRegion) _getOwner();
bucketRegion.updateCounter(change);
stats.updateCounter(change);
} else {
stats.updateCounter(change);
}
} else {
if (logger.isTraceEnabled(LogMarker.LRU_VERBOSE)) {
logger.trace(LogMarker.LRU_VERBOSE,
"no need to evict token for key={} because moving its value to disk resulted in a net change of {} bytes.",
entry.getKey(), change);
}
}
return change * -1;
} else {
throw new InternalGemFireException(
String.format("Unknown eviction action: %s", action));
}
}
/**
* update the running counter of all the entries
*
* @param delta Description of the Parameter
*/
protected void changeTotalEntrySize(int delta) {
if (_isOwnerALocalRegion()) {
if (_getOwner() instanceof BucketRegion) {
BucketRegion bucketRegion = (BucketRegion) _getOwner();
bucketRegion.updateCounter(delta);
}
}
getEvictionList().getStatistics().updateCounter(delta);
if (delta > 0) {
if (logger.isTraceEnabled(LogMarker.LRU_VERBOSE)) {
logger.trace(LogMarker.LRU_VERBOSE, "total lru size is now: {}", getTotalEntrySize());
}
}
}
@Override
public void evictValue(Object key) {
throw new IllegalStateException(
"The evictValue is not supported on regions with eviction attributes.");
}
/**
* Gets the total entry size limit for the map from the capacity controller helper.
*
* @return The total allowable size of this maps entries.
*/
protected long getLimit() {
if (_getOwner() instanceof BucketRegion) {
BucketRegion bucketRegion = (BucketRegion) _getOwner();
return bucketRegion.getLimit();
}
return getEvictionController().getCounters().getLimit();
}
public EvictionCounters getLRUStatistics() {
return getEvictionController().getCounters();
}
/**
* return the current size of all the entries.
*
* @return The current size of all the entries.
*/
protected long getTotalEntrySize() {
if (_getOwnerObject() instanceof BucketRegion) {
BucketRegion bucketRegion = (BucketRegion) _getOwner();
return bucketRegion.getCounter();
}
return getEvictionController().getCounters().getCounter();
}
@Override
public void lruUpdateCallback() {
final boolean isDebugEnabled_LRU = logger.isTraceEnabled(LogMarker.LRU_VERBOSE);
if (getCallbackDisabled()) {
return;
}
final int delta = getDelta();
int bytesToEvict = delta;
resetThreadLocals();
if (isDebugEnabled_LRU && _isOwnerALocalRegion()) {
logger.trace(LogMarker.LRU_VERBOSE,
"lruUpdateCallback; list size is: {}; actual size is: {}; map size is: {}; delta is: {}; limit is: {}; tombstone count={}",
getTotalEntrySize(), this.getEvictionList().size(), size(), delta, getLimit(),
_getOwner().getTombstoneCount());
}
EvictionCounters stats = getEvictionList().getStatistics();
if (!_isOwnerALocalRegion()) {
changeTotalEntrySize(delta);
// instead of evicting we just quit faulting values in
} else if (getEvictionController().getEvictionAlgorithm().isLRUHeap()) {
changeTotalEntrySize(delta);
try {
while (bytesToEvict > 0
&& getEvictionController().mustEvict(stats, _getOwner(), bytesToEvict)) {
boolean evictFromThisRegion = true;
if (HeapEvictor.EVICT_HIGH_ENTRY_COUNT_BUCKETS_FIRST
&& _getOwner() instanceof BucketRegion) {
long bytesEvicted = 0;
long totalBytesEvicted = 0;
List<BucketRegion> regions =
((BucketRegion) _getOwner()).getPartitionedRegion().getSortedBuckets();
Iterator<BucketRegion> iter = regions.iterator();
while (iter.hasNext()) {
BucketRegion region = iter.next();
// only primaries can trigger inline eviction fix for 41814
if (!region.getBucketAdvisor().isPrimary()) {
try {
bytesEvicted = region.getRegionMap().centralizedLruUpdateCallback();
if (bytesEvicted == 0) {
iter.remove();
} else {
evictFromThisRegion = false;
}
totalBytesEvicted += bytesEvicted;
bytesToEvict -= bytesEvicted;
if (bytesEvicted > bytesToEvict) {
bytesToEvict = 0;
break;
}
if (totalBytesEvicted > bytesToEvict) {
break;
}
} catch (RegionDestroyedException rd) {
region.cache.getCancelCriterion().checkCancelInProgress(rd);
} catch (Exception e) {
region.cache.getCancelCriterion().checkCancelInProgress(e);
logger.warn(String.format("Exception: %s occurred during eviction ",
new Object[] {e.getMessage()}),
e);
}
}
}
}
if (evictFromThisRegion) {
EvictableEntry removalEntry = getEvictionList().getEvictableEntry();
if (removalEntry != null) {
int sizeOfValue = evictEntry(removalEntry, stats);
if (sizeOfValue != 0) {
bytesToEvict -= sizeOfValue;
if (isDebugEnabled_LRU) {
logger.trace(LogMarker.LRU_VERBOSE,
"evicted entry key={} total entry size is now: {} bytesToEvict :{}",
removalEntry.getKey(), getTotalEntrySize(), bytesToEvict);
}
stats.incEvictions();
if (_isOwnerALocalRegion()) {
_getOwner().incBucketEvictions();
}
if (isDebugEnabled_LRU) {
logger.trace(LogMarker.LRU_VERBOSE, "evictions={}", stats.getEvictions());
}
}
} else {
if (getTotalEntrySize() != 0) {
if (isDebugEnabled_LRU) {
logger.trace(LogMarker.LRU_VERBOSE, "leaving evict loop early");
}
}
break;
}
}
}
} catch (RegionClearedException e) {
if (isDebugEnabled_LRU) {
logger.trace(LogMarker.LRU_VERBOSE, "exception ={}", e.getCause().getMessage(),
e.getCause());
}
}
} else {
try {
// to fix bug 48285 do no evict if bytesToEvict <= 0.
while (bytesToEvict > 0
&& getEvictionController().mustEvict(stats, _getOwner(), bytesToEvict)) {
EvictableEntry removalEntry = (EvictableEntry) getEvictionList().getEvictableEntry();
if (removalEntry != null) {
if (evictEntry(removalEntry, stats) != 0) {
if (isDebugEnabled_LRU) {
logger.trace(LogMarker.LRU_VERBOSE,
"evicted entry key(2)={} total entry size is now: {} bytesToEvict: {}",
removalEntry.getKey(), getTotalEntrySize(), bytesToEvict);
}
stats.incEvictions();
if (_isOwnerALocalRegion()) {
_getOwner().incBucketEvictions();
}
if (isDebugEnabled_LRU) {
logger.trace(LogMarker.LRU_VERBOSE, "evictions={}", stats.getEvictions());
}
}
} else {
if (getTotalEntrySize() != 0) {
if (isDebugEnabled_LRU) {
logger.trace(LogMarker.LRU_VERBOSE, "leaving evict loop early");
}
}
break;
}
}
changeTotalEntrySize(delta);
} catch (RegionClearedException e) {
if (isDebugEnabled_LRU) {
logger.debug("exception ={}", e.getCause().getMessage(), e.getCause());
}
}
}
if (isDebugEnabled_LRU) {
logger.trace(LogMarker.LRU_VERBOSE, "callback complete. LRU size is now {}",
getEvictionController().getCounters().getCounter());
}
// If in transaction context (either local or message)
// reset the tx thread local
}
private boolean mustEvict() {
LocalRegion owner = _getOwner();
InternalResourceManager resourceManager = owner.getCache().getInternalResourceManager();
boolean offheap = owner.getAttributes().getOffHeap();
return resourceManager.getMemoryMonitor(offheap).getState().isEviction() && this.sizeInVM() > 0;
}
@Override
public int centralizedLruUpdateCallback() {
final boolean isDebugEnabled_LRU = logger.isTraceEnabled(LogMarker.LRU_VERBOSE);
int evictedBytes = 0;
if (getCallbackDisabled()) {
return evictedBytes;
}
getDelta();
resetThreadLocals();
if (isDebugEnabled_LRU) {
logger.trace(LogMarker.LRU_VERBOSE,
"centralLruUpdateCallback: lru size is now {}, limit is: {}", getTotalEntrySize(),
getLimit());
}
EvictionCounters stats = getEvictionList().getStatistics();
try {
while (mustEvict() && evictedBytes == 0) {
EvictableEntry removalEntry = getEvictionList().getEvictableEntry();
if (removalEntry != null) {
evictedBytes = evictEntry(removalEntry, stats);
if (evictedBytes != 0) {
_getOwner().incBucketEvictions();
stats.incEvictions();
if (isDebugEnabled_LRU) {
logger.debug("evictions={}", stats.getEvictions());
}
}
} else {
if (getTotalEntrySize() != 0) {
if (isDebugEnabled_LRU) {
logger.trace(LogMarker.LRU_VERBOSE, "leaving evict loop early");
}
}
break;
}
}
} catch (RegionClearedException e) {
// Ignore
if (isDebugEnabled_LRU) {
logger.trace(LogMarker.LRU_VERBOSE, "exception ={}", e.getCause().getMessage(),
e.getCause());
}
}
if (isDebugEnabled_LRU) {
logger.trace(LogMarker.LRU_VERBOSE, "callback complete");
}
// If in transaction context (either local or message)
// reset the tx thread local
return evictedBytes;
}
/**
* Update counter related to limit in list
*
* @since GemFire 5.7
*/
@Override
public void updateEvictionCounter() {
final int delta = getDelta();
resetThreadLocals();
if (logger.isTraceEnabled(LogMarker.LRU_VERBOSE)) {
logger.trace(LogMarker.LRU_VERBOSE, "updateStats - delta is: {} total is: {} limit is: {}",
delta, getTotalEntrySize(), getLimit());
}
if (delta != 0) {
changeTotalEntrySize(delta);
}
}
@Override
public boolean disableLruUpdateCallback() {
if (getCallbackDisabled()) {
return false;
} else {
setCallbackDisabled(true);
return true;
}
}
@Override
public void enableLruUpdateCallback() {
setCallbackDisabled(false);
}
@Override
public void resetThreadLocals() {
mustRemove.set(null);
lruDelta.set(null);
callbackDisabled.set(null);
}
@Override
public Set<VersionSource> clear(RegionVersionVector rvv, BucketRegion bucketRegion) {
getEvictionList().clear(rvv, bucketRegion);
return super.clear(rvv, bucketRegion);
}
/*
* Asif : Motivation: An entry which is no longer existing in the system due to clear operation,
* should not be present the LRUList being used by the region.
*
* Case1 : An entry has been written to disk & on its return code path, it invokes lruCreate or
* lruUpdate. Before starting the operation of writing to disk, the HTree reference is set in the
* threadlocal. A clear operation changes the Htree reference in a write lock. Thus if the htree
* reference has not changed till this point, it would mean either the entry is still valid or a
* clear operation is in progress but has not changed the Htree Reference . Since we store the
* LRUList in a local variable, it implies that if clear occurs , it will go in the stale list &
* if not it goes in the right list. Both ways we are safe.
*
* Case 2: The Htree reference has changed ( implying a clear conflic with put) but the entry is
* valid. This is possible as we first set the Htree Ref in thread local. Now before the update
* operation has acquired the entry , clear happens. As a result the update operation has become
* create. Since the clear changes the Htree Ref & the LRUList in a write lock & hence by the time
* the original update operation acquires the read lock, the LRUList has already been changed by
* clear. Now in the update operation's return path the List which it stores in local variable is
* bound to be the new List. Since our code checks if the entry reference exists in the region in
* case of conflict & if yes, we append the entry to the List. It is guaranteed to be added to the
* new List.
*
* Also it is necessary that when we clear the region, first the concurrent map of the region
* containing entries needs to be cleared. The Htree Reference should be reset after that. And
* then we should be resetting the LRUList. Previously the Htree reference was being set before
* clearing the Map. This caused Bug 37606. If the order of clear operation on disk region is (
* incorrect ) 1) map.clear 2) Resetting the LRUList 3) Changing the Htree ref Then following bug
* can occur., During entry operation on its return path, invokes lruUpdate/lruCreate. By that
* time the clear proceeds & it has reset the LRUList & cleared the entries. But as the Htree ref
* has not changed, we would take the locally available LRUList ( which may be the new List) &
* append the entry to the List.
*
*
*
*/
@Override
public void lruEntryCreate(RegionEntry re) {
EvictableEntry e = (EvictableEntry) re;
if (logger.isTraceEnabled(LogMarker.LRU_VERBOSE)) {
logger.trace(LogMarker.LRU_VERBOSE,
"lruEntryCreate for key={}; list size is: {}; actual size is: {}; map size is: {}; entry size: {}; in lru clock: {}",
re.getKey(), getTotalEntrySize(), this.getEvictionList().size(), size(), e.getEntrySize(),
!e.isEvicted());
}
e.unsetEvicted();
EvictionList lruList = getEvictionList();
DiskRegion disk = _getOwner().getDiskRegion();
boolean possibleClear = disk != null && disk.didClearCountChange();
if (!possibleClear || this._getOwner().basicGetEntry(re.getKey()) == re) {
lruList.appendEntry(e);
lruEntryUpdate(e);
}
}
@Override
public void lruEntryUpdate(RegionEntry re) {
final EvictableEntry e = (EvictableEntry) re;
setDelta(e.updateEntrySize(getEvictionController()));
if (logger.isDebugEnabled()) {
logger.debug("lruEntryUpdate for key={} size={}", re.getKey(), e.getEntrySize());
}
EvictionList lruList = getEvictionList();
if (_isOwnerALocalRegion()) {
DiskRegion disk = _getOwner().getDiskRegion();
boolean possibleClear = disk != null && disk.didClearCountChange();
if (!possibleClear || this._getOwner().basicGetEntry(re.getKey()) == re) {
if (e instanceof DiskEntry) {
if (!e.isEvicted()) {
lruList.appendEntry(e);
}
}
// Why reset the refcount? All the txs that currently reference
// this region entry still do but they will now fail with conflicts.
// But they also have logic in them to dec the refcount.
// I think we did the resetRefCount thinking it was safe
// to drop it back to zero since the RE was modified and give
// us a chance to evict it. But if the txs that are going to fail
// with a conflict still do refCountDecs then after the reset any
// new txs that inc the refcount may have their count decd by one of
// the old txs allowing the entry to be evicted and causing a tx conflict.
// TODO: this should now be safe but why the odd condition for this block
// and why call lruList.appendEntry twice (once above and once in resetRefCount.
// Also lruEntryUpdate only happens on an lru. Do we need to call reset for the non-lru
// (expiration) case?
e.resetRefCount(lruList);
}
} else {
// We are recovering the region so it is a DiskEntry.
// Also clear is not yet possible and this entry will be in the region.
// No need to call resetRefCount since tx are not yet possible.
if (!e.isEvicted()) {
lruList.appendEntry(e);
}
}
}
@Override
public void lruEntryDestroy(RegionEntry regionEntry) {
final EvictableEntry e = (EvictableEntry) regionEntry;
if (logger.isTraceEnabled(LogMarker.LRU_VERBOSE)) {
logger.trace(LogMarker.LRU_VERBOSE,
"lruEntryDestroy for key={}; list size is: {}; actual size is: {}; map size is: {}; entry size: {}; in lru clock: {}",
regionEntry.getKey(), getTotalEntrySize(), this.getEvictionList().size(), size(),
e.getEntrySize(), !e.isEvicted());
}
getEvictionList().destroyEntry(e);
changeTotalEntrySize(-1 * e.getEntrySize());// subtract the size.
Token vTok = regionEntry.getValueAsToken();
if (vTok == Token.DESTROYED || vTok == Token.TOMBSTONE) {
// OFFHEAP noop TODO: use re.isDestroyedOrTombstone
// if in token mode we need to recalculate the size of the entry since it's
// staying in the map and may be resurrected
e.updateEntrySize(getEvictionController());
}
}
/**
* Called by DiskEntry.Helper.faultInValue
*/
@Override
public void lruEntryFaultIn(EvictableEntry e) {
if (logger.isDebugEnabled()) {
logger.debug("lruEntryFaultIn for key={} size={}", e.getKey(), e.getEntrySize());
}
EvictionList lruList = getEvictionList();
if (_isOwnerALocalRegion()) {
DiskRegion disk = _getOwner().getDiskRegion();
boolean possibleClear = disk != null && disk.didClearCountChange();
if (!possibleClear || this._getOwner().basicGetEntry(e.getKey()) == e) {
lruEntryUpdate(e);
e.unsetEvicted();
lruList.appendEntry(e);
}
} else {
lruEntryUpdate(e);
lruList.appendEntry(e);
}
}
@Override
public void decTxRefCount(RegionEntry re) {
LocalRegion lr = null;
if (_isOwnerALocalRegion()) {
lr = _getOwner();
}
re.decRefCount(getEvictionList(), lr);
}
@Override
public boolean lruLimitExceeded(DiskRegionView diskRegionView) {
return getEvictionController().lruLimitExceeded(getEvictionController().getCounters(),
diskRegionView);
}
@Override
public void lruCloseStats() {
getEvictionList().closeStats();
}
@Override
public boolean confirmEvictionDestroy(RegionEntry regionEntry) {
// We assume here that a LRURegionMap contains LRUEntries
EvictableEntry lruRe = (EvictableEntry) regionEntry;
if (lruRe.isInUseByTransaction() || lruRe.isDestroyed()) {
lruRe.unsetEvicted();
return false;
} else {
return true;
}
}
@Override
public long getEvictions() {
return this.getEvictionController().getCounters().getEvictions();
}
@Override
public void incRecentlyUsed() {
getEvictionList().incrementRecentlyUsed();
}
}