This is an automated email from the ASF dual-hosted git repository.
dschneider pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/develop by this push:
new 586d7c3 GEODE-5195: add unit tests for RegionMapPut (#1964)
586d7c3 is described below
commit 586d7c3076cce04f66ab3d975f3b4eccbe6b1c67
Author: Darrel Schneider <[email protected]>
AuthorDate: Wed May 16 10:25:00 2018 -0700
GEODE-5195: add unit tests for RegionMapPut (#1964)
---
.../geode/internal/cache/map/RegionMapPut.java | 152 ++---
.../geode/internal/cache/map/RegionMapPutTest.java | 654 ++++++++++++++++++++-
2 files changed, 716 insertions(+), 90 deletions(-)
diff --git
a/geode-core/src/main/java/org/apache/geode/internal/cache/map/RegionMapPut.java
b/geode-core/src/main/java/org/apache/geode/internal/cache/map/RegionMapPut.java
index 506b7b7..50dc4fa 100644
---
a/geode-core/src/main/java/org/apache/geode/internal/cache/map/RegionMapPut.java
+++
b/geode-core/src/main/java/org/apache/geode/internal/cache/map/RegionMapPut.java
@@ -21,7 +21,6 @@ import java.util.Set;
import org.apache.geode.cache.CacheWriter;
import org.apache.geode.cache.DiskAccessException;
import org.apache.geode.cache.Operation;
-import org.apache.geode.internal.cache.CachePerfStats;
import org.apache.geode.internal.cache.EntryEventImpl;
import org.apache.geode.internal.cache.EntryEventSerialization;
import org.apache.geode.internal.cache.InternalRegion;
@@ -35,7 +34,6 @@ import
org.apache.geode.internal.cache.wan.GatewaySenderEventImpl;
import org.apache.geode.internal.offheap.OffHeapHelper;
import org.apache.geode.internal.offheap.ReferenceCountHelper;
import org.apache.geode.internal.offheap.annotations.Released;
-import org.apache.geode.internal.offheap.annotations.Retained;
import org.apache.geode.internal.offheap.annotations.Unretained;
import org.apache.geode.internal.sequencelog.EntryLogger;
@@ -169,53 +167,49 @@ public class RegionMapPut extends AbstractRegionMapPut {
final EntryEventImpl event = getEvent();
final RegionEntry re = getRegionEntry();
event.setRegionEntry(re);
- boolean needToSetOldValue =
- isCacheWrite() || isRequireOldValue() ||
event.getOperation().guaranteesOldValue();
- if (needToSetOldValue) {
- if (event.getOperation().guaranteesOldValue()) {
- // In these cases we want to even get the old value from disk if it is
not in memory
- ReferenceCountHelper.skipRefCountTracking();
- @Released
- Object oldValueInVMOrDisk =
re.getValueOffHeapOrDiskWithoutFaultIn(event.getRegion());
- ReferenceCountHelper.unskipRefCountTracking();
- try {
- event.setOldValue(oldValueInVMOrDisk, true);
- } finally {
- OffHeapHelper.releaseWithNoTracking(oldValueInVMOrDisk);
- }
- } else {
- // In these cases only need the old value if it is in memory
- ReferenceCountHelper.skipRefCountTracking();
-
- @Retained
- @Released
- Object oldValueInVM = re.getValueRetain(event.getRegion(), true); //
OFFHEAP: re
- // synced so can use
- // its ref.
- if (oldValueInVM == null) {
- oldValueInVM = Token.NOT_AVAILABLE;
- }
- ReferenceCountHelper.unskipRefCountTracking();
- try {
- event.setOldValue(oldValueInVM);
- } finally {
- OffHeapHelper.releaseWithNoTracking(oldValueInVM);
- }
- }
+ if (event.getOperation().guaranteesOldValue()) {
+ setOldValueEvenIfFaultedOut();
+ } else if (isCacheWrite() || isRequireOldValue()) {
+ setOldValueIfNotFaultedOut();
} else {
- // if the old value is in memory then if it is a GatewaySenderEventImpl
then
- // we want to set the old value.
@Unretained
- Object ov = re.getValue(); // OFFHEAP _getValue is ok since re is synced
and we only use it
- // if its a GatewaySenderEventImpl.
- // Since GatewaySenderEventImpl is never stored in an off-heap region
nor a compressed region
- // we don't need to worry about ov being compressed.
- if (ov instanceof GatewaySenderEventImpl) {
- event.setOldValue(ov, true);
+ Object existingValue = re.getValue();
+ if (existingValue instanceof GatewaySenderEventImpl) {
+ event.setOldValue(existingValue, true);
}
}
}
+ private void setOldValueIfNotFaultedOut() {
+ final EntryEventImpl event = getEvent();
+ ReferenceCountHelper.skipRefCountTracking();
+ @Released
+ Object oldValueInVM = getRegionEntry().getValueRetain(event.getRegion(),
true);
+ if (oldValueInVM == null) {
+ oldValueInVM = Token.NOT_AVAILABLE;
+ }
+ ReferenceCountHelper.unskipRefCountTracking();
+ try {
+ event.setOldValue(oldValueInVM);
+ } finally {
+ OffHeapHelper.releaseWithNoTracking(oldValueInVM);
+ }
+ }
+
+ private void setOldValueEvenIfFaultedOut() {
+ final EntryEventImpl event = getEvent();
+ ReferenceCountHelper.skipRefCountTracking();
+ @Released
+ Object oldValueInVMOrDisk =
+
getRegionEntry().getValueOffHeapOrDiskWithoutFaultIn(event.getRegion());
+ ReferenceCountHelper.unskipRefCountTracking();
+ try {
+ event.setOldValue(oldValueInVMOrDisk, true);
+ } finally {
+ OffHeapHelper.releaseWithNoTracking(oldValueInVMOrDisk);
+ }
+ }
+
@Override
protected void unsetOldValueForDelta() {
OffHeapHelper.release(getOldValueForDelta());
@@ -300,20 +294,24 @@ public class RegionMapPut extends AbstractRegionMapPut {
getLastModifiedTime(), invokeListeners, isIfNew(), isIfOld(),
getExpectedOldValue(),
isRequireOldValue());
} finally {
- if (!isClearOccurred()) {
- try {
- getRegionMap().lruUpdateCallback();
- } catch (DiskAccessException dae) {
- getOwner().handleDiskAccessException(dae);
- throw dae;
- }
- }
+ lruUpdateCallbackIfNotCleared();
}
} else {
getRegionMap().resetThreadLocals();
}
}
+ private void lruUpdateCallbackIfNotCleared() {
+ if (!isClearOccurred()) {
+ try {
+ getRegionMap().lruUpdateCallback();
+ } catch (DiskAccessException dae) {
+ getOwner().handleDiskAccessException(dae);
+ throw dae;
+ }
+ }
+ }
+
private boolean isUpdate() {
if (isCacheWrite() && getEvent().getOperation().isUpdate()) {
// if there is a cacheWriter, type of event has already been set
@@ -329,18 +327,27 @@ public class RegionMapPut extends AbstractRegionMapPut {
}
/**
- * @return false if precondition indicates that
+ * @return false if preconditions indicate that
* the put should not be done.
*/
@Override
protected boolean checkPreconditions() {
- if (continueUpdate() && continueOverwriteDestroyed() &&
satisfiesExpectedOldValue()) {
- return true;
+ if (!checkUpdatePreconditions()) {
+ return false;
}
- return false;
+ if (!checkUninitializedRegionPreconditions()) {
+ return false;
+ }
+ if (!checkCreatePreconditions()) {
+ return false;
+ }
+ if (!checkExpectedOldValuePrecondition()) {
+ return false;
+ }
+ return true;
}
- private boolean continueUpdate() {
+ private boolean checkUpdatePreconditions() {
if (isIfOld()) {
final EntryEventImpl event = getEvent();
final RegionEntry re = getRegionEntry();
@@ -364,23 +371,29 @@ public class RegionMapPut extends AbstractRegionMapPut {
return true;
}
- private boolean continueOverwriteDestroyed() {
- Token oldValueInVM = getRegionEntry().getValueAsToken();
- // if region is under GII, check if token is destroyed
- if (!isOverwriteDestroyed()) {
- if (!getOwner().isInitialized()
- && (oldValueInVM == Token.DESTROYED || oldValueInVM ==
Token.TOMBSTONE)) {
- getEvent().setOldValueDestroyedToken();
- return false;
+ private boolean checkUninitializedRegionPreconditions() {
+ if (!getOwner().isInitialized()) {
+ if (!isOverwriteDestroyed()) {
+ Token oldValueInVM = getRegionEntry().getValueAsToken();
+ if (oldValueInVM == Token.DESTROYED || oldValueInVM ==
Token.TOMBSTONE) {
+ getEvent().setOldValueDestroyedToken();
+ return false;
+ }
}
}
- if (isIfNew() && !Token.isRemoved(oldValueInVM)) {
- return false;
+ return true;
+ }
+
+ private boolean checkCreatePreconditions() {
+ if (isIfNew()) {
+ if (!getRegionEntry().isDestroyedOrRemoved()) {
+ return false;
+ }
}
return true;
}
- private boolean satisfiesExpectedOldValue() {
+ private boolean checkExpectedOldValuePrecondition() {
// replace is propagated to server, so no need to check
// satisfiesOldValue on client
final EntryEventImpl event = getEvent();
@@ -431,10 +444,7 @@ public class RegionMapPut extends AbstractRegionMapPut {
} else {
getOwner().updateSizeOnCreate(key, newBucketSize);
if (!wasTombstone) {
- CachePerfStats stats = getOwner().getCachePerfStats();
- if (stats != null) {
- stats.incEntryCount(1);
- }
+ getOwner().getCachePerfStats().incEntryCount(1);
}
}
}
diff --git
a/geode-core/src/test/java/org/apache/geode/internal/cache/map/RegionMapPutTest.java
b/geode-core/src/test/java/org/apache/geode/internal/cache/map/RegionMapPutTest.java
index 391575e..dfbe381 100644
---
a/geode-core/src/test/java/org/apache/geode/internal/cache/map/RegionMapPutTest.java
+++
b/geode-core/src/test/java/org/apache/geode/internal/cache/map/RegionMapPutTest.java
@@ -17,10 +17,15 @@
package org.apache.geode.internal.cache.map;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.AdditionalMatchers.not;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -28,22 +33,30 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Map;
+import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.geode.cache.CacheWriter;
+import org.apache.geode.cache.DiskAccessException;
import org.apache.geode.cache.Operation;
+import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.Scope;
import org.apache.geode.internal.cache.CachePerfStats;
import org.apache.geode.internal.cache.EntryEventImpl;
import org.apache.geode.internal.cache.EntryEventSerialization;
+import org.apache.geode.internal.cache.ImageState;
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.RegionEntryFactory;
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.cache.wan.GatewaySenderEventImpl;
import org.apache.geode.test.junit.categories.UnitTest;
@Category(UnitTest.class)
@@ -53,7 +66,7 @@ public class RegionMapPutTest {
private final CacheModificationLock cacheModificationLock =
mock(CacheModificationLock.class);
private final EntryEventSerialization entryEventSerialization =
mock(EntryEventSerialization.class);
- private final RegionEntry regionEntry = mock(RegionEntry.class);
+ private final RegionEntry createdRegionEntry = mock(RegionEntry.class);
private final EntryEventImpl event = mock(EntryEventImpl.class);
private boolean ifNew = false;
private boolean ifOld = false;
@@ -61,21 +74,25 @@ public class RegionMapPutTest {
private Object expectedOldValue = null;
private boolean overwriteDestroyed = false;
private RegionMapPut instance;
+ private final RegionEntry existingRegionEntry = mock(RegionEntry.class);
@Before
public void setup() {
RegionEntryFactory regionEntryFactory = mock(RegionEntryFactory.class);
- when(regionEntryFactory.createEntry(any(), any(),
any())).thenReturn(regionEntry);
+ when(regionEntryFactory.createEntry(any(), any(),
any())).thenReturn(createdRegionEntry);
when(internalRegion.getScope()).thenReturn(Scope.LOCAL);
when(internalRegion.isInitialized()).thenReturn(true);
when(internalRegion.getCachePerfStats()).thenReturn(mock(CachePerfStats.class));
+
when(internalRegion.getAttributes()).thenReturn(mock(RegionAttributes.class));
+ when(internalRegion.getImageState()).thenReturn(mock(ImageState.class));
when(focusedRegionMap.getEntryMap()).thenReturn(mock(Map.class));
when(focusedRegionMap.getEntryFactory()).thenReturn(regionEntryFactory);
- when(event.getOperation()).thenReturn(Operation.UPDATE);
+ givenAnOperationThatDoesNotGuaranteeOldValue();
when(event.getKey()).thenReturn("key");
when(event.getRegion()).thenReturn(internalRegion);
- when(regionEntry.getValueAsToken()).thenReturn(Token.REMOVED_PHASE1);
- when(regionEntry.isRemoved()).thenReturn(true);
+
when(createdRegionEntry.getValueAsToken()).thenReturn(Token.REMOVED_PHASE1);
+ when(createdRegionEntry.isRemoved()).thenReturn(true);
+ when(createdRegionEntry.isDestroyedOrRemoved()).thenReturn(true);
}
private void createInstance() {
@@ -90,12 +107,298 @@ public class RegionMapPutTest {
}
@Test
+ public void
doesNotSetEventOldValueToExistingRegionEntryValue_ifNotRequired() {
+ givenExistingRegionEntry();
+ givenAnOperationThatDoesNotGuaranteeOldValue();
+ givenPutDoesNotNeedToDoCacheWrite();
+ this.requireOldValue = false;
+
+ Object oldValue = new Object();
+ when(existingRegionEntry.getValue()).thenReturn(oldValue);
+
+ doPut();
+
+ verify(event, never()).setOldValue(any());
+ verify(event, never()).setOldValue(any(), anyBoolean());
+ }
+
+ @Test
+ public void
setsEventOldValueToExistingRegionEntryValue_ifOldValueIsGatewaySenderEvent() {
+ givenExistingRegionEntry();
+
+ GatewaySenderEventImpl oldValue = new GatewaySenderEventImpl();
+ when(existingRegionEntry.getValue()).thenReturn(oldValue);
+
+ doPut();
+
+ verify(event, times(1)).setOldValue(same(oldValue), eq(true));
+ verify(event, never()).setOldValue(not(same(oldValue)), eq(true));
+ }
+
+ @Test
+ public void
setsEventOldValueToExistingRegionEntryValue_ifOperationGuaranteesOldValue() {
+ givenExistingRegionEntry();
+ givenAnOperationThatGuaranteesOldValue();
+
+ Object oldValue = new Object();
+
when(existingRegionEntry.getValueOffHeapOrDiskWithoutFaultIn(same(internalRegion)))
+ .thenReturn(oldValue);
+
+ doPut();
+
+ verify(event, times(1)).setOldValue(same(oldValue), eq(true));
+ verify(event, never()).setOldValue(not(same(oldValue)), eq(true));
+ }
+
+ @Test
+ public void eventPutExistingEntryGivenOldValue_ifRetrieveOldValueForDelta()
+ throws RegionClearedException {
+ givenThatRunWhileEvictionDisabledCallsItsRunnable();
+ givenExistingRegionEntry();
+ Object oldValue = new Object();
+ when(existingRegionEntry.getValue(any())).thenReturn(oldValue);
+ when(event.getDeltaBytes()).thenReturn(new byte[1]);
+
+ doPut();
+
+ verify(event, times(1)).putExistingEntry(same(internalRegion),
same(existingRegionEntry),
+ eq(false), same(oldValue));
+ }
+
+ @Test
+ public void
eventPutExistingEntryGivenNullOldValue_ifNotRetrieveOldValueForDelta()
+ throws RegionClearedException {
+ givenThatRunWhileEvictionDisabledCallsItsRunnable();
+ givenExistingRegionEntry();
+ Object oldValue = new Object();
+ when(existingRegionEntry.getValue(any())).thenReturn(oldValue);
+ when(event.getDeltaBytes()).thenReturn(null);
+
+ doPut();
+
+ verify(event, times(1)).putExistingEntry(same(internalRegion),
same(existingRegionEntry),
+ eq(false), eq(null));
+ }
+
+ @Test
+ public void
setsEventOldValueToExistingRegionEntryValue_ifIsRequiredOldValueAndOperationDoesNotGuaranteeOldValue()
{
+ this.requireOldValue = true;
+ givenExistingRegionEntry();
+ givenAnOperationThatDoesNotGuaranteeOldValue();
+
+ Object oldValue = new Object();
+ when(existingRegionEntry.getValueRetain(same(internalRegion),
eq(true))).thenReturn(oldValue);
+
+ doPut();
+
+ verify(event, times(1)).setOldValue(same(oldValue));
+ verify(event, never()).setOldValue(not(same(oldValue)));
+ }
+
+ @Test
+ public void
setsEventOldValueToExistingRegionEntryValue_ifIsCacheWriteAndOperationDoesNotGuaranteeOldValue()
{
+ givenExistingRegionEntry();
+ givenAnOperationThatDoesNotGuaranteeOldValue();
+ givenPutNeedsToDoCacheWrite();
+
+ Object oldValue = new Object();
+ when(existingRegionEntry.getValueRetain(same(internalRegion),
eq(true))).thenReturn(oldValue);
+
+ doPut();
+
+ verify(event, times(1)).setOldValue(same(oldValue));
+ verify(event, never()).setOldValue(not(same(oldValue)));
+ }
+
+ @Test
+ public void
setsEventOldValueToNotAvailable_ifIsCacheWriteAndOperationDoesNotGuaranteeOldValue_andExistingValueIsNull()
{
+ givenPutNeedsToDoCacheWrite();
+ givenAnOperationThatDoesNotGuaranteeOldValue();
+ givenExistingRegionEntry();
+
+ when(existingRegionEntry.getValueRetain(same(internalRegion),
eq(true))).thenReturn(null);
+
+ doPut();
+
+ verify(event, times(1)).setOldValue(Token.NOT_AVAILABLE);
+ }
+
+ @Test
public void retrieveOldValueForDeltaDefaultToFalse() {
createInstance();
assertThat(instance.isRetrieveOldValueForDelta()).isFalse();
}
+
+ @Test
+ public void
eventOldValueNotAvailableCalled_ifCacheWriteNotNeededAndNotInitialized() {
+ givenPutDoesNotNeedToDoCacheWrite();
+ when(internalRegion.isInitialized()).thenReturn(false);
+
+ doPut();
+
+ verify(event, times(1)).oldValueNotAvailable();
+ }
+
+ @Test
+ public void
eventOperationNotSet_ifCacheWriteNeededAndInitializedAndReplaceOnClient() {
+ givenPutNeedsToDoCacheWrite();
+ when(internalRegion.isInitialized()).thenReturn(true);
+ givenReplaceOnClient();
+
+ doPut();
+
+ verify(event, never()).makeCreate();
+ verify(event, never()).makeUpdate();
+ }
+
+ @Test
+ public void putExistingEntryCalled_ifReplaceOnClient() throws
RegionClearedException {
+ givenPutDoesNotNeedToDoCacheWrite();
+ when(internalRegion.isInitialized()).thenReturn(true);
+ givenReplaceOnClient();
+
+ doPut();
+
+ verify(event, times(1)).putExistingEntry(any(), any(), anyBoolean(),
any());
+ }
+
+ @Test
+ public void
eventOperationMadeCreate_ifCacheWriteNeededAndInitializedAndNotReplaceOnClientAndEntryRemoved()
{
+ givenPutNeedsToDoCacheWrite();
+ when(internalRegion.isInitialized()).thenReturn(true);
+ givenReplaceOnPeer();
+ when(createdRegionEntry.isDestroyedOrRemoved()).thenReturn(true);
+
+ doPut();
+
+ verify(event, times(1)).makeCreate();
+ verify(event, never()).makeUpdate();
+ }
+
+ @Test
+ public void
eventOperationMadeUpdate_ifCacheWriteNeededAndInitializedAndNotReplaceOnClientAndEntryExists()
{
+ givenPutNeedsToDoCacheWrite();
+ when(internalRegion.isInitialized()).thenReturn(true);
+ givenReplaceOnPeer();
+ when(createdRegionEntry.isDestroyedOrRemoved()).thenReturn(false);
+
+ doPut();
+
+ verify(event, never()).makeCreate();
+ verify(event, times(1)).makeUpdate();
+ }
+
+ @Test
+ public void cacheWriteBeforePutNotCalled_ifNotInitialized() {
+ givenPutNeedsToDoCacheWrite();
+ when(internalRegion.isInitialized()).thenReturn(false);
+
+ doPut();
+
+ verify(internalRegion, never()).cacheWriteBeforePut(any(), any(), any(),
anyBoolean(), any());
+ }
+
+ @Test
+ public void cacheWriteBeforePutNotCalled_ifCacheWriteNotNeeded() {
+ givenPutDoesNotNeedToDoCacheWrite();
+ when(internalRegion.isInitialized()).thenReturn(true);
+
+ doPut();
+
+ verify(internalRegion, never()).cacheWriteBeforePut(any(), any(), any(),
anyBoolean(), any());
+ }
+
+ @Test
+ public void
cacheWriteBeforePutCalledWithRequireOldValue_givenRequireOldValueTrue() {
+ givenPutNeedsToDoCacheWrite();
+ when(internalRegion.isInitialized()).thenReturn(true);
+ this.requireOldValue = true;
+
+ doPut();
+
+ verify(internalRegion, times(1)).cacheWriteBeforePut(same(event), any(),
any(),
+ eq(this.requireOldValue), eq(null));
+ }
+
+ @Test
+ public void
cacheWriteBeforePutCalledWithExpectedOldValue_givenRequireOldValueTrue() {
+ givenPutNeedsToDoCacheWrite();
+ when(internalRegion.isInitialized()).thenReturn(true);
+ givenAnOperationThatGuaranteesOldValue();
+ givenExistingRegionEntry();
+ when(existingRegionEntry.getValueRetain(same(internalRegion),
eq(true))).thenReturn(null);
+ expectedOldValue = "expectedOldValue";
+ when(event.getRawOldValue()).thenReturn(expectedOldValue);
+
+ doPut();
+
+ verify(internalRegion, times(1)).cacheWriteBeforePut(same(event), any(),
any(), anyBoolean(),
+ same(expectedOldValue));
+ }
+
+ @Test
+ public void
putWithExpectedOldValueReturnsNull_ifExistingValueIsNotExpected() {
+ givenAnOperationThatGuaranteesOldValue();
+ expectedOldValue = "expectedOldValue";
+ when(event.getRawOldValue()).thenReturn("unexpectedValue");
+
+ RegionEntry result = doPut();
+
+ assertThat(result).isNull();
+ }
+
+ @Test
+ public void
putWithExpectedOldValueReturnsRegionEntry_ifExistingValueIsExpected() {
+ givenAnOperationThatGuaranteesOldValue();
+ expectedOldValue = "expectedOldValue";
+ when(event.getRawOldValue()).thenReturn(expectedOldValue);
+
+ RegionEntry result = doPut();
+
+ assertThat(result).isSameAs(createdRegionEntry);
+ }
+
+ @Test
+ public void
putWithExpectedOldValueReturnsRegionEntry_ifExistingValueIsNotExpectedButIsReplaceOnClient()
{
+ givenAnOperationThatGuaranteesOldValue();
+ expectedOldValue = "expectedOldValue";
+ when(event.getRawOldValue()).thenReturn("unexpectedValue");
+ givenReplaceOnClient();
+
+ RegionEntry result = doPut();
+
+ assertThat(result).isSameAs(createdRegionEntry);
+ }
+
+ @Test
+ public void cacheWriteBeforePutCalledWithCacheWriter_givenACacheWriter() {
+ givenPutNeedsToDoCacheWrite();
+ when(internalRegion.isInitialized()).thenReturn(true);
+ CacheWriter cacheWriter = mock(CacheWriter.class);
+ when(internalRegion.basicGetWriter()).thenReturn(cacheWriter);
+
+ doPut();
+
+ verify(internalRegion, times(1)).cacheWriteBeforePut(same(event),
eq(null), same(cacheWriter),
+ anyBoolean(), eq(null));
+ }
+
+ @Test
+ public void
cacheWriteBeforePutCalledWithNetWriteRecipients_ifAdviseNetWrite() {
+ givenPutNeedsToDoCacheWrite();
+ when(internalRegion.isInitialized()).thenReturn(true);
+ when(internalRegion.basicGetWriter()).thenReturn(null);
+ Set netWriteRecipients = mock(Set.class);
+ when(internalRegion.adviseNetWrite()).thenReturn(netWriteRecipients);
+
+ doPut();
+
+ verify(internalRegion, times(1)).cacheWriteBeforePut(same(event),
eq(netWriteRecipients),
+ eq(null), anyBoolean(), eq(null));
+ }
+
@Test
public void retrieveOldValueForDeltaTrueIfEventHasDeltaBytes() {
when(event.getDeltaBytes()).thenReturn(new byte[1]);
@@ -124,8 +427,7 @@ public class RegionMapPutTest {
@Test
public void replaceOnClientIsTrueIfOperationIsReplaceAndOwnerIsClient() {
- when(event.getOperation()).thenReturn(Operation.REPLACE);
- when(internalRegion.hasServerProxy()).thenReturn(true);
+ givenReplaceOnClient();
createInstance();
@@ -134,7 +436,7 @@ public class RegionMapPutTest {
@Test
public void replaceOnClientIsFalseIfOperationIsReplaceAndOwnerIsNotClient() {
- when(event.getOperation()).thenReturn(Operation.REPLACE);
+ givenReplaceOnPeer();
createInstance();
@@ -142,6 +444,137 @@ public class RegionMapPutTest {
}
@Test
+ public void putReturnsNull_ifOnlyExistingAndEntryIsTombstone() {
+ ifOld = true;
+ givenExistingRegionEntry();
+ when(existingRegionEntry.isTombstone()).thenReturn(true);
+
+ RegionEntry result = doPut();
+
+ assertThat(result).isNull();
+ }
+
+ @Test
+ public void putReturnsExistingEntry_ifOnlyExistingAndEntryIsNotTombstone() {
+ ifOld = true;
+ givenExistingRegionEntry();
+ when(existingRegionEntry.isTombstone()).thenReturn(false);
+
+ RegionEntry result = doPut();
+
+ assertThat(result).isSameAs(existingRegionEntry);
+ }
+
+ @Test
+ public void putReturnsNull_ifOnlyExistingAndEntryIsRemoved() {
+ ifOld = true;
+ givenExistingRegionEntry();
+ when(existingRegionEntry.isRemoved()).thenReturn(true);
+ givenReplaceOnPeer();
+
+ RegionEntry result = doPut();
+
+ assertThat(result).isNull();
+ }
+
+ @Test
+ public void
putReturnsExistingEntry_ifOnlyExistingEntryIsRemovedAndReplaceOnClient() {
+ ifOld = true;
+ givenExistingRegionEntry();
+ when(existingRegionEntry.isRemoved()).thenReturn(true);
+ givenReplaceOnClient();
+
+ RegionEntry result = doPut();
+
+ assertThat(result).isSameAs(existingRegionEntry);
+ }
+
+ @Test
+ public void
putReturnsExistingEntry_ifReplaceOnClientAndTombstoneButNoVersionTag() {
+ ifOld = true;
+ givenReplaceOnClient();
+ givenExistingRegionEntry();
+ when(existingRegionEntry.isTombstone()).thenReturn(true);
+ when(event.getVersionTag()).thenReturn(null);
+
+ RegionEntry result = doPut();
+
+ assertThat(result).isSameAs(existingRegionEntry);
+ }
+
+ @Test
+ public void putReturnsNull_ifReplaceOnClientAndTombstoneAndVersionTag()
+ throws RegionClearedException {
+ ifOld = true;
+ givenReplaceOnClient();
+ givenExistingRegionEntry();
+ when(existingRegionEntry.isTombstone()).thenReturn(true);
+
when(existingRegionEntry.getVersionStamp()).thenReturn(mock(VersionStamp.class));
+ when(event.getVersionTag()).thenReturn(mock(VersionTag.class));
+
+ RegionEntry result = doPut();
+
+ assertThat(result).isNull();
+ verify(existingRegionEntry, times(1)).setValue(internalRegion,
Token.TOMBSTONE);
+ verify(internalRegion,
times(1)).rescheduleTombstone(same(existingRegionEntry), any());
+ }
+
+ @Test
+ public void
createWithoutOverwriteDestroyedReturnsNullAndCallsSetOldValueDestroyedToken_ifRegionUninitializedAndCurrentValueIsDestroyed()
{
+ overwriteDestroyed = false;
+ when(internalRegion.isInitialized()).thenReturn(false);
+ when(createdRegionEntry.getValueAsToken()).thenReturn(Token.DESTROYED);
+
+ RegionEntry result = doPut();
+
+ assertThat(result).isNull();
+ verify(event, times(1)).setOldValueDestroyedToken();
+ }
+
+ @Test
+ public void
createWithoutOverwriteDestroyedReturnsNullAndCallsSetOldValueDestroyedToken_ifRegionUninitializedAndCurrentValueIsTombstone()
{
+ overwriteDestroyed = false;
+ when(internalRegion.isInitialized()).thenReturn(false);
+ when(createdRegionEntry.getValueAsToken()).thenReturn(Token.TOMBSTONE);
+
+ RegionEntry result = doPut();
+
+ assertThat(result).isNull();
+ verify(event, times(1)).setOldValueDestroyedToken();
+ }
+
+ @Test
+ public void
createWithOverwriteDestroyedReturnsCreatedRegionEntry_ifRegionUninitializedAndCurrentValueIsDestroyed()
{
+ overwriteDestroyed = true;
+ when(internalRegion.isInitialized()).thenReturn(false);
+ when(createdRegionEntry.getValueAsToken()).thenReturn(Token.DESTROYED);
+
+ RegionEntry result = doPut();
+
+ assertThat(result).isSameAs(createdRegionEntry);
+ verify(event, never()).setOldValueDestroyedToken();
+ }
+
+ @Test
+ public void
putIgnoresRegionClearedException_ifReplaceOnClientAndTombstoneAndVersionTag()
+ throws RegionClearedException {
+ ifOld = true;
+ givenReplaceOnClient();
+ givenExistingRegionEntry();
+ when(existingRegionEntry.isTombstone()).thenReturn(true);
+
when(existingRegionEntry.getVersionStamp()).thenReturn(mock(VersionStamp.class));
+ when(event.getVersionTag()).thenReturn(mock(VersionTag.class));
+
doThrow(RegionClearedException.class).when(existingRegionEntry).setValue(internalRegion,
+ Token.TOMBSTONE);
+
+ RegionEntry result = doPut();
+
+ assertThat(result).isNull();
+ verify(existingRegionEntry, times(1)).setValue(internalRegion,
Token.TOMBSTONE);
+ verify(internalRegion,
times(1)).rescheduleTombstone(same(existingRegionEntry), any());
+ }
+
+ @Test
public void onlyExistingDefaultsToFalse() {
createInstance();
@@ -160,8 +593,7 @@ public class RegionMapPutTest {
@Test
public void onlyExistingIsFalseIfOldAndReplaceOnClient() {
ifOld = true;
- when(event.getOperation()).thenReturn(Operation.REPLACE);
- when(internalRegion.hasServerProxy()).thenReturn(true);
+ givenReplaceOnClient();
createInstance();
@@ -176,7 +608,7 @@ public class RegionMapPutTest {
}
@Test
- public void cacheWriteIsFaseIfGenerateCallbacksButNotDistributedEtc() {
+ public void cacheWriteIsFalseIfGenerateCallbacksButNotDistributedEtc() {
when(event.isGenerateCallbacks()).thenReturn(true);
createInstance();
@@ -230,6 +662,130 @@ public class RegionMapPutTest {
assertThat(instance.isCacheWrite()).isFalse();
}
+ @Test
+ public void basicPutPart2ToldClearDidNotOccur_ifPutDoneWithoutAClear()
throws Exception {
+ ifNew = true;
+ when(event.getOperation()).thenReturn(Operation.CREATE);
+
+ doPut();
+
+ verify(internalRegion, times(1)).basicPutPart2(any(), any(), anyBoolean(),
anyLong(),
+ eq(false));
+ }
+
+ @Test
+ public void basicPutPart2ToldClearDidOccur_ifPutDoneWithAClear() throws
Exception {
+ ifNew = true;
+ when(event.getOperation()).thenReturn(Operation.CREATE);
+ doThrow(RegionClearedException.class).when(event).putNewEntry(any(),
any());
+
+ doPut();
+
+ verify(internalRegion, times(1)).basicPutPart2(any(), any(), anyBoolean(),
anyLong(), eq(true));
+ }
+
+ @Test
+ public void lruUpdateCallbackCalled_ifPutDoneWithoutAClear() throws
Exception {
+ ifNew = true;
+ when(event.getOperation()).thenReturn(Operation.CREATE);
+
+ doPut();
+
+ verify(focusedRegionMap, times(1)).lruUpdateCallback();
+ }
+
+ @Test
+ public void lruUpdateCallbackNotCalled_ifPutDoneWithAClear() throws
Exception {
+ ifNew = true;
+ when(event.getOperation()).thenReturn(Operation.CREATE);
+ doThrow(RegionClearedException.class).when(event).putNewEntry(any(),
any());
+
+ doPut();
+
+ verify(focusedRegionMap, never()).lruUpdateCallback();
+ }
+
+ @Test
+ public void lruEnryCreateCalled_ifCreateDoneWithoutAClear() throws Exception
{
+ ifNew = true;
+ when(event.getOperation()).thenReturn(Operation.CREATE);
+
+ doPut();
+
+ verify(focusedRegionMap, times(1)).lruEntryCreate(createdRegionEntry);
+ }
+
+ @Test
+ public void lruEnryCreateNotCalled_ifCreateDoneWithAClear() throws Exception
{
+ ifNew = true;
+ when(event.getOperation()).thenReturn(Operation.CREATE);
+ doThrow(RegionClearedException.class).when(event).putNewEntry(any(),
any());
+
+ doPut();
+
+ verify(focusedRegionMap, never()).lruEntryCreate(createdRegionEntry);
+ }
+
+ @Test
+ public void lruEnryUpdateCalled_ifUpdateDoneWithoutAClear() throws Exception
{
+ ifOld = true;
+ RegionEntry existingRegionEntry = mock(RegionEntry.class);
+ when(focusedRegionMap.getEntry(event)).thenReturn(existingRegionEntry);
+
+ doPut();
+
+ verify(focusedRegionMap, times(1)).lruEntryUpdate(existingRegionEntry);
+ }
+
+ @Test
+ public void lruEnryUpdateNotCalled_ifUpdateDoneWithAClear() throws Exception
{
+ ifOld = true;
+ RegionEntry existingRegionEntry = mock(RegionEntry.class);
+ when(focusedRegionMap.getEntry(event)).thenReturn(existingRegionEntry);
+ doThrow(RegionClearedException.class).when(event).putExistingEntry(any(),
any(), anyBoolean(),
+ any());
+
+ doPut();
+
+ verify(focusedRegionMap, never()).lruEntryUpdate(existingRegionEntry);
+ }
+
+ @Test
+ public void putThrows_ifCreateDoneWithConcurrentCacheModificationException()
throws Exception {
+ ifNew = true;
+ when(event.getOperation()).thenReturn(Operation.CREATE);
+
doThrow(ConcurrentCacheModificationException.class).when(event).putNewEntry(any(),
any());
+
+ assertThatThrownBy(() ->
doPut()).isInstanceOf(ConcurrentCacheModificationException.class);
+
+ verify(event, times(1)).getVersionTag();
+ }
+
+ @Test
+ public void
putInvokesNotifyTimestampsToGateways_ifCreateDoneWithConcurrentCacheModificationException()
+ throws Exception {
+ ifNew = true;
+ when(event.getOperation()).thenReturn(Operation.CREATE);
+
doThrow(ConcurrentCacheModificationException.class).when(event).putNewEntry(any(),
any());
+ VersionTag versionTag = mock(VersionTag.class);
+ when(versionTag.isTimeStampUpdated()).thenReturn(true);
+ when(event.getVersionTag()).thenReturn(versionTag);
+
+ assertThatThrownBy(() ->
doPut()).isInstanceOf(ConcurrentCacheModificationException.class);
+
+ verify(internalRegion, times(1)).notifyTimestampsToGateways(same(event));
+ }
+
+ @Test
+ public void putThrows_ifLruUpdateCallbackThrowsDiskAccessException() throws
Exception {
+ ifNew = true;
+ when(event.getOperation()).thenReturn(Operation.CREATE);
+
doThrow(DiskAccessException.class).when(focusedRegionMap).lruUpdateCallback();
+
+ assertThatThrownBy(() -> doPut()).isInstanceOf(DiskAccessException.class);
+
+ verify(internalRegion, times(1)).handleDiskAccessException(any());
+ }
@Test
public void createOnEmptyMapAddsEntry() throws Exception {
@@ -238,8 +794,8 @@ public class RegionMapPutTest {
RegionEntry result = doPut();
- assertThat(result).isSameAs(regionEntry);
- verify(event, times(1)).putNewEntry(internalRegion, regionEntry);
+ assertThat(result).isSameAs(createdRegionEntry);
+ verify(event, times(1)).putNewEntry(internalRegion, createdRegionEntry);
verify(internalRegion, times(1)).basicPutPart2(eq(event), eq(result),
eq(true), anyLong(),
eq(false));
verify(internalRegion, times(1)).basicPutPart3(eq(event), eq(result),
eq(true), anyLong(),
@@ -247,6 +803,26 @@ public class RegionMapPutTest {
}
@Test
+ public void putWithTombstoneNewValue_callsBasicPutPart3WithFalse() {
+ when(event.basicGetNewValue()).thenReturn(Token.TOMBSTONE);
+
+ doPut();
+
+ verify(internalRegion, times(1)).basicPutPart3(any(), any(), anyBoolean(),
anyLong(), eq(false),
+ anyBoolean(), anyBoolean(), any(), anyBoolean());
+ }
+
+ @Test
+ public void putWithNonTombstoneNewValue_callsBasicPutPart3WithTrue() {
+ when(event.basicGetNewValue()).thenReturn("newValue");
+
+ doPut();
+
+ verify(internalRegion, times(1)).basicPutPart3(any(), any(), anyBoolean(),
anyLong(), eq(true),
+ anyBoolean(), anyBoolean(), any(), anyBoolean());
+ }
+
+ @Test
public void putOnEmptyMapAddsEntry() throws Exception {
ifNew = false;
ifOld = false;
@@ -254,8 +830,8 @@ public class RegionMapPutTest {
RegionEntry result = doPut();
- assertThat(result).isSameAs(regionEntry);
- verify(event, times(1)).putNewEntry(internalRegion, regionEntry);
+ assertThat(result).isSameAs(createdRegionEntry);
+ verify(event, times(1)).putNewEntry(internalRegion, createdRegionEntry);
verify(internalRegion, times(1)).basicPutPart2(eq(event), eq(result),
eq(true), anyLong(),
eq(false));
verify(internalRegion, times(1)).basicPutPart3(eq(event), eq(result),
eq(true), anyLong(),
@@ -298,7 +874,7 @@ public class RegionMapPutTest {
public void createOnEntryReturnedFromPutIfAbsentDoesNothing() throws
RegionClearedException {
ifNew = true;
when(focusedRegionMap.getEntry(event)).thenReturn(mock(RegionEntry.class));
- when(focusedRegionMap.putEntryIfAbsent(event.getKey(), regionEntry))
+ when(focusedRegionMap.putEntryIfAbsent(event.getKey(), createdRegionEntry))
.thenReturn(mock(RegionEntry.class));
when(event.getOperation()).thenReturn(Operation.CREATE);
@@ -318,14 +894,14 @@ public class RegionMapPutTest {
ifNew = true;
RegionEntry existingRegionEntry = mock(RegionEntry.class);
when(existingRegionEntry.isRemovedPhase2()).thenReturn(true);
- when(focusedRegionMap.putEntryIfAbsent(event.getKey(), regionEntry))
+ when(focusedRegionMap.putEntryIfAbsent(event.getKey(), createdRegionEntry))
.thenReturn(existingRegionEntry).thenReturn(null);
when(event.getOperation()).thenReturn(Operation.CREATE);
RegionEntry result = doPut();
- assertThat(result).isSameAs(regionEntry);
- verify(event, times(1)).putNewEntry(internalRegion, regionEntry);
+ assertThat(result).isSameAs(createdRegionEntry);
+ verify(event, times(1)).putNewEntry(internalRegion, createdRegionEntry);
verify(internalRegion, times(1)).basicPutPart2(eq(event), eq(result),
eq(true), anyLong(),
eq(false));
verify(internalRegion, times(1)).basicPutPart3(eq(event), eq(result),
eq(true), anyLong(),
@@ -371,4 +947,44 @@ public class RegionMapPutTest {
eq(true), eq(ifNew), eq(ifOld), eq(expectedOldValue),
eq(requireOldValue));
}
+ private void givenAnOperationThatDoesNotGuaranteeOldValue() {
+ when(event.getOperation()).thenReturn(Operation.UPDATE);
+ }
+
+ private void givenAnOperationThatGuaranteesOldValue() {
+ when(event.getOperation()).thenReturn(Operation.PUT_IF_ABSENT);
+ }
+
+ private void givenPutNeedsToDoCacheWrite() {
+ when(event.isGenerateCallbacks()).thenReturn(true);
+ when(internalRegion.getScope()).thenReturn(Scope.DISTRIBUTED_ACK);
+ }
+
+ private void givenPutDoesNotNeedToDoCacheWrite() {
+ when(event.isGenerateCallbacks()).thenReturn(false);
+ when(internalRegion.getScope()).thenReturn(Scope.DISTRIBUTED_ACK);
+ }
+
+ private void givenExistingRegionEntry() {
+ when(focusedRegionMap.getEntry(event)).thenReturn(existingRegionEntry);
+ }
+
+ private void givenReplaceOnClient() {
+ when(event.getOperation()).thenReturn(Operation.REPLACE);
+ when(internalRegion.hasServerProxy()).thenReturn(true);
+ }
+
+ private void givenReplaceOnPeer() {
+ when(event.getOperation()).thenReturn(Operation.REPLACE);
+ when(internalRegion.hasServerProxy()).thenReturn(false);
+ }
+
+ private void givenThatRunWhileEvictionDisabledCallsItsRunnable() {
+ doAnswer(invocation -> {
+ Runnable runnable = invocation.getArgument(0);
+ runnable.run();
+ return null;
+ }).when(focusedRegionMap).runWhileEvictionDisabled(any());
+ }
+
}
--
To stop receiving notification emails like this one, please contact
[email protected].