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

ringles 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 f70700e  feature/GEODE-9902: Modify ZUNIONSTORE and ZINTERSTORE 
storing methods (#7219)
f70700e is described below

commit f70700ed8702df331facb9131ce9e2c68ae4f29c
Author: Kris10 <[email protected]>
AuthorDate: Thu Jan 6 06:35:01 2022 -0800

    feature/GEODE-9902: Modify ZUNIONSTORE and ZINTERSTORE storing methods 
(#7219)
    
    GEODE-9902: Modify ZUNIONSTORE and ZINTERSTORE storing methods
---
 .../AbstractZInterStoreIntegrationTest.java        | 14 ++++
 .../executor/sortedset/ZInterStoreExecutor.java    |  5 +-
 .../executor/sortedset/ZUnionStoreExecutor.java    |  5 +-
 .../redis/internal/data/AbstractRedisData.java     | 10 +++
 .../geode/redis/internal/data/RedisSortedSet.java  | 94 +++++++++++++++-------
 .../geode/redis/internal/data/delta/DeltaType.java |  1 +
 .../data/delta/ReplaceByteArrayDoublePairs.java    | 62 ++++++++++++++
 .../redis/internal/data/RedisSortedSetTest.java    | 56 +++++++++++++
 8 files changed, 214 insertions(+), 33 deletions(-)

diff --git 
a/geode-for-redis/src/integrationTest/java/org/apache/geode/redis/internal/commands/executor/sortedset/AbstractZInterStoreIntegrationTest.java
 
b/geode-for-redis/src/integrationTest/java/org/apache/geode/redis/internal/commands/executor/sortedset/AbstractZInterStoreIntegrationTest.java
index 3ce1959..7a07499 100755
--- 
a/geode-for-redis/src/integrationTest/java/org/apache/geode/redis/internal/commands/executor/sortedset/AbstractZInterStoreIntegrationTest.java
+++ 
b/geode-for-redis/src/integrationTest/java/org/apache/geode/redis/internal/commands/executor/sortedset/AbstractZInterStoreIntegrationTest.java
@@ -220,6 +220,20 @@ public abstract class AbstractZInterStoreIntegrationTest 
implements RedisIntegra
   }
 
   @Test
+  public void shouldOverwriteDestinationKey_givenDestinationExists() {
+    Set<Tuple> expectedResults = new LinkedHashSet<>();
+    expectedResults.add(new Tuple("key1Member", 1.0));
+
+    jedis.zadd(NEW_SET, 1.0, "newSetMember1");
+    jedis.zadd(NEW_SET, 2.0, "newSetMember2");
+    jedis.zadd(KEY1, 1.0, "key1Member");
+
+    assertThat(jedis.zinterstore(NEW_SET, KEY1)).isEqualTo(1L);
+    Set<Tuple> results = jedis.zrangeWithScores(NEW_SET, 0L, 1L);
+    assertThat(results).containsExactlyInAnyOrderElementsOf(expectedResults);
+  }
+
+  @Test
   public void shouldStoreIntersection_givenWeightOfOne_andOneRedisSortedSet() {
     Map<String, Double> scores = buildMapOfMembersAndScores();
     Set<Tuple> expectedResults = convertToTuples(scores, (ignore, value) -> 
value);
diff --git 
a/geode-for-redis/src/main/java/org/apache/geode/redis/internal/commands/executor/sortedset/ZInterStoreExecutor.java
 
b/geode-for-redis/src/main/java/org/apache/geode/redis/internal/commands/executor/sortedset/ZInterStoreExecutor.java
index e21fae3..0ddff26 100644
--- 
a/geode-for-redis/src/main/java/org/apache/geode/redis/internal/commands/executor/sortedset/ZInterStoreExecutor.java
+++ 
b/geode-for-redis/src/main/java/org/apache/geode/redis/internal/commands/executor/sortedset/ZInterStoreExecutor.java
@@ -16,13 +16,13 @@ package 
org.apache.geode.redis.internal.commands.executor.sortedset;
 
 
 import static 
org.apache.geode.redis.internal.RedisConstants.ERROR_KEY_REQUIRED_ZINTERSTORE;
+import static org.apache.geode.redis.internal.data.RedisSortedSet.zinterstore;
 
 import java.util.List;
 
 import org.apache.geode.redis.internal.commands.Command;
 import org.apache.geode.redis.internal.commands.executor.RedisResponse;
 import org.apache.geode.redis.internal.data.RedisKey;
-import org.apache.geode.redis.internal.data.RedisSortedSet;
 import org.apache.geode.redis.internal.netty.ExecutionHandlerContext;
 import org.apache.geode.redis.internal.services.RegionProvider;
 
@@ -35,8 +35,7 @@ public class ZInterStoreExecutor extends ZStoreExecutor {
     List<RedisKey> keysToLock = getKeysToLock(regionProvider, key, keyWeights);
 
     return context.lockedExecute(key, keysToLock,
-        () -> new RedisSortedSet(0))
-        .zinterstore(regionProvider, key, keyWeights, aggregator);
+        () -> zinterstore(regionProvider, key, keyWeights, aggregator));
   }
 
   @Override
diff --git 
a/geode-for-redis/src/main/java/org/apache/geode/redis/internal/commands/executor/sortedset/ZUnionStoreExecutor.java
 
b/geode-for-redis/src/main/java/org/apache/geode/redis/internal/commands/executor/sortedset/ZUnionStoreExecutor.java
index 7214cfa..6d30155 100644
--- 
a/geode-for-redis/src/main/java/org/apache/geode/redis/internal/commands/executor/sortedset/ZUnionStoreExecutor.java
+++ 
b/geode-for-redis/src/main/java/org/apache/geode/redis/internal/commands/executor/sortedset/ZUnionStoreExecutor.java
@@ -15,13 +15,13 @@
 package org.apache.geode.redis.internal.commands.executor.sortedset;
 
 import static 
org.apache.geode.redis.internal.RedisConstants.ERROR_KEY_REQUIRED_ZUNIONSTORE;
+import static org.apache.geode.redis.internal.data.RedisSortedSet.zunionstore;
 
 import java.util.List;
 
 import org.apache.geode.redis.internal.commands.Command;
 import org.apache.geode.redis.internal.commands.executor.RedisResponse;
 import org.apache.geode.redis.internal.data.RedisKey;
-import org.apache.geode.redis.internal.data.RedisSortedSet;
 import org.apache.geode.redis.internal.netty.ExecutionHandlerContext;
 import org.apache.geode.redis.internal.services.RegionProvider;
 
@@ -34,8 +34,7 @@ public class ZUnionStoreExecutor extends ZStoreExecutor {
     List<RedisKey> keysToLock = getKeysToLock(regionProvider, key, keyWeights);
 
     return context.lockedExecute(key, keysToLock,
-        () -> new RedisSortedSet(0))
-        .zunionstore(regionProvider, key, keyWeights, aggregator);
+        () -> zunionstore(regionProvider, key, keyWeights, aggregator));
   }
 
   @Override
diff --git 
a/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/AbstractRedisData.java
 
b/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/AbstractRedisData.java
index 3785784..349bcd7 100644
--- 
a/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/AbstractRedisData.java
+++ 
b/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/AbstractRedisData.java
@@ -25,6 +25,7 @@ import static 
org.apache.geode.redis.internal.data.delta.DeltaType.APPEND_BYTE_A
 import static 
org.apache.geode.redis.internal.data.delta.DeltaType.REMOVE_BYTE_ARRAYS;
 import static 
org.apache.geode.redis.internal.data.delta.DeltaType.REPLACE_BYTE_ARRAYS;
 import static 
org.apache.geode.redis.internal.data.delta.DeltaType.REPLACE_BYTE_ARRAY_AT_OFFSET;
+import static 
org.apache.geode.redis.internal.data.delta.DeltaType.REPLACE_BYTE_ARRAY_DOUBLE_PAIRS;
 import static 
org.apache.geode.redis.internal.data.delta.DeltaType.REPLACE_BYTE_AT_OFFSET;
 import static 
org.apache.geode.redis.internal.data.delta.DeltaType.SET_BYTE_ARRAY;
 import static 
org.apache.geode.redis.internal.data.delta.DeltaType.SET_BYTE_ARRAY_AND_TIMESTAMP;
@@ -54,6 +55,7 @@ import org.apache.geode.redis.internal.data.delta.DeltaInfo;
 import org.apache.geode.redis.internal.data.delta.DeltaType;
 import org.apache.geode.redis.internal.data.delta.RemoveByteArrays;
 import org.apache.geode.redis.internal.data.delta.ReplaceByteArrayAtOffset;
+import org.apache.geode.redis.internal.data.delta.ReplaceByteArrayDoublePairs;
 import org.apache.geode.redis.internal.data.delta.ReplaceByteArrays;
 import org.apache.geode.redis.internal.data.delta.ReplaceByteAtOffset;
 import org.apache.geode.redis.internal.data.delta.SetByteArray;
@@ -249,6 +251,9 @@ public abstract class AbstractRedisData implements 
RedisData {
       case REPLACE_BYTE_ARRAY_AT_OFFSET:
         ReplaceByteArrayAtOffset.deserializeFrom(in, this);
         break;
+      case REPLACE_BYTE_ARRAY_DOUBLE_PAIRS:
+        ReplaceByteArrayDoublePairs.deserializeFrom(in, this);
+        break;
       case REPLACE_BYTE_AT_OFFSET:
         ReplaceByteAtOffset.deserializeFrom(in, this);
         break;
@@ -295,6 +300,11 @@ public abstract class AbstractRedisData implements 
RedisData {
     throw new IllegalStateException("unexpected " + 
REPLACE_BYTE_ARRAY_AT_OFFSET);
   }
 
+  public void applyReplaceByteArrayDoublePairDelta(RedisSortedSet.MemberMap 
members,
+      RedisSortedSet.ScoreSet scoreSet) {
+    throw new IllegalStateException("unexpected " + 
REPLACE_BYTE_ARRAY_DOUBLE_PAIRS);
+  }
+
   public void applyReplaceByteAtOffsetDelta(int offset, byte bits) {
     throw new IllegalStateException("unexpected " + REPLACE_BYTE_AT_OFFSET);
   }
diff --git 
a/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/RedisSortedSet.java
 
b/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/RedisSortedSet.java
index 0af1040..114fd5f 100644
--- 
a/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/RedisSortedSet.java
+++ 
b/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/RedisSortedSet.java
@@ -58,6 +58,7 @@ import 
org.apache.geode.redis.internal.data.collections.OrderStatisticsTree;
 import 
org.apache.geode.redis.internal.data.collections.SizeableBytes2ObjectOpenCustomHashMapWithCursor;
 import org.apache.geode.redis.internal.data.delta.AddByteArrayDoublePairs;
 import org.apache.geode.redis.internal.data.delta.RemoveByteArrays;
+import org.apache.geode.redis.internal.data.delta.ReplaceByteArrayDoublePairs;
 import org.apache.geode.redis.internal.netty.Coder;
 import org.apache.geode.redis.internal.services.RegionProvider;
 
@@ -66,7 +67,7 @@ public class RedisSortedSet extends AbstractRedisData {
   private static final Logger logger = LogService.getLogger();
 
   private MemberMap members;
-  private final ScoreSet scoreSet = new ScoreSet();
+  private ScoreSet scoreSet = new ScoreSet();
 
   @Override
   public int getSizeInBytes() {
@@ -83,6 +84,11 @@ public class RedisSortedSet extends AbstractRedisData {
     }
   }
 
+  RedisSortedSet(MemberMap members, ScoreSet scoreSet) {
+    this.members = members;
+    this.scoreSet = scoreSet;
+  }
+
   public RedisSortedSet(int size) {
     this.members = new MemberMap(size);
   }
@@ -104,6 +110,13 @@ public class RedisSortedSet extends AbstractRedisData {
     memberAdd(bytes, score);
   }
 
+  @Override
+  public void applyReplaceByteArrayDoublePairDelta(MemberMap members, ScoreSet 
scoreSet) {
+    persistNoDelta();
+    this.members = members;
+    this.scoreSet = scoreSet;
+  }
+
   /**
    * Since GII (getInitialImage) can come in and call toData while other 
threads are modifying this
    * object, the striped executor will not protect toData. So any methods that 
modify "members"
@@ -274,16 +287,17 @@ public class RedisSortedSet extends AbstractRedisData {
     return Coder.doubleToBytes(score);
   }
 
-  public long zinterstore(RegionProvider regionProvider, RedisKey key, 
List<ZKeyWeight> keyWeights,
+  public static long zinterstore(RegionProvider regionProvider, RedisKey key,
+      List<ZKeyWeight> keyWeights,
       ZAggregator aggregator) {
     List<RedisSortedSet> sets = new ArrayList<>(keyWeights.size());
+
     for (ZKeyWeight keyWeight : keyWeights) {
       RedisSortedSet set =
           regionProvider.getTypedRedisData(REDIS_SORTED_SET, 
keyWeight.getKey(), false);
 
       if (set == NULL_REDIS_SORTED_SET) {
-        regionProvider.getLocalDataRegion().remove(key);
-        return 0;
+        return sortedSetOpStoreResult(regionProvider, key, new MemberMap(0), 
new ScoreSet());
       } else {
         sets.add(set);
       }
@@ -296,6 +310,8 @@ public class RedisSortedSet extends AbstractRedisData {
       }
     }
 
+    MemberMap interMembers = new MemberMap(smallestSet.getSortedSetSize());
+    ScoreSet interScores = new ScoreSet();
     for (byte[] member : smallestSet.members.keySet()) {
       boolean addToSet = true;
       double newScore;
@@ -323,18 +339,41 @@ public class RedisSortedSet extends AbstractRedisData {
           }
         }
       }
+
       if (addToSet) {
-        memberAdd(member, newScore);
+        OrderedSetEntry entry = new OrderedSetEntry(member, newScore);
+        interMembers.put(member, entry);
+        interScores.add(entry);
       }
     }
 
-    if (removeFromRegion()) {
-      regionProvider.getDataRegion().remove(key);
-    } else {
-      regionProvider.getLocalDataRegion().put(key, this);
+    return sortedSetOpStoreResult(regionProvider, key, interMembers, 
interScores);
+  }
+
+  @VisibleForTesting
+  static long sortedSetOpStoreResult(RegionProvider regionProvider, RedisKey 
destinationKey,
+      MemberMap interMembers, ScoreSet interScores) {
+    RedisSortedSet destinationSet =
+        regionProvider.getTypedRedisDataElseRemove(REDIS_SORTED_SET, 
destinationKey, false);
+
+    if (interMembers.isEmpty() || interScores.isEmpty()) {
+      if (destinationSet != null) {
+        regionProvider.getDataRegion().remove(destinationKey);
+      }
+      return 0;
     }
 
-    return getSortedSetSize();
+    if (destinationSet != null) {
+      destinationSet.persistNoDelta();
+      destinationSet.members = interMembers;
+      destinationSet.scoreSet = interScores;
+      destinationSet.storeChanges(regionProvider.getDataRegion(), 
destinationKey,
+          new ReplaceByteArrayDoublePairs(interMembers));
+    } else {
+      regionProvider.getDataRegion().put(destinationKey,
+          new RedisSortedSet(interMembers, interScores));
+    }
+    return interMembers.size();
   }
 
   public long zlexcount(SortedSetLexRangeOptions lexOptions) {
@@ -463,19 +502,30 @@ public class RedisSortedSet extends AbstractRedisData {
     return null;
   }
 
-  public long zunionstore(RegionProvider regionProvider, RedisKey key, 
List<ZKeyWeight> keyWeights,
+  public static long zunionstore(RegionProvider regionProvider, RedisKey key,
+      List<ZKeyWeight> keyWeights,
       ZAggregator aggregator) {
+    MemberMap unionMembers = new MemberMap(0);
+    ScoreSet unionScores = new ScoreSet();
+
     for (ZKeyWeight keyWeight : keyWeights) {
       RedisSortedSet set =
           regionProvider.getTypedRedisData(REDIS_SORTED_SET, 
keyWeight.getKey(), false);
       if (set == NULL_REDIS_SORTED_SET) {
         continue;
       }
+
       double weight = keyWeight.getWeight();
 
       for (AbstractOrderedSetEntry entry : set.members.values()) {
-        OrderedSetEntry existingValue = members.get(entry.getMember());
-        if (existingValue == null) {
+        OrderedSetEntry existingValue = unionMembers.get(entry.getMember());
+
+        if (existingValue != null) {
+          unionScores.remove(existingValue);
+          
existingValue.updateScore(aggregator.getFunction().apply(existingValue.getScore(),
+              entry.getScore() * weight));
+          unionScores.add(existingValue);
+        } else {
           double score;
           // Redis math and Java math are different when handling infinity. 
Specifically:
           // Java: INFINITY * 0 = NaN
@@ -492,23 +542,13 @@ public class RedisSortedSet extends AbstractRedisData {
               score = newScore;
             }
           }
-          members.put(entry.getMember(), new 
OrderedSetEntry(entry.getMember(), score));
-          continue;
+          OrderedSetEntry newUnion = new OrderedSetEntry(entry.getMember(), 
score);
+          unionMembers.put(entry.getMember(), newUnion);
+          unionScores.add(newUnion);
         }
-
-        
existingValue.updateScore(aggregator.getFunction().apply(existingValue.getScore(),
-            entry.getScore() * weight));
       }
     }
-
-    if (removeFromRegion()) {
-      regionProvider.getDataRegion().remove(key);
-    } else {
-      scoreSet.addAll(members.values());
-      regionProvider.getLocalDataRegion().put(key, this);
-    }
-
-    return getSortedSetSize();
+    return sortedSetOpStoreResult(regionProvider, key, unionMembers, 
unionScores);
   }
 
   private List<byte[]> zpop(Iterator<AbstractOrderedSetEntry> scoresIterator,
diff --git 
a/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/delta/DeltaType.java
 
b/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/delta/DeltaType.java
index 05bef52..c3fef85 100644
--- 
a/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/delta/DeltaType.java
+++ 
b/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/delta/DeltaType.java
@@ -24,6 +24,7 @@ public enum DeltaType {
   REMOVE_BYTE_ARRAYS,
   REPLACE_BYTE_ARRAYS,
   REPLACE_BYTE_ARRAY_AT_OFFSET,
+  REPLACE_BYTE_ARRAY_DOUBLE_PAIRS,
   REPLACE_BYTE_AT_OFFSET,
   SET_BYTE_ARRAY,
   SET_BYTE_ARRAY_AND_TIMESTAMP,
diff --git 
a/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/delta/ReplaceByteArrayDoublePairs.java
 
b/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/delta/ReplaceByteArrayDoublePairs.java
new file mode 100644
index 0000000..0b63096
--- /dev/null
+++ 
b/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/delta/ReplaceByteArrayDoublePairs.java
@@ -0,0 +1,62 @@
+/*
+ * 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.redis.internal.data.delta;
+
+import static org.apache.geode.DataSerializer.readByteArray;
+import static org.apache.geode.DataSerializer.readPrimitiveDouble;
+import static org.apache.geode.internal.InternalDataSerializer.readArrayLength;
+import static 
org.apache.geode.redis.internal.data.delta.DeltaType.REPLACE_BYTE_ARRAY_DOUBLE_PAIRS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+import org.apache.geode.DataSerializer;
+import org.apache.geode.internal.InternalDataSerializer;
+import org.apache.geode.redis.internal.data.AbstractRedisData;
+import org.apache.geode.redis.internal.data.RedisSortedSet;
+
+public class ReplaceByteArrayDoublePairs implements DeltaInfo {
+  private final RedisSortedSet.MemberMap members;
+
+  public ReplaceByteArrayDoublePairs(RedisSortedSet.MemberMap members) {
+    this.members = members;
+  }
+
+  public void serializeTo(DataOutput out) throws IOException {
+    DataSerializer.writeEnum(REPLACE_BYTE_ARRAY_DOUBLE_PAIRS, out);
+    InternalDataSerializer.writeArrayLength(members.size(), out);
+    for (byte[] member : members.keySet()) {
+      DataSerializer.writeByteArray(member, out);
+      DataSerializer.writePrimitiveDouble(members.get(member).getScore(), out);
+    }
+  }
+
+  public static void deserializeFrom(DataInput in, AbstractRedisData 
redisData) throws IOException {
+    int size = readArrayLength(in);
+    RedisSortedSet.MemberMap membersMap = new RedisSortedSet.MemberMap(size);
+    RedisSortedSet.ScoreSet scoreSet = new RedisSortedSet.ScoreSet();
+    while (size > 0) {
+      byte[] member = readByteArray(in);
+      double score = readPrimitiveDouble(in);
+      RedisSortedSet.OrderedSetEntry entry = new 
RedisSortedSet.OrderedSetEntry(member, score);
+      membersMap.put(member, entry);
+      scoreSet.add(entry);
+      size--;
+    }
+    redisData.applyReplaceByteArrayDoublePairDelta(membersMap, scoreSet);
+
+  }
+}
diff --git 
a/geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/RedisSortedSetTest.java
 
b/geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/RedisSortedSetTest.java
index 14601cf..0d20d15 100644
--- 
a/geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/RedisSortedSetTest.java
+++ 
b/geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/RedisSortedSetTest.java
@@ -17,8 +17,11 @@
 package org.apache.geode.redis.internal.data;
 
 import static java.util.Collections.singletonList;
+import static 
org.apache.geode.redis.internal.data.AbstractRedisData.NO_EXPIRATION;
+import static 
org.apache.geode.redis.internal.data.RedisDataType.REDIS_SORTED_SET;
 import static 
org.apache.geode.redis.internal.data.RedisSortedSet.OrderedSetEntry.ORDERED_SET_ENTRY_OVERHEAD;
 import static 
org.apache.geode.redis.internal.data.RedisSortedSet.REDIS_SORTED_SET_OVERHEAD;
+import static 
org.apache.geode.redis.internal.data.RedisSortedSet.sortedSetOpStoreResult;
 import static org.apache.geode.redis.internal.netty.Coder.stringToBytes;
 import static 
org.apache.geode.redis.internal.netty.StringBytesGlossary.GREATEST_MEMBER_NAME;
 import static 
org.apache.geode.redis.internal.netty.StringBytesGlossary.LEAST_MEMBER_NAME;
@@ -65,6 +68,7 @@ import 
org.apache.geode.redis.internal.commands.executor.sortedset.SortedSetRank
 import org.apache.geode.redis.internal.commands.executor.sortedset.ZAddOptions;
 import org.apache.geode.redis.internal.data.delta.RemoveByteArrays;
 import org.apache.geode.redis.internal.netty.Coder;
+import org.apache.geode.redis.internal.services.RegionProvider;
 import org.apache.geode.test.junit.runners.GeodeParamsRunner;
 
 @RunWith(GeodeParamsRunner.class)
@@ -153,6 +157,58 @@ public class RedisSortedSetTest {
     assertThat(sortedSet1.hasDelta()).isFalse();
   }
 
+  @Test
+  public void sortedSetOpStoreResult_stores_delta_that_is_stable() {
+    RegionProvider regionProvider = uncheckedCast(mock(RegionProvider.class));
+    Region<RedisKey, RedisData> dataRegion = uncheckedCast(mock(Region.class));
+
+    RedisSortedSet sortedSet1 = createRedisSortedSet("3.14159", "v1", 
"2.71828", "v2");
+    when(regionProvider.getTypedRedisDataElseRemove(REDIS_SORTED_SET, null, 
false))
+        .thenReturn(sortedSet1);
+    when(regionProvider.getDataRegion()).thenReturn(dataRegion);
+    when(dataRegion.put(any(), 
any())).thenAnswer(this::validateDeltaSerialization);
+
+    // Setting up for store operation
+    RedisSortedSet.MemberMap members = new RedisSortedSet.MemberMap(1);
+    RedisSortedSet.ScoreSet scores = new RedisSortedSet.ScoreSet();
+    byte[] member = new byte[] {4};
+    RedisSortedSet.OrderedSetEntry entry = new 
RedisSortedSet.OrderedSetEntry(member, 5);
+    members.put(member, entry);
+    scores.add(entry);
+
+    sortedSetOpStoreResult(regionProvider, null, members, scores);
+
+    verify(dataRegion).put(any(), any());
+    assertThat(sortedSet1.hasDelta()).isFalse();
+  }
+
+  @Test
+  public void sortedSetOpStoreResult_sets_expiration_time_to_zero() {
+    RegionProvider regionProvider = uncheckedCast(mock(RegionProvider.class));
+    Region<RedisKey, RedisData> dataRegion = uncheckedCast(mock(Region.class));
+
+    RedisSortedSet setDest = createRedisSortedSet("3.14159", "v1", "2.71828", 
"v2");
+    setDest.setExpirationTimestamp(dataRegion, null, 100);
+
+    when(regionProvider.getTypedRedisDataElseRemove(REDIS_SORTED_SET, null, 
false))
+        .thenReturn(setDest);
+    when(regionProvider.getDataRegion()).thenReturn(dataRegion);
+    when(dataRegion.put(any(), 
any())).thenAnswer(this::validateDeltaSerialization);
+
+    // Setting up for store operation
+    RedisSortedSet.MemberMap members = new RedisSortedSet.MemberMap(1);
+    RedisSortedSet.ScoreSet scores = new RedisSortedSet.ScoreSet();
+    byte[] member = new byte[] {4};
+    RedisSortedSet.OrderedSetEntry entry = new 
RedisSortedSet.OrderedSetEntry(member, 5);
+    members.put(member, entry);
+    scores.add(entry);
+
+    sortedSetOpStoreResult(regionProvider, null, members, scores);
+
+    assertThat(setDest.getExpirationTimestamp()).isEqualTo(NO_EXPIRATION);
+    assertThat(setDest.hasDelta()).isFalse();
+  }
+
   private Object validateDeltaSerialization(InvocationOnMock invocation) 
throws IOException {
     RedisSortedSet value = invocation.getArgument(1, RedisSortedSet.class);
     assertThat(value.hasDelta()).isTrue();

Reply via email to