GEODE-8786 redis info command hit miss ratios (#5875)

* GEODE-8786: fix hit/miss ratios in redis stats

- add enum for keyspace increment type
- remove clearall() method
- add tests for supported commands that do not update the stats
- use boolean to indicate if stats should be updated
- get the s*store command tests working
- add internal pttl to be called from the expire command to avoid updating the stats
- move the updateStats boolean up a level
- remove unused executors
- change s*store stats integrations tests to reflect behavior in native redis
- fix bitop test
- add INTERNAL command type
- fix supported commands dunit tests to allow for new internal commands
- changed tests to use delegate methods
- remove unecessary pubsub and connection tests. they don't have anything to do with key hits/misses
- remove unecessary getRedisString and getRedisHash methods. leaving only the method that takes a boolean for updating the stats

Co-authored-by: Ray Ingles <ringles@vmware.com>
Co-authored-by: john Hutchison <hutchisonjo@vmware.com>
diff --git a/geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/server/HitsMissesNativeRedisAcceptanceTest.java b/geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/server/HitsMissesNativeRedisAcceptanceTest.java
index 668a064..a50d8ae 100644
--- a/geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/server/HitsMissesNativeRedisAcceptanceTest.java
+++ b/geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/server/HitsMissesNativeRedisAcceptanceTest.java
@@ -28,10 +28,4 @@
   public int getPort() {
     return redis.getPort();
   }
-
-  @Override
-  void resetStats() {
-    jedis.configResetStat();
-  }
-
 }
diff --git a/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/RedisStatsIntegrationTest.java b/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/RedisStatsIntegrationTest.java
index 849f6b7..a8ecd26 100644
--- a/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/RedisStatsIntegrationTest.java
+++ b/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/RedisStatsIntegrationTest.java
@@ -121,18 +121,16 @@
         .isEqualTo(preTestKeySpaceMisses + 1);
   }
 
-  // TODO: Set doesn't work like native Redis!
   @Test
   public void keyspaceStats_setCommand_existingKey() {
     jedis.set(EXISTING_STRING_KEY, "New_Value");
 
     assertThat(redisStats.getKeyspaceHits())
-        .isEqualTo(preTestKeySpaceHits + 1);
+        .isEqualTo(preTestKeySpaceHits);
     assertThat(redisStats.getKeyspaceMisses())
         .isEqualTo(preTestKeySpaceMisses);
   }
 
-  // TODO: Set doesn't work like native Redis!
   @Test
   public void keyspaceStats_setCommand_nonexistentKey() {
     jedis.set("Another_Key", "Another_Value");
@@ -140,7 +138,7 @@
     assertThat(redisStats.getKeyspaceHits())
         .isEqualTo(preTestKeySpaceHits);
     assertThat(redisStats.getKeyspaceMisses())
-        .isEqualTo(preTestKeySpaceMisses + 1);
+        .isEqualTo(preTestKeySpaceMisses);
   }
 
   @Test
@@ -235,10 +233,10 @@
 
   @Test
   public void keyspaceStats_bitopCommand() {
-    jedis.bitop(BitOP.AND, EXISTING_STRING_KEY, EXISTING_STRING_KEY, "Nonexistent_Key");
+    jedis.bitop(BitOP.AND, "Destination_Key", EXISTING_STRING_KEY, "Nonexistent_Key");
 
     assertThat(redisStats.getKeyspaceHits())
-        .isEqualTo(preTestKeySpaceHits + 2);
+        .isEqualTo(preTestKeySpaceHits + 1);
     assertThat(redisStats.getKeyspaceMisses())
         .isEqualTo(preTestKeySpaceMisses + 1);
   }
@@ -332,9 +330,37 @@
         "Nonexistent_Set");
 
     assertThat(redisStats.getKeyspaceHits())
-        .isEqualTo(preTestKeySpaceHits + 2);
+        .isEqualTo(preTestKeySpaceHits);
     assertThat(redisStats.getKeyspaceMisses())
-        .isEqualTo(preTestKeySpaceMisses + 1);
+        .isEqualTo(preTestKeySpaceMisses);
+  }
+
+  @Test
+  public void keyspaceStats_sdiffstoreCommand_existingKey() {
+    jedis.sdiffstore(
+        "New_Set",
+        EXISTING_SET_KEY_1,
+        EXISTING_SET_KEY_2,
+        "Nonexistent_Set");
+
+    assertThat(redisStats.getKeyspaceHits())
+        .isEqualTo(preTestKeySpaceHits);
+    assertThat(redisStats.getKeyspaceMisses())
+        .isEqualTo(preTestKeySpaceMisses);
+  }
+
+  @Test
+  public void keyspaceStats_sinterstoreCommand_existingKey() {
+    jedis.sinterstore(
+        "New_Set",
+        EXISTING_SET_KEY_1,
+        EXISTING_SET_KEY_2,
+        "Nonexistent_Set");
+
+    assertThat(redisStats.getKeyspaceHits())
+        .isEqualTo(preTestKeySpaceHits);
+    assertThat(redisStats.getKeyspaceMisses())
+        .isEqualTo(preTestKeySpaceMisses);
   }
 
   @Test
diff --git a/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/executor/server/AbstractHitsMissesIntegrationTest.java b/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/executor/server/AbstractHitsMissesIntegrationTest.java
index 9142b5b..e8d2d6e 100644
--- a/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/executor/server/AbstractHitsMissesIntegrationTest.java
+++ b/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/executor/server/AbstractHitsMissesIntegrationTest.java
@@ -17,6 +17,7 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 
+import java.time.Duration;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.function.BiConsumer;
@@ -41,14 +42,10 @@
   private static final int REDIS_CLIENT_TIMEOUT =
       Math.toIntExact(GeodeAwaitility.getTimeout().toMillis());
 
-  abstract void resetStats();
-
   @Before
   public void classSetup() {
     jedis = new Jedis("localhost", getPort(), REDIS_CLIENT_TIMEOUT);
 
-    resetStats();
-
     jedis.set("string", "yarn");
     jedis.sadd("set", "cotton");
     jedis.hset("hash", "green", "eggs");
@@ -82,6 +79,11 @@
     runCommandAndAssertHitsAndMisses("string", k -> jedis.pttl(k));
   }
 
+  @Test
+  public void testRename() {
+    runCommandAndAssertNoStatUpdates("string", (k, v) -> jedis.rename(k, v));
+  }
+
   // ------------ String related commands -----------
 
   @Test
@@ -128,32 +130,40 @@
 
   @Test
   public void testBitpos() {
-    jedis.bitpos("string", true);
     Map<String, String> info = getInfo(jedis);
+    Long currentHits = Long.parseLong(info.get(HITS));
+    Long currentMisses = Long.parseLong(info.get(MISSES));
 
-    assertThat(info.get(HITS)).isEqualTo("1");
-    assertThat(info.get(MISSES)).isEqualTo("0");
+    jedis.bitpos("string", true);
+    info = getInfo(jedis);
+
+    assertThat(info.get(HITS)).isEqualTo(String.valueOf(currentHits + 1));
+    assertThat(info.get(MISSES)).isEqualTo(String.valueOf(currentMisses));
 
     jedis.bitpos("missed", true);
     info = getInfo(jedis);
 
-    assertThat(info.get(HITS)).isEqualTo("1");
-    assertThat(info.get(MISSES)).isEqualTo("1");
+    assertThat(info.get(HITS)).isEqualTo(String.valueOf(currentHits + 1));
+    assertThat(info.get(MISSES)).isEqualTo(String.valueOf(currentMisses + 1));
   }
 
   @Test
   public void testBitop() {
-    jedis.bitop(BitOP.OR, "dest", "string", "string");
     Map<String, String> info = getInfo(jedis);
+    Long currentHits = Long.parseLong(info.get(HITS));
+    Long currentMisses = Long.parseLong(info.get(MISSES));
 
-    assertThat(info.get(HITS)).isEqualTo("2");
-    assertThat(info.get(MISSES)).isEqualTo("0");
+    jedis.bitop(BitOP.OR, "dest", "string", "string");
+    info = getInfo(jedis);
+
+    assertThat(info.get(HITS)).isEqualTo(String.valueOf(currentHits + 2));
+    assertThat(info.get(MISSES)).isEqualTo(String.valueOf(currentMisses));
 
     jedis.bitop(BitOP.OR, "dest", "string", "missed");
     info = getInfo(jedis);
 
-    assertThat(info.get(HITS)).isEqualTo("3");
-    assertThat(info.get(MISSES)).isEqualTo("1");
+    assertThat(info.get(HITS)).isEqualTo(String.valueOf(currentHits + 3));
+    assertThat(info.get(MISSES)).isEqualTo(String.valueOf(currentMisses + 1));
   }
 
   // ------------ Set related commands -----------
@@ -252,8 +262,8 @@
   }
 
   @Test
-  public void testHkeys() {
-    runCommandAndAssertHitsAndMisses("hash", k -> jedis.hkeys(k));
+  public void testKeys() {
+    runCommandAndAssertNoStatUpdates("hash", k -> jedis.keys(k));
   }
 
   @Test
@@ -286,47 +296,105 @@
     runCommandAndAssertHitsAndMisses("hash", (k, v) -> jedis.hscan(k, v));
   }
 
-  private void runCommandAndAssertHitsAndMisses(String key, Consumer<String> command) {
-    command.accept(key);
-    Map<String, String> info = getInfo(jedis);
+  @Test
+  public void testHMSet() {
+    Map<String, String> map = new HashMap<>();
+    map.put("key1", "value1");
+    map.put("key2", "value2");
 
-    assertThat(info.get(HITS)).isEqualTo("1");
-    assertThat(info.get(MISSES)).isEqualTo("0");
+    runCommandAndAssertNoStatUpdates("key", (k) -> jedis.hmset(k, map));
+  }
+
+  // ------------ Key related commands -----------
+
+  @Test
+  public void testExpire() {
+    runCommandAndAssertNoStatUpdates("hash", (k) -> jedis.expire(k, 5));
+  }
+
+  @Test
+  public void testPassiveExpiration() {
+    runCommandAndAssertNoStatUpdates("hash", (k) -> {
+      jedis.expire(k, 1);
+      GeodeAwaitility.await().during(Duration.ofSeconds(3)).until(() -> true);
+    });
+  }
+
+  @Test
+  public void testExpireAt() {
+    runCommandAndAssertNoStatUpdates("hash", (k) -> jedis.expireAt(k, 2145916800));
+  }
+
+  @Test
+  public void testPExpire() {
+    runCommandAndAssertNoStatUpdates("hash", (k) -> jedis.pexpire(k, 1024));
+  }
+
+  @Test
+  public void testPExpireAt() {
+    runCommandAndAssertNoStatUpdates("hash", (k) -> jedis.pexpireAt(k, 1608247597));
+  }
+
+  @Test
+  public void testPersist() {
+    runCommandAndAssertNoStatUpdates("hash", (k) -> jedis.persist(k));
+  }
+
+  // ------------ Helper Methods -----------
+
+  private void runCommandAndAssertHitsAndMisses(String key, Consumer<String> command) {
+    Map<String, String> info = getInfo(jedis);
+    Long currentHits = Long.parseLong(info.get(HITS));
+    Long currentMisses = Long.parseLong(info.get(MISSES));
+
+    command.accept(key);
+    info = getInfo(jedis);
+
+    assertThat(info.get(HITS)).isEqualTo(String.valueOf(currentHits + 1));
+    assertThat(info.get(MISSES)).isEqualTo(String.valueOf(currentMisses));
 
     command.accept("missed");
     info = getInfo(jedis);
 
-    assertThat(info.get(HITS)).isEqualTo("1");
-    assertThat(info.get(MISSES)).isEqualTo("1");
+    assertThat(info.get(HITS)).isEqualTo(String.valueOf(currentHits + 1));
+    assertThat(info.get(MISSES)).isEqualTo(String.valueOf(currentMisses + 1));
   }
 
   private void runCommandAndAssertHitsAndMisses(String key, BiConsumer<String, String> command) {
-    command.accept(key, "42");
     Map<String, String> info = getInfo(jedis);
+    Long currentHits = Long.parseLong(info.get(HITS));
+    Long currentMisses = Long.parseLong(info.get(MISSES));
 
-    assertThat(info.get(HITS)).isEqualTo("1");
-    assertThat(info.get(MISSES)).isEqualTo("0");
+    command.accept(key, "42");
+    info = getInfo(jedis);
+
+    assertThat(info.get(HITS)).isEqualTo(String.valueOf(currentHits + 1));
+    assertThat(info.get(MISSES)).isEqualTo(String.valueOf(currentMisses));
 
     command.accept("missed", "42");
     info = getInfo(jedis);
 
-    assertThat(info.get(HITS)).isEqualTo("1");
-    assertThat(info.get(MISSES)).isEqualTo("1");
+    assertThat(info.get(HITS)).isEqualTo(String.valueOf(currentHits + 1));
+    assertThat(info.get(MISSES)).isEqualTo(String.valueOf(currentMisses + 1));
   }
 
   private void runDiffCommandAndAssertHitsAndMisses(String key,
       BiConsumer<String, String> command) {
-    command.accept(key, key);
     Map<String, String> info = getInfo(jedis);
+    Long currentHits = Long.parseLong(info.get(HITS));
+    Long currentMisses = Long.parseLong(info.get(MISSES));
 
-    assertThat(info.get(HITS)).isEqualTo("2");
-    assertThat(info.get(MISSES)).isEqualTo("0");
+    command.accept(key, key);
+    info = getInfo(jedis);
+
+    assertThat(info.get(HITS)).isEqualTo(String.valueOf(currentHits + 2));
+    assertThat(info.get(MISSES)).isEqualTo(String.valueOf(currentMisses));
 
     command.accept(key, "missed");
     info = getInfo(jedis);
 
-    assertThat(info.get(HITS)).isEqualTo("3");
-    assertThat(info.get(MISSES)).isEqualTo("1");
+    assertThat(info.get(HITS)).isEqualTo(String.valueOf(currentHits + 3));
+    assertThat(info.get(MISSES)).isEqualTo(String.valueOf(currentMisses + 1));
   }
 
   /**
@@ -334,42 +402,58 @@
    */
   private void runDiffStoreCommandAndAssertNoStatUpdates(String key,
       TriConsumer<String, String, String> command) {
-    command.accept("destination", key, key);
     Map<String, String> info = getInfo(jedis);
+    String currentHits = info.get(HITS);
+    String currentMisses = info.get(MISSES);
 
-    assertThat(info.get(HITS)).isEqualTo("0");
-    assertThat(info.get(MISSES)).isEqualTo("0");
+    command.accept("destination", key, key);
+    info = getInfo(jedis);
+
+    assertThat(info.get(HITS)).isEqualTo(currentHits);
+    assertThat(info.get(MISSES)).isEqualTo(currentMisses);
 
     command.accept("destination", key, "missed");
     info = getInfo(jedis);
 
-    assertThat(info.get(HITS)).isEqualTo("0");
-    assertThat(info.get(MISSES)).isEqualTo("0");
+    assertThat(info.get(HITS)).isEqualTo(currentHits);
+    assertThat(info.get(MISSES)).isEqualTo(currentMisses);
   }
 
   private void runCommandAndAssertNoStatUpdates(String key, Consumer<String> command) {
-    command.accept(key);
     Map<String, String> info = getInfo(jedis);
+    String currentHits = info.get(HITS);
+    String currentMisses = info.get(MISSES);
 
-    assertThat(info.get(HITS)).isEqualTo("0");
-    assertThat(info.get(MISSES)).isEqualTo("0");
+    command.accept(key);
+    info = getInfo(jedis);
+
+    assertThat(info.get(HITS)).isEqualTo(currentHits);
+    assertThat(info.get(MISSES)).isEqualTo(currentMisses);
   }
 
   private void runCommandAndAssertNoStatUpdates(String key, BiConsumer<String, String> command) {
-    command.accept(key, "42");
     Map<String, String> info = getInfo(jedis);
+    String currentHits = info.get(HITS);
+    String currentMisses = info.get(MISSES);
 
-    assertThat(info.get(HITS)).isEqualTo("0");
-    assertThat(info.get(MISSES)).isEqualTo("0");
+    command.accept(key, "42");
+    info = getInfo(jedis);
+
+    assertThat(info.get(HITS)).isEqualTo(currentHits);
+    assertThat(info.get(MISSES)).isEqualTo(currentMisses);
   }
 
   private void runCommandAndAssertNoStatUpdates(String key,
       TriConsumer<String, String, String> command) {
-    command.accept(key, key, "42");
     Map<String, String> info = getInfo(jedis);
+    String currentHits = info.get(HITS);
+    String currentMisses = info.get(MISSES);
 
-    assertThat(info.get(HITS)).isEqualTo("0");
-    assertThat(info.get(MISSES)).isEqualTo("0");
+    command.accept(key, key, "42");
+    info = getInfo(jedis);
+
+    assertThat(info.get(HITS)).isEqualTo(currentHits);
+    assertThat(info.get(MISSES)).isEqualTo(currentMisses);
   }
 
   /**
diff --git a/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/executor/server/HitsMissesIntegrationTest.java b/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/executor/server/HitsMissesIntegrationTest.java
new file mode 100644
index 0000000..0a96c9d
--- /dev/null
+++ b/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/executor/server/HitsMissesIntegrationTest.java
@@ -0,0 +1,32 @@
+/*
+ * 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.executor.server;
+
+import org.junit.ClassRule;
+
+import org.apache.geode.redis.GeodeRedisServerRule;
+
+public class HitsMissesIntegrationTest extends AbstractHitsMissesIntegrationTest {
+
+  @ClassRule
+  public static GeodeRedisServerRule server = new GeodeRedisServerRule();
+
+  @Override
+  public int getPort() {
+    return server.getPort();
+  }
+}
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/GeodeRedisServer.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/GeodeRedisServer.java
index b11c184..06fa6d6 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/GeodeRedisServer.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/GeodeRedisServer.java
@@ -130,7 +130,7 @@
   }
 
   @VisibleForTesting
-  RedisStats getStats() {
+  public RedisStats getStats() {
     return redisStats;
   }
 
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/PassiveExpirationManager.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/PassiveExpirationManager.java
index 26de09e..6094fe9 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/PassiveExpirationManager.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/PassiveExpirationManager.java
@@ -71,7 +71,7 @@
         try {
           if (entry.getValue().hasExpired(now)) {
             // pttl will do its own check using active expiration and expire the key if needed
-            if (-2 == redisKeyCommands.pttl(entry.getKey())) {
+            if (-2 == redisKeyCommands.internalPttl(entry.getKey())) {
               expireCount++;
             }
           }
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisCommandSupportLevel.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisCommandSupportLevel.java
index 3971e31..6ff8891 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisCommandSupportLevel.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisCommandSupportLevel.java
@@ -20,5 +20,6 @@
   SUPPORTED,
   UNSUPPORTED,
   UNIMPLEMENTED,
-  UNKNOWN
+  UNKNOWN,
+  INTERNAL
 }
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisCommandType.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisCommandType.java
index 0bf44cd..beba759 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisCommandType.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisCommandType.java
@@ -15,6 +15,7 @@
 
 package org.apache.geode.redis.internal;
 
+import static org.apache.geode.redis.internal.RedisCommandSupportLevel.INTERNAL;
 import static org.apache.geode.redis.internal.RedisCommandSupportLevel.SUPPORTED;
 import static org.apache.geode.redis.internal.RedisCommandSupportLevel.UNIMPLEMENTED;
 import static org.apache.geode.redis.internal.RedisCommandSupportLevel.UNSUPPORTED;
@@ -167,7 +168,6 @@
   SREM(new SRemExecutor(), SUPPORTED, new MinimumParameterRequirements(3)),
 
   /********** Publish Subscribe **********/
-
   SUBSCRIBE(new SubscribeExecutor(), SUPPORTED, new MinimumParameterRequirements(2)),
   PUBLISH(new PublishExecutor(), SUPPORTED, new ExactParameterRequirements(3)),
   PSUBSCRIBE(new PsubscribeExecutor(), SUPPORTED, new MinimumParameterRequirements(2)),
@@ -175,6 +175,14 @@
   UNSUBSCRIBE(new UnsubscribeExecutor(), SUPPORTED, new MinimumParameterRequirements(1)),
 
   /***************************************
+   ********** Internal Commands **********
+   * /
+   ***************************************/
+  // do not call these directly, only to be used in other commands
+  INTERNALPTTL(null, INTERNAL, new ExactParameterRequirements(2)),
+  INTERNALSMEMBERS(null, INTERNAL, new ExactParameterRequirements(3)),
+
+  /***************************************
    *** Unsupported Commands ***
    ***************************************/
 
@@ -419,6 +427,10 @@
     return supportLevel == UNIMPLEMENTED;
   }
 
+  public boolean isInternal() {
+    return supportLevel == INTERNAL;
+  }
+
   public boolean isUnknown() {
     return supportLevel == RedisCommandSupportLevel.UNKNOWN;
   }
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/data/CommandHelper.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/data/CommandHelper.java
index 3c40582..53e2568 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/data/CommandHelper.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/data/CommandHelper.java
@@ -83,12 +83,14 @@
     }
   }
 
-  RedisSet getRedisSet(ByteArrayWrapper key) {
+  RedisSet getRedisSet(ByteArrayWrapper key, boolean updateStats) {
     RedisData redisData = getRedisData(key, NULL_REDIS_SET);
-    if (redisData == NULL_REDIS_SET) {
-      redisStats.incKeyspaceMisses();
-    } else {
-      redisStats.incKeyspaceHits();
+    if (updateStats) {
+      if (redisData == NULL_REDIS_SET) {
+        redisStats.incKeyspaceMisses();
+      } else {
+        redisStats.incKeyspaceHits();
+      }
     }
     return checkSetType(redisData);
   }
@@ -103,14 +105,15 @@
     return (RedisSet) redisData;
   }
 
-  RedisHash getRedisHash(ByteArrayWrapper key) {
+  RedisHash getRedisHash(ByteArrayWrapper key, boolean updateStats) {
     RedisData redisData = getRedisData(key, NULL_REDIS_HASH);
-    if (redisData == NULL_REDIS_HASH) {
-      redisStats.incKeyspaceMisses();
-    } else {
-      redisStats.incKeyspaceHits();
+    if (updateStats) {
+      if (redisData == NULL_REDIS_HASH) {
+        redisStats.incKeyspaceMisses();
+      } else {
+        redisStats.incKeyspaceHits();
+      }
     }
-
     return checkHashType(redisData);
   }
 
@@ -137,35 +140,39 @@
     return (RedisString) redisData;
   }
 
-  RedisString getRedisString(ByteArrayWrapper key) {
+  RedisString getRedisString(ByteArrayWrapper key, boolean updateStats) {
     RedisData redisData = getRedisData(key, NULL_REDIS_STRING);
-    if (redisData == NULL_REDIS_STRING) {
-      redisStats.incKeyspaceMisses();
-    } else {
-      redisStats.incKeyspaceHits();
+    if (updateStats) {
+      if (redisData == NULL_REDIS_STRING) {
+        redisStats.incKeyspaceMisses();
+      } else {
+        redisStats.incKeyspaceHits();
+      }
     }
 
     return checkStringType(redisData, false);
   }
 
-  RedisString getRedisStringIgnoringType(ByteArrayWrapper key) {
+  RedisString getRedisStringIgnoringType(ByteArrayWrapper key, boolean updateStats) {
     RedisData redisData = getRedisData(key, NULL_REDIS_STRING);
-    if (redisData == NULL_REDIS_STRING) {
-      redisStats.incKeyspaceMisses();
-    } else {
-      redisStats.incKeyspaceHits();
+    if (updateStats) {
+      if (redisData == NULL_REDIS_STRING) {
+        redisStats.incKeyspaceMisses();
+      } else {
+        redisStats.incKeyspaceHits();
+      }
     }
+
     return checkStringType(redisData, true);
   }
 
   RedisString setRedisString(ByteArrayWrapper key, ByteArrayWrapper value) {
     RedisString result;
     RedisData redisData = getRedisData(key);
+
     if (redisData.isNull() || redisData.getType() != REDIS_STRING) {
-      redisStats.incKeyspaceMisses();
       result = new RedisString(value);
     } else {
-      redisStats.incKeyspaceHits();
       result = (RedisString) redisData;
       result.set(value);
     }
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/data/NullRedisSet.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/data/NullRedisSet.java
index 07943d6..f2b5446 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/data/NullRedisSet.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/data/NullRedisSet.java
@@ -132,7 +132,7 @@
     }
     for (Set<ByteArrayWrapper> set : nonDestinationSets) {
       if (set == null) {
-        set = helper.getRedisSet(destination).smembers();
+        set = helper.getRedisSet(destination, false).smembers();
       }
       if (result == null) {
         result = set;
@@ -169,7 +169,7 @@
       if (key.equals(destination)) {
         result.add(null);
       } else {
-        result.add(redisSetCommands.smembers(key));
+        result.add(redisSetCommands.internalsmembers(key));
       }
     }
     return result;
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/data/NullRedisString.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/data/NullRedisString.java
index c60ef5c..867797b 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/data/NullRedisString.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/data/NullRedisString.java
@@ -230,7 +230,7 @@
       int selfIndex,
       List<ByteArrayWrapper> sourceValues) {
     if (selfIndex != -1) {
-      RedisString redisString = helper.getRedisString(key);
+      RedisString redisString = helper.getRedisString(key, true);
       if (!redisString.isNull()) {
         sourceValues.set(selfIndex, redisString.getValue());
       }
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/data/RedisHashCommandsFunctionExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/data/RedisHashCommandsFunctionExecutor.java
index f03edbe..4fc72c6 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/data/RedisHashCommandsFunctionExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/data/RedisHashCommandsFunctionExecutor.java
@@ -33,79 +33,83 @@
     super(helper);
   }
 
-  private RedisHash getRedisHash(ByteArrayWrapper key) {
-    return helper.getRedisHash(key);
+  private RedisHash getRedisHash(ByteArrayWrapper key, boolean updateStats) {
+    return helper.getRedisHash(key, updateStats);
   }
 
   @Override
   public int hset(ByteArrayWrapper key, List<ByteArrayWrapper> fieldsToSet, boolean NX) {
-    return stripedExecute(key, () -> getRedisHash(key)
-        .hset(getRegion(), key, fieldsToSet, NX));
+    return stripedExecute(key,
+        () -> getRedisHash(key, false)
+            .hset(getRegion(), key, fieldsToSet, NX));
   }
 
   @Override
   public int hdel(ByteArrayWrapper key, List<ByteArrayWrapper> fieldsToRemove) {
-    return stripedExecute(key, () -> getRedisHash(key)
-        .hdel(getRegion(), key, fieldsToRemove));
+    return stripedExecute(key,
+        () -> getRedisHash(key, false)
+            .hdel(getRegion(), key, fieldsToRemove));
   }
 
   @Override
   public Collection<ByteArrayWrapper> hgetall(ByteArrayWrapper key) {
-    return stripedExecute(key, () -> getRedisHash(key).hgetall());
+    return stripedExecute(key, () -> getRedisHash(key, true).hgetall());
   }
 
   @Override
   public int hexists(ByteArrayWrapper key, ByteArrayWrapper field) {
-    return stripedExecute(key, () -> getRedisHash(key).hexists(field));
+    return stripedExecute(key, () -> getRedisHash(key, true).hexists(field));
   }
 
   @Override
   public ByteArrayWrapper hget(ByteArrayWrapper key, ByteArrayWrapper field) {
-    return stripedExecute(key, () -> getRedisHash(key).hget(field));
+    return stripedExecute(key, () -> getRedisHash(key, true).hget(field));
   }
 
   @Override
   public int hlen(ByteArrayWrapper key) {
-    return stripedExecute(key, () -> getRedisHash(key).hlen());
+    return stripedExecute(key, () -> getRedisHash(key, true).hlen());
   }
 
   @Override
   public int hstrlen(ByteArrayWrapper key, ByteArrayWrapper field) {
-    return stripedExecute(key, () -> getRedisHash(key).hstrlen(field));
+    return stripedExecute(key, () -> getRedisHash(key, true).hstrlen(field));
   }
 
   @Override
   public List<ByteArrayWrapper> hmget(ByteArrayWrapper key, List<ByteArrayWrapper> fields) {
-    return stripedExecute(key, () -> getRedisHash(key).hmget(fields));
+    return stripedExecute(key, () -> getRedisHash(key, true).hmget(fields));
   }
 
   @Override
   public Collection<ByteArrayWrapper> hvals(ByteArrayWrapper key) {
-    return stripedExecute(key, () -> getRedisHash(key).hvals());
+    return stripedExecute(key, () -> getRedisHash(key, true).hvals());
   }
 
   @Override
   public Collection<ByteArrayWrapper> hkeys(ByteArrayWrapper key) {
-    return stripedExecute(key, () -> getRedisHash(key).hkeys());
+    return stripedExecute(key, () -> getRedisHash(key, true).hkeys());
   }
 
   @Override
   public Pair<BigInteger, List<Object>> hscan(ByteArrayWrapper key, Pattern matchPattern, int count,
       BigInteger cursor) {
-    return stripedExecute(key, () -> getRedisHash(key).hscan(matchPattern, count, cursor));
+    return stripedExecute(key,
+        () -> getRedisHash(key, true)
+            .hscan(matchPattern, count, cursor));
   }
 
   @Override
   public long hincrby(ByteArrayWrapper key, ByteArrayWrapper field, long increment) {
     return stripedExecute(key,
-        () -> getRedisHash(key)
+        () -> getRedisHash(key, true)
             .hincrby(getRegion(), key, field, increment));
   }
 
   @Override
   public double hincrbyfloat(ByteArrayWrapper key, ByteArrayWrapper field, double increment) {
     return stripedExecute(key,
-        () -> getRedisHash(key)
+        () -> getRedisHash(key, true)
             .hincrbyfloat(getRegion(), key, field, increment));
   }
 
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/data/RedisKeyCommandsFunctionExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/data/RedisKeyCommandsFunctionExecutor.java
index aa4922f..109365c 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/data/RedisKeyCommandsFunctionExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/data/RedisKeyCommandsFunctionExecutor.java
@@ -59,6 +59,11 @@
   }
 
   @Override
+  public long internalPttl(ByteArrayWrapper key) {
+    return stripedExecute(key, () -> getRedisData(key).pttl(getRegion(), key));
+  }
+
+  @Override
   public int pexpireat(ByteArrayWrapper key, long timestamp) {
     return stripedExecute(key,
         () -> getRedisData(key).pexpireat(helper, key, timestamp));
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/data/RedisSetCommandsFunctionExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/data/RedisSetCommandsFunctionExecutor.java
index ffffeeb..1a9bc68 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/data/RedisSetCommandsFunctionExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/data/RedisSetCommandsFunctionExecutor.java
@@ -37,18 +37,22 @@
     super(helper);
   }
 
-  private RedisSet getRedisSet(ByteArrayWrapper key) {
-    return helper.getRedisSet(key);
+  private RedisSet getRedisSet(ByteArrayWrapper key, boolean updateStats) {
+    return helper.getRedisSet(key, updateStats);
   }
 
   @Override
   public long sadd(
       ByteArrayWrapper key,
       ArrayList<ByteArrayWrapper> membersToAdd) {
-    return stripedExecute(key, () -> getRedisSet(key).sadd(membersToAdd,
-        getRegion(), key));
+    return stripedExecute(key,
+        () -> getRedisSet(key, false)
+            .sadd(membersToAdd,
+                getRegion(), key));
   }
 
+
+
   @Override
   public int sunionstore(ByteArrayWrapper destination,
       ArrayList<ByteArrayWrapper> setKeys) {
@@ -71,44 +75,50 @@
   public long srem(
       ByteArrayWrapper key,
       ArrayList<ByteArrayWrapper> membersToRemove) {
-    return stripedExecute(key, () -> getRedisSet(key).srem(membersToRemove,
+    return stripedExecute(key, () -> getRedisSet(key, false).srem(membersToRemove,
         getRegion(), key));
   }
 
   @Override
   public Set<ByteArrayWrapper> smembers(
       ByteArrayWrapper key) {
-    return stripedExecute(key, () -> getRedisSet(key).smembers());
+    return stripedExecute(key, () -> getRedisSet(key, true).smembers());
+  }
+
+  @Override
+  public Set<ByteArrayWrapper> internalsmembers(
+      ByteArrayWrapper key) {
+    return stripedExecute(key, () -> getRedisSet(key, false).smembers());
   }
 
   @Override
   public int scard(ByteArrayWrapper key) {
-    return stripedExecute(key, () -> getRedisSet(key).scard());
+    return stripedExecute(key, () -> getRedisSet(key, true).scard());
   }
 
   @Override
   public boolean sismember(
       ByteArrayWrapper key, ByteArrayWrapper member) {
-    return stripedExecute(key, () -> getRedisSet(key).sismember(member));
+    return stripedExecute(key, () -> getRedisSet(key, true).sismember(member));
   }
 
   @Override
   public Collection<ByteArrayWrapper> srandmember(
       ByteArrayWrapper key, int count) {
-    return stripedExecute(key, () -> getRedisSet(key).srandmember(count));
+    return stripedExecute(key, () -> getRedisSet(key, true).srandmember(count));
   }
 
   @Override
   public Collection<ByteArrayWrapper> spop(
       ByteArrayWrapper key, int popCount) {
-    return stripedExecute(key, () -> getRedisSet(key)
+    return stripedExecute(key, () -> getRedisSet(key, false)
         .spop(getRegion(), key, popCount));
   }
 
   @Override
   public Pair<BigInteger, List<Object>> sscan(ByteArrayWrapper key, Pattern matchPattern, int count,
       BigInteger cursor) {
-    return stripedExecute(key, () -> getRedisSet(key).sscan(matchPattern, count, cursor));
+    return stripedExecute(key, () -> getRedisSet(key, true).sscan(matchPattern, count, cursor));
   }
 
 }
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/data/RedisStringCommandsFunctionExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/data/RedisStringCommandsFunctionExecutor.java
index d16bb3f..38643f0 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/data/RedisStringCommandsFunctionExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/data/RedisStringCommandsFunctionExecutor.java
@@ -31,28 +31,29 @@
     super(helper);
   }
 
-  private RedisString getRedisString(ByteArrayWrapper key) {
-    return helper.getRedisString(key);
+  private RedisString getRedisString(ByteArrayWrapper key, boolean updateStats) {
+    return helper.getRedisString(key, updateStats);
   }
 
-  private RedisString getRedisStringIgnoringType(ByteArrayWrapper key) {
-    return helper.getRedisStringIgnoringType(key);
+  private RedisString getRedisStringIgnoringType(ByteArrayWrapper key, boolean updateStats) {
+    return helper.getRedisStringIgnoringType(key, updateStats);
   }
 
   @Override
   public long append(ByteArrayWrapper key, ByteArrayWrapper valueToAppend) {
     return stripedExecute(key,
-        () -> getRedisString(key).append(valueToAppend, getRegion(), key));
+        () -> getRedisString(key, false)
+            .append(valueToAppend, getRegion(), key));
   }
 
   @Override
   public ByteArrayWrapper get(ByteArrayWrapper key) {
-    return stripedExecute(key, () -> getRedisString(key).get());
+    return stripedExecute(key, () -> getRedisString(key, true).get());
   }
 
   @Override
   public ByteArrayWrapper mget(ByteArrayWrapper key) {
-    return stripedExecute(key, () -> getRedisStringIgnoringType(key).get());
+    return stripedExecute(key, () -> getRedisStringIgnoringType(key, true).get());
   }
 
   @Override
@@ -63,30 +64,30 @@
 
   @Override
   public long incr(ByteArrayWrapper key) {
-    return stripedExecute(key, () -> getRedisString(key).incr(getRegion(), key));
+    return stripedExecute(key, () -> getRedisString(key, true).incr(getRegion(), key));
   }
 
   @Override
   public long decr(ByteArrayWrapper key) {
-    return stripedExecute(key, () -> getRedisString(key).decr(getRegion(), key));
+    return stripedExecute(key, () -> getRedisString(key, true).decr(getRegion(), key));
   }
 
   @Override
   public ByteArrayWrapper getset(ByteArrayWrapper key, ByteArrayWrapper value) {
     return stripedExecute(key,
-        () -> getRedisString(key).getset(getRegion(), key, value));
+        () -> getRedisString(key, true).getset(getRegion(), key, value));
   }
 
   @Override
   public long incrby(ByteArrayWrapper key, long increment) {
     return stripedExecute(key,
-        () -> getRedisString(key).incrby(getRegion(), key, increment));
+        () -> getRedisString(key, true).incrby(getRegion(), key, increment));
   }
 
   @Override
   public double incrbyfloat(ByteArrayWrapper key, double increment) {
     return stripedExecute(key,
-        () -> getRedisString(key)
+        () -> getRedisString(key, true)
             .incrbyfloat(getRegion(), key, increment));
   }
 
@@ -99,46 +100,46 @@
   @Override
   public long decrby(ByteArrayWrapper key, long decrement) {
     return stripedExecute(key,
-        () -> getRedisString(key).decrby(getRegion(), key, decrement));
+        () -> getRedisString(key, true).decrby(getRegion(), key, decrement));
   }
 
   @Override
   public ByteArrayWrapper getrange(ByteArrayWrapper key, long start, long end) {
-    return stripedExecute(key, () -> getRedisString(key).getrange(start, end));
+    return stripedExecute(key, () -> getRedisString(key, true).getrange(start, end));
   }
 
   @Override
   public int setrange(ByteArrayWrapper key, int offset, byte[] value) {
     return stripedExecute(key,
-        () -> getRedisString(key)
+        () -> getRedisString(key, true)
             .setrange(getRegion(), key, offset, value));
   }
 
   @Override
   public int bitpos(ByteArrayWrapper key, int bit, int start, Integer end) {
     return stripedExecute(key,
-        () -> getRedisString(key)
+        () -> getRedisString(key, true)
             .bitpos(getRegion(), key, bit, start, end));
   }
 
   @Override
   public long bitcount(ByteArrayWrapper key, int start, int end) {
-    return stripedExecute(key, () -> getRedisString(key).bitcount(start, end));
+    return stripedExecute(key, () -> getRedisString(key, true).bitcount(start, end));
   }
 
   @Override
   public long bitcount(ByteArrayWrapper key) {
-    return stripedExecute(key, () -> getRedisString(key).bitcount());
+    return stripedExecute(key, () -> getRedisString(key, true).bitcount());
   }
 
   @Override
   public int strlen(ByteArrayWrapper key) {
-    return stripedExecute(key, () -> getRedisString(key).strlen());
+    return stripedExecute(key, () -> getRedisString(key, true).strlen());
   }
 
   @Override
   public int getbit(ByteArrayWrapper key, int offset) {
-    return stripedExecute(key, () -> getRedisString(key).getbit(offset));
+    return stripedExecute(key, () -> getRedisString(key, true).getbit(offset));
   }
 
   @Override
@@ -146,7 +147,7 @@
     int byteIndex = (int) (offset / 8);
     byte bitIndex = (byte) (offset % 8);
     return stripedExecute(key,
-        () -> getRedisString(key)
+        () -> getRedisString(key, true)
             .setbit(getRegion(), key, value, byteIndex, bitIndex));
   }
 
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/CommandFunction.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/CommandFunction.java
index 751d3b9..55c2f0f 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/CommandFunction.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/CommandFunction.java
@@ -98,6 +98,8 @@
         return keyCommands.persist(key);
       case PTTL:
         return keyCommands.pttl(key);
+      case INTERNALPTTL:
+        return keyCommands.internalPttl(key);
       case APPEND: {
         ByteArrayWrapper valueToAdd = (ByteArrayWrapper) args[1];
         return stringCommands.append(key, valueToAdd);
@@ -182,6 +184,8 @@
       }
       case SMEMBERS:
         return setCommands.smembers(key);
+      case INTERNALSMEMBERS:
+        return setCommands.internalsmembers(key);
       case SCARD:
         return setCommands.scard(key);
       case SISMEMBER: {
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HScanExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HScanExecutor.java
index ada758f..d9af712 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HScanExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HScanExecutor.java
@@ -68,6 +68,7 @@
 
     ByteArrayWrapper key = command.getKey();
     if (!getDataRegion(context).containsKey(key)) {
+      context.getRedisStats().incKeyspaceMisses();
       return RedisResponse.emptyScan();
     }
 
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/key/RedisKeyCommands.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/key/RedisKeyCommands.java
index f89a9e7..cf413e4 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/key/RedisKeyCommands.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/key/RedisKeyCommands.java
@@ -27,6 +27,8 @@
 
   long pttl(ByteArrayWrapper key);
 
+  long internalPttl(ByteArrayWrapper key);
+
   int pexpireat(ByteArrayWrapper key, long timestamp);
 
   int persist(ByteArrayWrapper key);
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/key/RedisKeyCommandsFunctionInvoker.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/key/RedisKeyCommandsFunctionInvoker.java
index d7a2b13..32de43c 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/key/RedisKeyCommandsFunctionInvoker.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/key/RedisKeyCommandsFunctionInvoker.java
@@ -17,6 +17,7 @@
 
 import static org.apache.geode.redis.internal.RedisCommandType.DEL;
 import static org.apache.geode.redis.internal.RedisCommandType.EXISTS;
+import static org.apache.geode.redis.internal.RedisCommandType.INTERNALPTTL;
 import static org.apache.geode.redis.internal.RedisCommandType.PERSIST;
 import static org.apache.geode.redis.internal.RedisCommandType.PEXPIREAT;
 import static org.apache.geode.redis.internal.RedisCommandType.PTTL;
@@ -57,6 +58,11 @@
   }
 
   @Override
+  public long internalPttl(ByteArrayWrapper key) {
+    return invokeCommandFunction(key, INTERNALPTTL);
+  }
+
+  @Override
   public int pexpireat(ByteArrayWrapper key, long timestamp) {
     return invokeCommandFunction(key, PEXPIREAT, timestamp);
   }
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/RedisSetCommands.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/RedisSetCommands.java
index 7a6722d..2bb14fd 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/RedisSetCommands.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/RedisSetCommands.java
@@ -34,6 +34,8 @@
 
   Set<ByteArrayWrapper> smembers(ByteArrayWrapper key);
 
+  Set<ByteArrayWrapper> internalsmembers(ByteArrayWrapper key);
+
   int scard(ByteArrayWrapper key);
 
   boolean sismember(ByteArrayWrapper key, ByteArrayWrapper member);
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/RedisSetCommandsFunctionInvoker.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/RedisSetCommandsFunctionInvoker.java
index 3d6e5b4..cc38577 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/RedisSetCommandsFunctionInvoker.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/RedisSetCommandsFunctionInvoker.java
@@ -15,6 +15,7 @@
 
 package org.apache.geode.redis.internal.executor.set;
 
+import static org.apache.geode.redis.internal.RedisCommandType.INTERNALSMEMBERS;
 import static org.apache.geode.redis.internal.RedisCommandType.SADD;
 import static org.apache.geode.redis.internal.RedisCommandType.SCARD;
 import static org.apache.geode.redis.internal.RedisCommandType.SDIFFSTORE;
@@ -69,6 +70,11 @@
   }
 
   @Override
+  public Set<ByteArrayWrapper> internalsmembers(ByteArrayWrapper key) {
+    return invokeCommandFunction(key, INTERNALSMEMBERS);
+  }
+
+  @Override
   public int scard(ByteArrayWrapper key) {
     return invokeCommandFunction(key, SCARD);
   }
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SScanExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SScanExecutor.java
index 6f855a1..909c955 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SScanExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SScanExecutor.java
@@ -63,6 +63,7 @@
     ByteArrayWrapper key = command.getKey();
 
     if (!getDataRegion(context).containsKey(key)) {
+      context.getRedisStats().incKeyspaceMisses();
       return RedisResponse.emptyScan();
     }
 
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/statistics/RedisStats.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/statistics/RedisStats.java
index 2a535f6..32b7409 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/statistics/RedisStats.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/statistics/RedisStats.java
@@ -28,7 +28,6 @@
 import org.apache.geode.redis.internal.RedisCommandType;
 
 public class RedisStats {
-
   private final AtomicLong commandsProcessed = new AtomicLong();
   private final AtomicLong totalNetworkBytesRead = new AtomicLong();
   private final AtomicLong totalConnectionsReceived = new AtomicLong();
@@ -127,7 +126,6 @@
 
   public void incKeyspaceHits() {
     keyspaceHits.incrementAndGet();
-    geodeRedisStats.incrementKeyspaceHits();
   }
 
   public long getKeyspaceHits() {
@@ -136,7 +134,6 @@
 
   public void incKeyspaceMisses() {
     keyspaceMisses.incrementAndGet();
-    geodeRedisStats.incrementKeyspaceMisses();
   }
 
   public long getKeyspaceMisses() {
diff --git a/geode-redis/src/test/java/org/apache/geode/redis/internal/SupportedCommandsJUnitTest.java b/geode-redis/src/test/java/org/apache/geode/redis/internal/SupportedCommandsJUnitTest.java
index a6bd34f..4474201 100644
--- a/geode-redis/src/test/java/org/apache/geode/redis/internal/SupportedCommandsJUnitTest.java
+++ b/geode-redis/src/test/java/org/apache/geode/redis/internal/SupportedCommandsJUnitTest.java
@@ -234,6 +234,11 @@
       "UNKNOWN"
   };
 
+  private final String[] internalCommands = new String[] {
+      "INTERNALSMEMBERS",
+      "INTERNALPTTL"
+  };
+
   @Test
   public void crossCheckAllUnsupportedCommands_areMarkedUnsupported() {
     for (String commandName : unSupportedCommands) {
@@ -294,6 +299,7 @@
     allCommands.addAll(asList(unSupportedCommands));
     allCommands.addAll(asList(unImplementedCommands));
     allCommands.addAll(asList(unknownCommands));
+    allCommands.addAll(asList(internalCommands));
 
     List<String> definedCommands =
         Arrays.stream(RedisCommandType.values()).map(Enum::name).collect(Collectors.toList());
@@ -301,9 +307,30 @@
     assertThat(definedCommands).containsExactlyInAnyOrderElementsOf(allCommands);
   }
 
+  @Test
+  public void checkAllInternalCommands_areIncludedInInternalLists() {
+    List<String> allInternalCommands = new ArrayList<>(asList(internalCommands));
+
+    List<String> internalCommands = getAllInternalCommands().stream()
+        .filter(c -> !c.isUnknown())
+        .map(Enum::name).collect(Collectors.toList());
+
+    assertThat(internalCommands).containsExactlyInAnyOrderElementsOf(allInternalCommands);
+  }
+
   private List<RedisCommandType> getAllImplementedCommands() {
     List<RedisCommandType> implementedCommands = new ArrayList<>(asList(RedisCommandType.values()));
     implementedCommands.removeIf(RedisCommandType::isUnimplemented);
+    implementedCommands.removeIf(RedisCommandType::isInternal);
     return implementedCommands;
   }
+
+  private List<RedisCommandType> getAllInternalCommands() {
+    List<RedisCommandType> internalCommands = new ArrayList<>(asList(RedisCommandType.values()));
+    internalCommands.removeIf(RedisCommandType::isUnimplemented);
+    internalCommands.removeIf(RedisCommandType::isSupported);
+    internalCommands.removeIf(RedisCommandType::isUnsupported);
+
+    return internalCommands;
+  }
 }