This is an automated email from the ASF dual-hosted git repository.

eshu11 pushed a commit to branch support/1.15
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/support/1.15 by this push:
     new 34e15feb97 GEODE-10294: Compare invalid token during putIfAbsent 
retry. (#7738)
34e15feb97 is described below

commit 34e15feb97b0aa932dae6c41e5e8a01332522db1
Author: Eric Shu <[email protected]>
AuthorDate: Wed Jun 1 11:47:59 2022 -0700

    GEODE-10294: Compare invalid token during putIfAbsent retry. (#7738)
    
     * During putIfAbsent retry, comparing invalid token value when
       putIfAbsent of a null value.
     * Do not make putIfAbsent event to update event if current
       entry value is null or invalidate and is a retried event.
    
    (cherry picked from commit ea48e7f7c0e8f272957377030ab28f7f87da8eac)
---
 .../cache/RetryPutIfAbsentIntegrationTest.java     | 99 +++++++++++++---------
 .../geode/internal/cache/map/RegionMapPut.java     | 20 ++++-
 .../geode/internal/cache/map/RegionMapPutTest.java | 17 +++-
 3 files changed, 88 insertions(+), 48 deletions(-)

diff --git 
a/geode-core/src/integrationTest/java/org/apache/geode/cache/RetryPutIfAbsentIntegrationTest.java
 
b/geode-core/src/integrationTest/java/org/apache/geode/cache/RetryPutIfAbsentIntegrationTest.java
index f79c2d2972..255eee9401 100644
--- 
a/geode-core/src/integrationTest/java/org/apache/geode/cache/RetryPutIfAbsentIntegrationTest.java
+++ 
b/geode-core/src/integrationTest/java/org/apache/geode/cache/RetryPutIfAbsentIntegrationTest.java
@@ -14,17 +14,14 @@
  */
 package org.apache.geode.cache;
 
-import static org.apache.geode.internal.Assert.assertTrue;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
+import static org.assertj.core.api.Assertions.assertThat;
 
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 import org.apache.geode.cache.query.CacheUtils;
+import org.apache.geode.cache.util.CacheListenerAdapter;
 import 
org.apache.geode.distributed.internal.membership.InternalDistributedMember;
 import org.apache.geode.internal.cache.EventID;
 import org.apache.geode.internal.cache.EventIDHolder;
@@ -32,55 +29,75 @@ import org.apache.geode.internal.cache.LocalRegion;
 import org.apache.geode.internal.cache.VMCachedDeserializable;
 import org.apache.geode.internal.cache.tier.sockets.ClientProxyMembershipID;
 
-public class RetryPutIfAbsentIntegrationTest {
+class RetryPutIfAbsentIntegrationTest {
 
-  Cache cache;
+  private Cache cache;
+  private LocalRegion myRegion;
+  private final ClientProxyMembershipID id =
+      new ClientProxyMembershipID(new InternalDistributedMember("localhost", 
1));
+  private final EventIDHolder clientEvent =
+      new EventIDHolder(new EventID(new byte[] {1, 2, 3, 4, 5}, 1, 1));
+  private final String key = "key";
+  private int updateCount;
 
-  @Rule
-  public ExpectedException expectedException = ExpectedException.none();
+  @Test
+  void duplicatePutIfAbsentIsAccepted() {
+    myRegion = (LocalRegion) 
cache.createRegionFactory(RegionShortcut.REPLICATE)
+        .setConcurrencyChecksEnabled(true).create("myRegion");
+
+    clientEvent.setRegion(myRegion);
+    byte[] valueBytes = new VMCachedDeserializable("myValue", 
7).getSerializedValue();
+    Object oldValue =
+        myRegion.basicBridgePutIfAbsent(key, valueBytes, true, null, id, true, 
clientEvent);
+    assertThat(oldValue).isNull();
+    assertThat(myRegion.containsKey(key)).isTrue();
+
+    myRegion.getEventTracker().clear();
+
+    clientEvent.setPossibleDuplicate(true);
+    clientEvent.setOperation(Operation.PUT_IF_ABSENT);
+    assertThat(myRegion.getEventTracker().hasSeenEvent(clientEvent)).isFalse();
+
+    oldValue = myRegion.basicBridgePutIfAbsent(key, valueBytes, true, null, 
id, true, clientEvent);
+    assertThat(oldValue).isNull();
+  }
 
   @Test
-  public void duplicatePutIfAbsentIsAccepted() {
-    final String key = "mykey";
-    final String value = "myvalue";
-
-    LocalRegion myregion =
-        (LocalRegion) 
CacheUtils.getCache().createRegionFactory(RegionShortcut.REPLICATE)
-            .setConcurrencyChecksEnabled(true).create("myregion");
-
-    ClientProxyMembershipID id =
-        new ClientProxyMembershipID(new InternalDistributedMember("localhost", 
1));
-    EventIDHolder clientEvent = new EventIDHolder(new EventID(new byte[] {1, 
2, 3, 4, 5}, 1, 1));
-    clientEvent.setRegion(myregion);
-    byte[] valueBytes = new VMCachedDeserializable("myvalue", 
7).getSerializedValue();
-    System.out.println("first putIfAbsent");
+  void duplicatePutIfAbsentOfNullValueDoesNotInvokeAfterUpdateListener() {
+    myRegion = (LocalRegion) 
cache.createRegionFactory(RegionShortcut.REPLICATE)
+        .setConcurrencyChecksEnabled(true)
+        .addCacheListener(new CacheListenerAdapter<Object, Object>() {
+          @Override
+          public void afterUpdate(EntryEvent<Object, Object> event) {
+            ++updateCount;
+          }
+        }).create("myRegion");
+
+    clientEvent.setRegion(myRegion);
     Object oldValue =
-        myregion.basicBridgePutIfAbsent("mykey", valueBytes, true, null, id, 
true, clientEvent);
-    assertEquals(null, oldValue);
-    assertTrue(myregion.containsKey(key));
+        myRegion.basicBridgePutIfAbsent(key, null, true, null, id, true, 
clientEvent);
+    assertThat(oldValue).isNull();
+    assertThat(myRegion.containsKey(key)).isTrue();
 
-    myregion.getEventTracker().clear();
+    myRegion.getEventTracker().clear();
 
-    clientEvent = new EventIDHolder(new EventID(new byte[] {1, 2, 3, 4, 5}, 1, 
1));
-    clientEvent.setRegion(myregion);
     clientEvent.setPossibleDuplicate(true);
     clientEvent.setOperation(Operation.PUT_IF_ABSENT);
-    assertFalse(myregion.getEventTracker().hasSeenEvent(clientEvent));
+    assertThat(myRegion.getEventTracker().hasSeenEvent(clientEvent)).isFalse();
 
-    System.out.println("second putIfAbsent");
-    oldValue =
-        myregion.basicBridgePutIfAbsent("mykey", valueBytes, true, null, id, 
true, clientEvent);
-    assertEquals(null, oldValue);
+    oldValue = myRegion.basicBridgePutIfAbsent(key, null, true, null, id, 
true, clientEvent);
+    assertThat(oldValue).isNull();
+    assertThat(updateCount).isEqualTo(0);
   }
 
-  @Before
-  public void setUp() throws Exception {
+  @BeforeEach
+  void setUp() {
     CacheUtils.startCache();
     cache = CacheUtils.getCache();
   }
 
-  @After
-  public void tearDown() throws Exception {
+  @AfterEach
+  void tearDown() {
     CacheUtils.closeCache();
   }
 
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 e0b62a5976..545d35885f 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
@@ -235,7 +235,8 @@ public class RegionMapPut extends AbstractRegionMapPut {
     final EntryEventImpl event = getEvent();
     if (getOwner().isInitialized() && isCacheWrite()) {
       if (!isReplaceOnClient()) {
-        if (getRegionEntry().isDestroyedOrRemoved()) {
+        if (getRegionEntry().isDestroyedOrRemoved()
+            || (getRegionEntry().isInvalid() && event.getOperation() == 
Operation.PUT_IF_ABSENT)) {
           event.makeCreate();
         } else {
           event.makeUpdate();
@@ -343,6 +344,9 @@ public class RegionMapPut extends AbstractRegionMapPut {
     if (isReplaceOnClient()) {
       return true;
     }
+    if (getRegionEntry().isInvalid() && getEvent().getOperation() == 
Operation.PUT_IF_ABSENT) {
+      return false;
+    }
     return !getRegionEntry().isRemoved();
   }
 
@@ -409,9 +413,7 @@ public class RegionMapPut extends AbstractRegionMapPut {
             event.isPossibleDuplicate()) {
           Object retainedValue = getRegionEntry().getValueRetain(getOwner());
           try {
-            if (ValueComparisonHelper.checkEquals(retainedValue,
-                getEvent().getRawNewValue(),
-                isCompressedOffHeap(event), getOwner().getCache())) {
+            if (isSameValueAlreadyInCacheForPutIfAbsent(retainedValue)) {
               if (logger.isDebugEnabled()) {
                 logger.debug("retried putIfAbsent found same value already in 
cache "
                     + "- allowing the operation.  entry={}; event={}", 
getRegionEntry(),
@@ -430,6 +432,16 @@ public class RegionMapPut extends AbstractRegionMapPut {
     return true;
   }
 
+  private boolean isSameValueAlreadyInCacheForPutIfAbsent(Object 
retainedValue) {
+    Object rawNewValue = getEvent().getRawNewValue();
+    if (Token.isInvalid(retainedValue)) {
+      return rawNewValue == null || Token.isInvalid(rawNewValue);
+    }
+
+    return ValueComparisonHelper.checkEquals(retainedValue, rawNewValue,
+        isCompressedOffHeap(getEvent()), getOwner().getCache());
+  }
+
 
   private boolean isCompressedOffHeap(EntryEventImpl event) {
     return event.getRegion().getAttributes().getOffHeap()
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 7fceaeb43a..8b3d77e062 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
@@ -137,7 +137,7 @@ public class RegionMapPutTest {
   public void doesNotSetEventOldValueIfRetriedPutIfAbsentOperation() {
     final byte[] bytes = new byte[] {1, 2, 3, 4, 5};
     givenExistingRegionEntry();
-    when(existingRegionEntry.getValue()).thenReturn(bytes);
+    when(existingRegionEntry.getValueRetain(internalRegion)).thenReturn(bytes);
     when(internalRegion.getConcurrencyChecksEnabled()).thenReturn(true);
     givenPutIfAbsentOperation(bytes); // duplicate operation
     doPut();
@@ -145,11 +145,22 @@ public class RegionMapPutTest {
     assertThat(instance.isOverwritePutIfAbsent()).isTrue();
   }
 
+  @Test
+  public void doesNotSetEventOldValueIfRetriedPutIfAbsentOperationOfNull() {
+    givenExistingRegionEntry();
+    
when(existingRegionEntry.getValueRetain(internalRegion)).thenReturn(Token.INVALID);
+    when(internalRegion.getConcurrencyChecksEnabled()).thenReturn(true);
+    givenPutIfAbsentOperation(null); // duplicate operation
+    doPut();
+    verify(event).setOldValue(null, true);
+    assertThat(instance.isOverwritePutIfAbsent()).isTrue();
+  }
+
   @Test
   public void 
overWritePutIfAbsentIsTrueIfRetriedPutIfAbsentOperationHavingValidVersionTag() {
     final byte[] bytes = new byte[] {1, 2, 3, 4, 5};
     givenExistingRegionEntry();
-    when(existingRegionEntry.getValue()).thenReturn(bytes);
+    when(existingRegionEntry.getValueRetain(internalRegion)).thenReturn(bytes);
     when(internalRegion.getConcurrencyChecksEnabled()).thenReturn(true);
     givenPutIfAbsentOperation(bytes); // duplicate operation
     when(event.hasValidVersionTag()).thenReturn(true);
@@ -162,7 +173,7 @@ public class RegionMapPutTest {
 
   private void givenPutIfAbsentOperation(byte[] bytes) {
     when(event.isPossibleDuplicate()).thenReturn(true);
-    when(event.basicGetNewValue()).thenReturn(bytes);
+    when(event.getRawNewValue()).thenReturn(bytes);
     when(event.getOperation()).thenReturn(Operation.PUT_IF_ABSENT);
     when(event.hasValidVersionTag()).thenReturn(false);
     ifNew = true;

Reply via email to