blob: 5b2e779504628098129687775f4d9986a4885774 [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.map;
import org.apache.logging.log4j.Logger;
import org.apache.geode.InternalGemFireError;
import org.apache.geode.annotations.internal.MutableForTesting;
import org.apache.geode.cache.CacheWriterException;
import org.apache.geode.cache.EntryNotFoundException;
import org.apache.geode.cache.TimeoutException;
import org.apache.geode.cache.query.internal.index.IndexManager;
import org.apache.geode.internal.Assert;
import org.apache.geode.internal.cache.EntryEventImpl;
import org.apache.geode.internal.cache.HARegion;
import org.apache.geode.internal.cache.InternalRegion;
import org.apache.geode.internal.cache.RegionClearedException;
import org.apache.geode.internal.cache.RegionEntry;
import org.apache.geode.internal.cache.Token;
import org.apache.geode.internal.cache.versions.ConcurrentCacheModificationException;
import org.apache.geode.internal.cache.versions.VersionStamp;
import org.apache.geode.internal.cache.versions.VersionTag;
import org.apache.geode.internal.logging.log4j.LogMarker;
import org.apache.geode.internal.offheap.annotations.Released;
import org.apache.geode.internal.sequencelog.EntryLogger;
import org.apache.geode.logging.internal.log4j.api.LogService;
/**
* RegionMap Destroy operation.
*
* <p>
* Extracted from AbstractRegionMap.
*/
public class RegionMapDestroy {
private static final Logger logger = LogService.getLogger();
@MutableForTesting
static Runnable testHookRunnableForConcurrentOperation;
private final InternalRegion internalRegion;
private final FocusedRegionMap focusedRegionMap;
private final CacheModificationLock cacheModificationLock;
private EntryEventImpl event;
private boolean inTokenMode;
private boolean duringRI;
private boolean cacheWrite;
private boolean isEviction;
private Object expectedOldValue;
private boolean removeRecoveredEntry;
private boolean retry = true;
private boolean opCompleted = false;
private boolean doPart3 = false;
private boolean retainForConcurrency = false;
private boolean abortDestroyAndReturnFalse;
private RegionEntry oldRegionEntry;
private RegionEntry newRegionEntry;
private RegionEntry regionEntry;
private RegionEntry tombstone;
private boolean haveTombstone;
private boolean doContinue;
public RegionMapDestroy(InternalRegion internalRegion, FocusedRegionMap focusedRegionMap,
CacheModificationLock cacheModificationLock) {
this.internalRegion = internalRegion;
this.focusedRegionMap = focusedRegionMap;
this.cacheModificationLock = cacheModificationLock;
}
public boolean destroy(final EntryEventImpl eventArg, final boolean inTokenModeArg,
final boolean duringRIArg, final boolean cacheWriteArg, final boolean isEvictionArg,
final Object expectedOldValueArg, final boolean removeRecoveredEntryArg)
throws CacheWriterException, EntryNotFoundException, TimeoutException {
if (internalRegion == null) {
throw new InternalGemFireError("The internalRegion for RegionMap " + this
+ " is null for event " + event);
}
event = eventArg;
inTokenMode = inTokenModeArg;
duringRI = duringRIArg;
cacheWrite = cacheWriteArg;
isEviction = isEvictionArg;
expectedOldValue = expectedOldValueArg;
removeRecoveredEntry = removeRecoveredEntryArg;
if (event.isFromRILocalDestroy()) {
// for RI local-destroy we don't want to keep tombstones.
// In order to simplify things we just set this recovery
// flag to true to force the entry to be removed
removeRecoveredEntry = true;
}
cacheModificationLock.lockForCacheModification(internalRegion, event);
final boolean locked = internalRegion.lockWhenRegionIsInitializing();
try {
while (retry) {
retry = false;
opCompleted = false;
tombstone = null;
haveTombstone = false;
doContinue = false;
abortDestroyAndReturnFalse = false;
regionEntry = focusedRegionMap.getEntry(event);
invokeTestHookForConcurrentOperation();
try {
if (logger.isTraceEnabled(LogMarker.LRU_TOMBSTONE_COUNT_VERBOSE)
&& !(internalRegion instanceof HARegion)) {
logger.trace(LogMarker.LRU_TOMBSTONE_COUNT_VERBOSE,
"ARM.destroy() inTokenMode={}; duringRI={}; riLocalDestroy={}; withRepl={}; fromServer={}; concurrencyEnabled={}; isOriginRemote={}; isEviction={}; operation={}; re={}",
inTokenMode, duringRI, event.isFromRILocalDestroy(),
internalRegion.getDataPolicy().withReplication(), event.isFromServer(),
internalRegion.getConcurrencyChecksEnabled(), event.isOriginRemote(), isEviction,
event.getOperation(), regionEntry);
}
// the logic in this method is already very involved, and adding tombstone
// permutations to (re != null) greatly complicates it. So, we check
// for a tombstone here and, if found, pretend for a bit that the entry is null
if (regionEntry != null && regionEntry.isTombstone() && !removeRecoveredEntry) {
tombstone = regionEntry;
haveTombstone = true;
regionEntry = null;
}
if (regionEntry == null) {
checkTombstoneAndConcurrency();
if (inTokenMode || retainForConcurrency) {
handleMissingRegionEntry();
}
} else {
handleExistingRegionEntry();
}
if (abortDestroyAndReturnFalse) {
return false;
}
if (doContinue) {
continue;
}
if (opCompleted) {
EntryLogger.logDestroy(event);
}
return opCompleted;
} finally {
try {
triggerDistributionAndListenerNotification();
} finally {
cancelExpiryTaskIfRegionEntryExisted();
}
}
} // retry loop
} finally {
if (locked) {
internalRegion.unlockWhenRegionIsInitializing();
}
cacheModificationLock.releaseCacheModificationLock(internalRegion, event);
}
return false;
}
private void checkTombstoneAndConcurrency() {
if (regionEntry == null) {
// we need to create an entry if in token mode or if we've received
// a destroy from a peer or WAN gateway and we need to retain version
// information for concurrency checks
retainForConcurrency = (!haveTombstone
&& (internalRegion.getDataPolicy().withReplication() || event.isFromServer())
&& internalRegion.getConcurrencyChecksEnabled()
&& (event.isOriginRemote() /* destroy received from other must create tombstone */
|| event.isFromWANAndVersioned() /* wan event must create a tombstone */
|| event.isBridgeEvent())); /*
* event from client must create a tombstone so client has
* a version #
*/
if (!inTokenMode && !retainForConcurrency) {
retryRemoveWithTombstone();
}
}
}
private void handleExistingRegionEntry() {
IndexManager oqlIndexManager = internalRegion.getIndexManager();
if (oqlIndexManager != null) {
oqlIndexManager.waitForIndexInit();
}
try {
synchronized (regionEntry) {
internalRegion.checkReadiness();
// if the entry is a tombstone and the event is from a peer or a client
// then we allow the operation to be performed so that we can update the
// version stamp. Otherwise we would retain an old version stamp and may allow
// an operation that is older than the destroy() to be applied to the cache
// Bug 45170: If removeRecoveredEntry, we treat tombstone as regular entry to be
// deleted
boolean createTombstoneForConflictChecks = (internalRegion.getConcurrencyChecksEnabled()
&& (event.isOriginRemote() || event.getContext() != null || removeRecoveredEntry));
if (!regionEntry.isRemoved() || createTombstoneForConflictChecks) {
retryIfIsRemovedPhase2();
if (doContinue) {
return;
}
abortLocalExpirationIfEntryIsInUseByTransaction();
if (abortDestroyAndReturnFalse) {
return;
}
event.setRegionEntry(regionEntry);
// See comment above about eviction checks
confirmEvictionDestroy();
if (abortDestroyAndReturnFalse) {
return;
}
destroyExistingEntry();
} else { // already removed
updateVersionTagOnEntryWithTombstone();
if (expectedOldValue != null) {
abortDestroyAndReturnFalse = true;
return;
}
if (!inTokenMode && !isEviction) {
internalRegion.checkEntryNotFound(event.getKey());
}
}
} // synchronized re
} catch (ConcurrentCacheModificationException e) {
VersionTag tag = event.getVersionTag();
if (tag != null && tag.isTimeStampUpdated()) {
// Notify gateways of new time-stamp.
internalRegion.notifyTimestampsToGateways(event);
}
throw e;
} finally {
if (oqlIndexManager != null) {
oqlIndexManager.countDownIndexUpdaters();
}
}
// No need to call lruUpdateCallback since the only lru action
// we may have taken was lruEntryDestroy. This fixes bug 31759.
}
private void cancelExpiryTaskIfRegionEntryExisted() {
if (opCompleted) {
if (regionEntry != null) {
// we only want to cancel if concurrency-check is not enabled
// regionEntry will be null when concurrency-check is enable and removeTombstone
// method
// will call cancelExpiryTask on regionEntry
internalRegion.cancelExpiryTask(regionEntry);
}
}
}
private void triggerDistributionAndListenerNotification() {
// If concurrency conflict is there and event contains gateway version tag then
// do NOT distribute.
if (event.isConcurrencyConflict()
&& (event.getVersionTag() != null && event.getVersionTag().isGatewayTag())) {
doPart3 = false;
}
// distribution and listener notification
if (doPart3) {
internalRegion.basicDestroyPart3(regionEntry, event, inTokenMode, duringRI, true,
expectedOldValue);
}
}
private void updateVersionTagOnEntryWithTombstone() {
if (regionEntry.isTombstone() && event.getVersionTag() != null) {
// if we're dealing with a tombstone and this is a remote event
// (e.g., from cache client update thread) we need to update
// the tombstone's version information
// TODO use destroyEntry() here
focusedRegionMap.processVersionTag(regionEntry, event);
try {
regionEntry.makeTombstone(internalRegion, event.getVersionTag());
} catch (RegionClearedException e) {
// that's okay - when writing a tombstone into a disk, the
// region has been cleared (including this tombstone)
}
}
}
private void confirmEvictionDestroy() {
if (isEviction) {
assert expectedOldValue == null;
if (!focusedRegionMap.confirmEvictionDestroy(regionEntry)) {
opCompleted = false;
abortDestroyAndReturnFalse = true;
}
}
}
private void abortLocalExpirationIfEntryIsInUseByTransaction() {
if (!event.isOriginRemote() && event.getOperation().isExpiration()) {
// If this expiration started locally then only do it if the RE is not being
// used by a tx.
if (regionEntry.isInUseByTransaction()) {
opCompleted = false;
abortDestroyAndReturnFalse = true;
}
}
}
private void retryIfIsRemovedPhase2() {
if (regionEntry.isRemovedPhase2()) {
focusedRegionMap.getEntryMap().remove(event.getKey(), regionEntry);
internalRegion.getCachePerfStats().incRetries();
retry = true;
doContinue = true;
}
}
private void retryRemoveWithTombstone() {
if (!isEviction || internalRegion.getConcurrencyChecksEnabled()) {
// The following ensures that there is not a concurrent operation
// on the entry and leaves behind a tombstone if concurrencyChecksEnabled.
// It fixes bug #32467 by propagating the destroy to the server even though
// the entry isn't in the client
newRegionEntry = haveTombstone ? tombstone
: focusedRegionMap.getEntryFactory().createEntry(internalRegion, event.getKey(),
Token.REMOVED_PHASE1);
synchronized (newRegionEntry) {
if (haveTombstone && !tombstone.isTombstone()) {
// we have to check this again under synchronization since it may have changed
retry = true;
doContinue = true;
return;
}
regionEntry = focusedRegionMap.putEntryIfAbsent(event.getKey(), newRegionEntry);
if (regionEntry != null && regionEntry != tombstone) {
// concurrent change - try again
retry = true;
doContinue = true;
return;
} else {
try {
if (!isEviction) {
handleEntryNotFound();
}
} finally {
if (isEviction && newRegionEntry.isTombstone()) {
return;
} else {
removeEntryOrLeaveTombstone();
}
}
}
} // synchronized(newRegionEntry)
}
}
private void invokeTestHookForConcurrentOperation() {
/*
* Execute the test hook runnable inline (not threaded) if it is not null.
*/
if (null != testHookRunnableForConcurrentOperation) {
testHookRunnableForConcurrentOperation.run();
}
}
private void destroyExistingEntry() {
boolean removed = false;
try {
opCompleted = destroyEntry(regionEntry, event, inTokenMode, cacheWrite, expectedOldValue,
false, removeRecoveredEntry);
if (opCompleted) {
// It is very, very important for Partitioned Regions to keep
// the entry in the map until after distribution occurs so that other
// threads performing a create on this entry wait until the destroy
// distribution is finished.
// keeping backup copies consistent. Fix for bug 35906.
internalRegion.basicDestroyBeforeRemoval(regionEntry, event);
// do this before basicDestroyPart2 to fix bug 31786
if (!inTokenMode) {
if (regionEntry.getVersionStamp() == null) {
regionEntry.removePhase2();
focusedRegionMap.removeEntry(event.getKey(), regionEntry, true, event, internalRegion);
removed = true;
}
}
if (inTokenMode && !duringRI) {
event.inhibitCacheListenerNotification(true);
}
doPart3 = true;
internalRegion.basicDestroyPart2(regionEntry, event, inTokenMode,
false /* conflict with clear */, duringRI, true);
focusedRegionMap.lruEntryDestroy(regionEntry);
} else {
if (!inTokenMode) {
EntryLogger.logDestroy(event);
internalRegion.recordEvent(event);
if (regionEntry.getVersionStamp() == null) {
regionEntry.removePhase2();
focusedRegionMap.removeEntry(event.getKey(), regionEntry, true, event, internalRegion);
focusedRegionMap.lruEntryDestroy(regionEntry);
} else {
if (regionEntry.isTombstone()) {
// the entry is already a tombstone, but we're destroying it
// again, so we need to reschedule the tombstone's expiration
if (event.isOriginRemote()) {
internalRegion.rescheduleTombstone(regionEntry,
regionEntry.getVersionStamp().asVersionTag());
}
}
}
focusedRegionMap.lruEntryDestroy(regionEntry);
opCompleted = true;
}
}
} catch (RegionClearedException rce) {
// Ignore. The exception will ensure that we do not update
// the LRU List
opCompleted = true;
internalRegion.recordEvent(event);
if (inTokenMode && !duringRI) {
event.inhibitCacheListenerNotification(true);
}
internalRegion.basicDestroyPart2(regionEntry, event, inTokenMode,
true /* conflict with clear */, duringRI, true);
doPart3 = true;
} finally {
internalRegion.checkReadiness();
if (regionEntry.isRemoved() && !regionEntry.isTombstone()) {
if (!removed) {
focusedRegionMap.removeEntry(event.getKey(), regionEntry, true, event, internalRegion);
}
}
}
}
private void removeEntryOrLeaveTombstone() {
// either remove the entry or leave a tombstone
try {
if (!event.isOriginRemote() && event.getVersionTag() != null
&& internalRegion.getConcurrencyChecksEnabled()) {
// this shouldn't fail since we just created the entry.
// it will either generate a tag or apply a server's version tag
focusedRegionMap.processVersionTag(newRegionEntry, event);
if (doPart3) {
internalRegion.generateAndSetVersionTag(event, newRegionEntry);
}
try {
internalRegion.recordEvent(event);
newRegionEntry.makeTombstone(internalRegion, event.getVersionTag());
} catch (RegionClearedException e) {
// that's okay - when writing a tombstone into a disk, the
// region has been cleared (including this tombstone)
}
opCompleted = true;
// lruEntryCreate(newRegionEntry);
} else if (!haveTombstone) {
try {
assert newRegionEntry != tombstone;
newRegionEntry.setValue(internalRegion, Token.REMOVED_PHASE2);
focusedRegionMap.removeEntry(event.getKey(), newRegionEntry, false);
} catch (RegionClearedException e) {
// that's okay - we just need to remove the new entry
}
} else if (event.getVersionTag() != null) { // haveTombstone - update the
// tombstone version info
focusedRegionMap.processVersionTag(tombstone, event);
if (doPart3) {
// TODO: this looks like dead code. We only get here if doPart3 is true
// but then only happens if !event.isOriginRemote() && concurrencyChecks().
// But if we have a versionTag then we will have concurrencyChecks().
// If concurrencyChecks is false then this code makes no sense;
// we should not be doing anything with version tags in that case.
internalRegion.generateAndSetVersionTag(event, newRegionEntry);
}
// This is not conflict, we need to persist the tombstone again with new
// version tag
try {
tombstone.setValue(internalRegion, Token.TOMBSTONE);
} catch (RegionClearedException e) {
// that's okay - when writing a tombstone into a disk, the
// region has been cleared (including this tombstone)
}
internalRegion.recordEvent(event);
internalRegion.rescheduleTombstone(tombstone, event.getVersionTag());
internalRegion.basicDestroyPart2(tombstone, event, inTokenMode,
true /* conflict with clear */, duringRI, true);
opCompleted = true;
} else {
Assert.assertTrue(event.getVersionTag() == null);
Assert.assertTrue(newRegionEntry == tombstone);
event.setVersionTag(getVersionTagFromStamp(tombstone.getVersionStamp()));
}
} catch (ConcurrentCacheModificationException e) {
VersionTag tag = event.getVersionTag();
if (tag != null && tag.isTimeStampUpdated()) {
// Notify gateways of new time-stamp.
internalRegion.notifyTimestampsToGateways(event);
}
throw e;
}
}
private void handleEntryNotFound() {
boolean throwException = false;
EntryNotFoundException entryNotFoundException = null;
if (!cacheWrite) {
throwException = true;
} else {
try {
if (!removeRecoveredEntry) {
throwException = !internalRegion.bridgeWriteBeforeDestroy(event, expectedOldValue);
}
} catch (EntryNotFoundException e) {
throwException = true;
entryNotFoundException = e;
}
}
if (throwException) {
if (!event.isOriginRemote() && !event.getOperation().isLocal()
&& (event.isFromBridgeAndVersioned() || // if this is a replayed client
// event that already has a
// version
event.isFromWANAndVersioned())) { // or if this is a WAN event that
// has been applied in another
// system
// we must distribute these since they will update the version information
// in peers
if (logger.isDebugEnabled()) {
logger.debug("ARM.destroy is allowing wan/client destroy of {} to continue",
event.getKey());
}
throwException = false;
event.setIsRedestroyedEntry(true);
// Distribution of this op happens on re and re might me null here before
// distributing this destroy op.
if (regionEntry == null) {
regionEntry = newRegionEntry;
}
doPart3 = true;
}
}
if (throwException) {
if (entryNotFoundException == null) {
// Fix for 48182, check cache state and/or region state before sending
// entry not found.
// this is from the server and any exceptions will propogate to the client
internalRegion.checkEntryNotFound(event.getKey());
} else {
throw entryNotFoundException;
}
}
}
private void handleMissingRegionEntry() {
// removeRecoveredEntry should be false in this case
newRegionEntry = focusedRegionMap.getEntryFactory().createEntry(internalRegion, event.getKey(),
Token.REMOVED_PHASE1);
IndexManager oqlIndexManager = internalRegion.getIndexManager();
if (oqlIndexManager != null) {
oqlIndexManager.waitForIndexInit();
}
try {
synchronized (newRegionEntry) {
oldRegionEntry = focusedRegionMap.putEntryIfAbsent(event.getKey(), newRegionEntry);
// what is this doing?
removeRegionEntryUntilCompleted();
if (abortDestroyAndReturnFalse) {
return;
}
if (!opCompleted) {
// The following try has a finally that cleans up the newRegionEntry.
// This is only needed if newRegionEntry was added to the map which only
// happens if we didn't get completed with oldRegionEntry in the above while
// loop.
try {
regionEntry = newRegionEntry;
event.setRegionEntry(newRegionEntry);
try {
// if concurrency checks are enabled, destroy will set the version tag
if (isEviction) {
opCompleted = false;
abortDestroyAndReturnFalse = true;
return;
}
destroyEntryInternal(newRegionEntry, oldRegionEntry);
} catch (RegionClearedException rce) {
handleRegionClearedExceptionDuringDestroyEntryInternal(newRegionEntry);
} catch (ConcurrentCacheModificationException ccme) {
VersionTag tag = event.getVersionTag();
if (tag != null && tag.isTimeStampUpdated()) {
// Notify gateways of new time-stamp.
internalRegion.notifyTimestampsToGateways(event);
}
throw ccme;
}
// Note no need for LRU work since the entry is destroyed
// and will be removed when gii completes
} finally {
if (!opCompleted && !haveTombstone /* to fix bug 51583 do this for all operations */ ) {
focusedRegionMap.removeEntry(event.getKey(), newRegionEntry, false);
}
if (!opCompleted && isEviction) {
focusedRegionMap.removeEntry(event.getKey(), newRegionEntry, false);
}
}
} // !opCompleted
} // synchronized newRegionEntry
} finally {
if (oqlIndexManager != null) {
oqlIndexManager.countDownIndexUpdaters();
}
}
}
private void removeRegionEntryUntilCompleted() {
while (!opCompleted && oldRegionEntry != null) {
synchronized (oldRegionEntry) {
if (oldRegionEntry.isRemovedPhase2()) {
internalRegion.getCachePerfStats().incRetries();
focusedRegionMap.getEntryMap().remove(event.getKey(), oldRegionEntry);
oldRegionEntry = focusedRegionMap.putEntryIfAbsent(event.getKey(), newRegionEntry);
} else {
event.setRegionEntry(oldRegionEntry);
// Last transaction related eviction check. This should
// prevent
// transaction conflict (caused by eviction) when the entry
// is being added to transaction state.
if (isEviction) {
if (!focusedRegionMap.confirmEvictionDestroy(oldRegionEntry)) {
opCompleted = false;
abortDestroyAndReturnFalse = true;
return;
}
}
try {
// if concurrency checks are enabled, destroy will set the version tag
boolean destroyed = destroyEntry(oldRegionEntry, event, inTokenMode, cacheWrite,
expectedOldValue, false, removeRecoveredEntry);
if (destroyed) {
if (retainForConcurrency) {
internalRegion.basicDestroyBeforeRemoval(oldRegionEntry, event);
}
internalRegion.basicDestroyPart2(oldRegionEntry, event, inTokenMode,
false /* conflict with clear */, duringRI, true);
focusedRegionMap.lruEntryDestroy(oldRegionEntry);
doPart3 = true;
}
} catch (RegionClearedException rce) {
// Ignore. The exception will ensure that we do not update
// the LRU List
internalRegion.basicDestroyPart2(oldRegionEntry, event, inTokenMode,
true/* conflict with clear */, duringRI, true);
doPart3 = true;
} catch (ConcurrentCacheModificationException ccme) {
// TODO: GEODE-3967: change will go here
VersionTag tag = event.getVersionTag();
if (tag != null && tag.isTimeStampUpdated()) {
// Notify gateways of new time-stamp.
internalRegion.notifyTimestampsToGateways(event);
}
throw ccme;
}
regionEntry = oldRegionEntry;
opCompleted = true;
}
} // synchronized oldRegionEntry
} // while
}
private void handleRegionClearedExceptionDuringDestroyEntryInternal(RegionEntry newRegionEntry) {
// Ignore. The exception will ensure that we do not update the LRU List
opCompleted = true;
EntryLogger.logDestroy(event);
internalRegion.basicDestroyPart2(newRegionEntry, event, inTokenMode, true, duringRI, true);
doPart3 = true;
}
private void destroyEntryInternal(RegionEntry newRegionEntry, RegionEntry oldRegionEntry)
throws RegionClearedException {
opCompleted = destroyEntry(newRegionEntry, event, inTokenMode, cacheWrite, expectedOldValue,
true, removeRecoveredEntry);
if (opCompleted) {
// This is a new entry that was created because we are in
// token mode or are accepting a destroy operation by adding
// a tombstone. There is no oldValue, so we don't need to
// call updateSizeOnRemove
// internalRegion.recordEvent(event);
event.setIsRedestroyedEntry(true); // native clients need to know if the
// entry didn't exist
if (retainForConcurrency) {
internalRegion.basicDestroyBeforeRemoval(oldRegionEntry, event);
}
internalRegion.basicDestroyPart2(newRegionEntry, event, inTokenMode, false, duringRI, true);
doPart3 = true;
}
}
private boolean destroyEntry(RegionEntry re, EntryEventImpl event, boolean inTokenMode,
boolean cacheWrite, @Released Object expectedOldValue, boolean forceDestroy,
boolean removeRecoveredEntry) throws CacheWriterException, TimeoutException,
EntryNotFoundException, RegionClearedException {
focusedRegionMap.processVersionTag(re, event);
final int oldSize = internalRegion.calculateRegionEntryValueSize(re);
final boolean wasRemoved = re.isDestroyedOrRemoved();
boolean retVal = re.destroy(event.getRegion(), event, inTokenMode, cacheWrite, expectedOldValue,
forceDestroy, removeRecoveredEntry);
if (retVal) {
EntryLogger.logDestroy(event);
if (!wasRemoved) {
internalRegion.updateSizeOnRemove(event.getKey(), oldSize);
}
}
return retVal;
}
private VersionTag getVersionTagFromStamp(VersionStamp stamp) {
VersionTag tag = VersionTag.create(stamp.getMemberID());
tag.setEntryVersion(stamp.getEntryVersion());
tag.setRegionVersion(stamp.getRegionVersion());
tag.setVersionTimeStamp(stamp.getVersionTimeStamp());
tag.setDistributedSystemId(stamp.getDistributedSystemId());
return tag;
}
}