You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by je...@apache.org on 2020/01/30 17:17:18 UTC

[geode] branch develop updated: GEODE-7747: Refactor - extract class KeyRegistrar (#4647)

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

jensdeppe 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 b7b061d  GEODE-7747: Refactor - extract class KeyRegistrar (#4647)
b7b061d is described below

commit b7b061d98585fed3f88dd5c5030a8f0490111947
Author: Murtuza Boxwala <mb...@pivotal.io>
AuthorDate: Thu Jan 30 12:16:53 2020 -0500

    GEODE-7747: Refactor - extract class KeyRegistrar (#4647)
    
    KeyRegistrar encapsulates info about keys that are inserted via the
    Redis API. It uses a Geode Region to store a map from key -> RedisDataType
---
 .../geode/redis/SetCommandNegativeCaseTest.java    | 90 +++++++++++++++++++++
 .../org/apache/geode/redis/GeodeRedisServer.java   | 10 ++-
 .../redis/internal/ExecutionHandlerContext.java    |  9 ++-
 .../apache/geode/redis/internal/KeyRegistrar.java  | 94 ++++++++++++++++++++++
 .../geode/redis/internal/RegionProvider.java       | 80 +++---------------
 .../redis/internal/executor/AbstractExecutor.java  | 17 ++--
 .../redis/internal/executor/DBSizeExecutor.java    |  2 +-
 .../geode/redis/internal/executor/DelExecutor.java |  2 +-
 .../redis/internal/executor/ExistsExecutor.java    |  2 +-
 .../redis/internal/executor/FlushAllExecutor.java  |  2 +-
 .../redis/internal/executor/KeysExecutor.java      |  2 +-
 .../redis/internal/executor/ScanExecutor.java      |  2 +-
 .../geode/redis/internal/executor/TTLExecutor.java |  2 +-
 .../redis/internal/executor/TypeExecutor.java      |  2 +-
 .../redis/internal/executor/hll/HllExecutor.java   |  9 +--
 .../internal/executor/string/BitOpExecutor.java    |  5 +-
 .../internal/executor/string/DecrExecutor.java     |  2 -
 .../internal/executor/string/MSetNXExecutor.java   |  3 +-
 .../internal/executor/string/SetExecutor.java      |  3 +-
 .../internal/executor/string/StringExecutor.java   | 20 +----
 20 files changed, 231 insertions(+), 127 deletions(-)

diff --git a/geode-redis/src/integrationTest/java/org/apache/geode/redis/SetCommandNegativeCaseTest.java b/geode-redis/src/integrationTest/java/org/apache/geode/redis/SetCommandNegativeCaseTest.java
new file mode 100644
index 0000000..c9e256c
--- /dev/null
+++ b/geode-redis/src/integrationTest/java/org/apache/geode/redis/SetCommandNegativeCaseTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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;
+
+import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
+import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
+import static org.apache.geode.redis.GeodeRedisServer.REDIS_META_DATA_REGION;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.util.Random;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.exceptions.JedisDataException;
+
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.cache.GemFireCache;
+import org.apache.geode.internal.AvailablePortHelper;
+import org.apache.geode.test.junit.categories.RedisTest;
+
+@Category({RedisTest.class})
+public class SetCommandNegativeCaseTest {
+  private static Jedis jedis;
+  private static GeodeRedisServer server;
+  private static GemFireCache cache;
+  private static Random rand;
+  private static int port = 6379;
+
+  @BeforeClass
+  public static void setUp() {
+    rand = new Random();
+    CacheFactory cf = new CacheFactory();
+    cf.set(LOG_LEVEL, "error");
+    cf.set(MCAST_PORT, "0");
+    cf.set(LOCATORS, "");
+    cache = cf.create();
+    port = AvailablePortHelper.getRandomAvailableTCPPort();
+    server = new GeodeRedisServer("localhost", port);
+
+    server.start();
+    jedis = new Jedis("localhost", port, 10000000);
+  }
+
+
+  @After
+  public void flushAll() {
+    jedis.flushAll();
+  }
+
+  @AfterClass
+  public static void tearDown() {
+    jedis.close();
+    cache.close();
+    server.shutdown();
+  }
+
+  @Test
+  public void Should_Throw_RedisDataTypeMismatchException_Given_Key_Already_Exists_With_Different_RedisDataType() {
+    jedis.hset("key", "field", "value");
+
+    assertThatThrownBy(
+        () -> jedis.set("key", "something else")).isInstanceOf(JedisDataException.class)
+            .hasMessageContaining("WRONGTYPE");
+  }
+
+  @Test
+  public void Should_Throw_RedisDataTypeMismatchException_Given_RedisDataType_REDIS_PROTECTED() {
+    assertThatThrownBy(
+        () -> jedis.set(REDIS_META_DATA_REGION, "something else"))
+            .isInstanceOf(JedisDataException.class)
+            .hasMessageContaining("protected");
+  }
+}
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/GeodeRedisServer.java b/geode-redis/src/main/java/org/apache/geode/redis/GeodeRedisServer.java
index d1fc7a6..12db96b 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/GeodeRedisServer.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/GeodeRedisServer.java
@@ -70,6 +70,7 @@ import org.apache.geode.redis.internal.ByteArrayWrapper;
 import org.apache.geode.redis.internal.ByteToCommandDecoder;
 import org.apache.geode.redis.internal.Coder;
 import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.KeyRegistrar;
 import org.apache.geode.redis.internal.RedisDataType;
 import org.apache.geode.redis.internal.RegionProvider;
 
@@ -259,6 +260,7 @@ public class GeodeRedisServer {
 
   private boolean shutdown;
   private boolean started;
+  private KeyRegistrar keyRegistrar;
 
   /**
    * Determine the {@link RegionShortcut} type from a String value. If the String value doesn't map
@@ -443,7 +445,8 @@ public class GeodeRedisServer {
         assErr.initCause(e);
         throw assErr;
       }
-      this.regionCache = new RegionProvider(stringsRegion, hLLRegion, redisMetaData,
+      this.keyRegistrar = new KeyRegistrar(redisMetaData);
+      this.regionCache = new RegionProvider(stringsRegion, hLLRegion, this.keyRegistrar,
           expirationFutures, expirationExecutor, this.DEFAULT_REGION_TYPE);
       redisMetaData.put(REDIS_META_DATA_REGION, RedisDataType.REDIS_PROTECTED);
       redisMetaData.put(HLL_REGION, RedisDataType.REDIS_PROTECTED);
@@ -453,7 +456,7 @@ public class GeodeRedisServer {
   }
 
   private void checkForRegions() {
-    Collection<Entry<String, RedisDataType>> entrySet = this.regionCache.metaEntrySet();
+    Collection<Entry<String, RedisDataType>> entrySet = keyRegistrar.keyInfos();
     for (Entry<String, RedisDataType> entry : entrySet) {
       String regionName = entry.getKey();
       RedisDataType type = entry.getValue();
@@ -525,7 +528,8 @@ public class GeodeRedisServer {
             ChannelPipeline p = ch.pipeline();
             p.addLast(ByteToCommandDecoder.class.getSimpleName(), new ByteToCommandDecoder());
             p.addLast(ExecutionHandlerContext.class.getSimpleName(),
-                new ExecutionHandlerContext(ch, cache, regionCache, GeodeRedisServer.this, pwdB));
+                new ExecutionHandlerContext(ch, cache, regionCache, GeodeRedisServer.this, pwdB,
+                    keyRegistrar));
           }
         }).option(ChannelOption.SO_REUSEADDR, true).option(ChannelOption.SO_RCVBUF, getBufferSize())
         .childOption(ChannelOption.SO_KEEPALIVE, true)
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/ExecutionHandlerContext.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/ExecutionHandlerContext.java
index 628b294..be06572 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/ExecutionHandlerContext.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/ExecutionHandlerContext.java
@@ -81,6 +81,12 @@ public class ExecutionHandlerContext extends ChannelInboundHandlerAdapter {
 
   private boolean isAuthenticated;
 
+  public KeyRegistrar getKeyRegistrar() {
+    return keyRegistrar;
+  }
+
+  private KeyRegistrar keyRegistrar;
+
   /**
    * Default constructor for execution contexts.
    *
@@ -92,7 +98,8 @@ public class ExecutionHandlerContext extends ChannelInboundHandlerAdapter {
    * @param pwd Authentication password for each context, can be null
    */
   public ExecutionHandlerContext(Channel ch, Cache cache, RegionProvider regionProvider,
-      GeodeRedisServer server, byte[] pwd) {
+      GeodeRedisServer server, byte[] pwd, KeyRegistrar keyRegistrar) {
+    this.keyRegistrar = keyRegistrar;
     if (ch == null || cache == null || regionProvider == null || server == null)
       throw new IllegalArgumentException("Only the authentication password may be null");
     this.cache = cache;
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/KeyRegistrar.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/KeyRegistrar.java
new file mode 100644
index 0000000..caeba25
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/KeyRegistrar.java
@@ -0,0 +1,94 @@
+/*
+ * 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;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.geode.cache.Region;
+
+public class KeyRegistrar {
+  private Region<String, RedisDataType> redisMetaRegion;
+
+  public KeyRegistrar(Region<String, RedisDataType> redisMetaRegion) {
+    this.redisMetaRegion = redisMetaRegion;
+  }
+
+  /**
+   * Checks if the givenKey is associated with the passed data type. If an entry doesn't exist,
+   * store the key:datatype association in the metadataRegion
+   */
+  public void register(ByteArrayWrapper key, RedisDataType type) {
+    RedisDataType existingType = this.redisMetaRegion.putIfAbsent(key.toString(), type);
+    if (!isValidDataType(existingType, type)) {
+      throwDataTypeException(key, existingType);
+    }
+  }
+
+  public boolean unregister(ByteArrayWrapper key) {
+    return this.redisMetaRegion.remove(key.toString()) != null;
+  }
+
+  public boolean isRegistered(ByteArrayWrapper key) {
+    return this.redisMetaRegion.containsKey(key.toString());
+  }
+
+  public Set<String> keys() {
+    Set<String> keysWithProtected = this.redisMetaRegion.keySet();
+    return keysWithProtected;
+  }
+
+  public Set<Map.Entry<String, RedisDataType>> keyInfos() {
+    return this.redisMetaRegion.entrySet();
+  }
+
+  public int numKeys() {
+    return this.redisMetaRegion.size() - RedisConstants.NUM_DEFAULT_KEYS;
+  }
+
+  public RedisDataType getType(ByteArrayWrapper key) {
+    return this.redisMetaRegion.get(key.toString());
+  }
+
+  /**
+   * Checks if the given key is associated with the passed data type. If there is a mismatch, a
+   * {@link RuntimeException} is thrown
+   *
+   * @param key Key to check
+   * @param type Type to check to
+   */
+  public void validate(ByteArrayWrapper key, RedisDataType type) {
+    RedisDataType currentType = redisMetaRegion.get(key.toString());
+    if (!isValidDataType(currentType, type)) {
+      throwDataTypeException(key, currentType);
+    }
+  }
+
+  private boolean isValidDataType(RedisDataType actualDataType, RedisDataType expectedDataType) {
+    return isKeyUnused(actualDataType) || actualDataType == expectedDataType;
+  }
+
+  private boolean isKeyUnused(RedisDataType dataType) {
+    return dataType == null;
+  }
+
+  private void throwDataTypeException(ByteArrayWrapper key, RedisDataType dataType) {
+    if (dataType == RedisDataType.REDIS_PROTECTED)
+      throw new RedisDataTypeMismatchException("The key name \"" + key + "\" is protected");
+    else
+      throw new RedisDataTypeMismatchException(
+          "The key name \"" + key + "\" is already used by a " + dataType.toString());
+  }
+}
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/RegionProvider.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/RegionProvider.java
index c1e96e4..9e37eb9 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/RegionProvider.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/RegionProvider.java
@@ -18,7 +18,6 @@ import java.io.Closeable;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ScheduledExecutorService;
@@ -64,7 +63,7 @@ public class RegionProvider implements Closeable {
    * all Regions created. The mapping is a {@link String} key which is the name of the
    * {@link Region} created to hold the data to the RedisDataType it contains.
    */
-  private final Region<String, RedisDataType> redisMetaRegion;
+  private final KeyRegistrar keyRegistrar;
 
   /**
    * This is the {@link RedisDataType#REDIS_STRING} {@link Region}. This is the Region that stores
@@ -91,7 +90,7 @@ public class RegionProvider implements Closeable {
 
   public RegionProvider(Region<ByteArrayWrapper, ByteArrayWrapper> stringsRegion,
       Region<ByteArrayWrapper, HyperLogLogPlus> hLLRegion,
-      Region<String, RedisDataType> redisMetaRegion,
+      KeyRegistrar redisMetaRegion,
       ConcurrentMap<ByteArrayWrapper, ScheduledFuture<?>> expirationsMap,
       ScheduledExecutorService expirationExecutor, RegionShortcut defaultShortcut) {
     if (stringsRegion == null || hLLRegion == null || redisMetaRegion == null)
@@ -99,7 +98,7 @@ public class RegionProvider implements Closeable {
     this.regions = new ConcurrentHashMap<>();
     this.stringsRegion = stringsRegion;
     this.hLLRegion = hLLRegion;
-    this.redisMetaRegion = redisMetaRegion;
+    this.keyRegistrar = redisMetaRegion;
     this.cache = GemFireCacheImpl.getInstance();
     this.queryService = cache.getQueryService();
     this.expirationsMap = expirationsMap;
@@ -108,38 +107,6 @@ public class RegionProvider implements Closeable {
     this.locks = new ConcurrentHashMap<>();
   }
 
-  public boolean existsKey(ByteArrayWrapper key) {
-    return this.redisMetaRegion.containsKey(key.toString());
-  }
-
-  public Set<String> metaKeySet() {
-    return this.redisMetaRegion.keySet();
-  }
-
-  public Set<Map.Entry<String, RedisDataType>> metaEntrySet() {
-    return this.redisMetaRegion.entrySet();
-  }
-
-  public int getMetaSize() {
-    return this.redisMetaRegion.size() - RedisConstants.NUM_DEFAULT_KEYS;
-  }
-
-  private boolean metaRemoveEntry(ByteArrayWrapper key) {
-    return this.redisMetaRegion.remove(key.toString()) != null;
-  }
-
-  public RedisDataType metaPutIfAbsent(ByteArrayWrapper key, RedisDataType value) {
-    return this.redisMetaRegion.putIfAbsent(key.toString(), value);
-  }
-
-  public RedisDataType metaPut(ByteArrayWrapper key, RedisDataType value) {
-    return this.redisMetaRegion.put(key.toString(), value);
-  }
-
-  public RedisDataType metaGet(ByteArrayWrapper key) {
-    return this.redisMetaRegion.get(key.toString());
-  }
-
   public Region<?, ?> getRegion(ByteArrayWrapper key) {
     return this.regions.get(key);
   }
@@ -163,7 +130,7 @@ public class RegionProvider implements Closeable {
   }
 
   public boolean removeKey(ByteArrayWrapper key) {
-    RedisDataType type = getRedisDataType(key);
+    RedisDataType type = this.keyRegistrar.getType(key);
     return removeKey(key, type);
   }
 
@@ -179,7 +146,7 @@ public class RegionProvider implements Closeable {
       if (lock != null) {// Strings/hlls will not have locks
         lock.lock();
       }
-      metaRemoveEntry(key);
+      this.keyRegistrar.unregister(key);
       try {
         if (type == RedisDataType.REDIS_STRING) {
           return this.stringsRegion.remove(key) != null;
@@ -257,7 +224,7 @@ public class RegionProvider implements Closeable {
 
   private Region<?, ?> getOrCreateRegion0(ByteArrayWrapper key, RedisDataType type,
       ExecutionHandlerContext context, boolean addToMeta) {
-    checkDataType(key, type);
+    this.keyRegistrar.validate(key, type);
     Region<?, ?> r = this.regions.get(key);
     if (r != null && r.isDestroyed()) {
       removeKey(key, type);
@@ -306,10 +273,7 @@ public class RegionProvider implements Closeable {
             } while (concurrentCreateDestroyException != null);
             this.regions.put(key, r);
             if (addToMeta) {
-              RedisDataType existingType = metaPutIfAbsent(key, type);
-              if (existingType != null && existingType != type)
-                throw new RedisDataTypeMismatchException(
-                    "The key name \"" + key + "\" is already used by a " + existingType.toString());
+              this.keyRegistrar.register(key, type);
             }
           } finally {
             if (hasTransaction)
@@ -424,24 +388,6 @@ public class RegionProvider implements Closeable {
     return this.preparedQueries.get(key).get(query);
   }
 
-  /**
-   * Checks if the given key is associated with the passed data type. If there is a mismatch, a
-   * {@link RuntimeException} is thrown
-   *
-   * @param key Key to check
-   * @param type Type to check to
-   */
-  protected void checkDataType(ByteArrayWrapper key, RedisDataType type) {
-    RedisDataType currentType = redisMetaRegion.get(key.toString());
-    if (currentType == null)
-      return;
-    if (currentType == RedisDataType.REDIS_PROTECTED)
-      throw new RedisDataTypeMismatchException("The key name \"" + key + "\" is protected");
-    if (currentType != type)
-      throw new RedisDataTypeMismatchException(
-          "The key name \"" + key + "\" is already used by a " + currentType.toString());
-  }
-
   public boolean regionExists(ByteArrayWrapper key) {
     return this.regions.containsKey(key);
   }
@@ -454,14 +400,6 @@ public class RegionProvider implements Closeable {
     return this.hLLRegion;
   }
 
-  private RedisDataType getRedisDataType(String key) {
-    return this.redisMetaRegion.get(key);
-  }
-
-  public RedisDataType getRedisDataType(ByteArrayWrapper key) {
-    return getRedisDataType(key.toString());
-  }
-
   /**
    * Sets the expiration for a key. The setting and modifying of a key expiration can only be set by
    * a delay, which means that both expiring after a time and at a time can be done but the delay to
@@ -473,7 +411,7 @@ public class RegionProvider implements Closeable {
    * @return True is expiration set, false otherwise
    */
   public boolean setExpiration(ByteArrayWrapper key, long delay) {
-    RedisDataType type = getRedisDataType(key);
+    RedisDataType type = this.keyRegistrar.getType(key);
     if (type == null)
       return false;
     ScheduledFuture<?> future = this.expirationExecutor
@@ -498,7 +436,7 @@ public class RegionProvider implements Closeable {
     if (!canceled)
       return false;
 
-    RedisDataType type = getRedisDataType(key);
+    RedisDataType type = this.keyRegistrar.getType(key);
     if (type == null)
       return false;
 
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/AbstractExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/AbstractExecutor.java
index dfe0668..f36e265 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/AbstractExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/AbstractExecutor.java
@@ -29,7 +29,6 @@ import org.apache.geode.redis.internal.ExecutionHandlerContext;
 import org.apache.geode.redis.internal.Executor;
 import org.apache.geode.redis.internal.RedisConstants;
 import org.apache.geode.redis.internal.RedisDataType;
-import org.apache.geode.redis.internal.RedisDataTypeMismatchException;
 import org.apache.geode.redis.internal.RegionProvider;
 
 /**
@@ -77,23 +76,17 @@ public abstract class AbstractExecutor implements Executor {
   }
 
   /**
-   * Checks if the given key is associated with the passed data type. If there is a mismatch, a
+   * Checks if the given key is associated with the passed expectedDataType. If there is a mismatch,
+   * a
    * {@link RuntimeException} is thrown
    *
    * @param key Key to check
-   * @param type Type to check to
+   * @param expectedDataType Type to check to
    * @param context context
    */
-  protected void checkDataType(ByteArrayWrapper key, RedisDataType type,
+  protected void checkDataType(ByteArrayWrapper key, RedisDataType expectedDataType,
       ExecutionHandlerContext context) {
-    RedisDataType currentType = context.getRegionProvider().getRedisDataType(key);
-    if (currentType == null)
-      return;
-    if (currentType == RedisDataType.REDIS_PROTECTED)
-      throw new RedisDataTypeMismatchException("The key name \"" + key + "\" is protected");
-    if (currentType != type)
-      throw new RedisDataTypeMismatchException(
-          "The key name \"" + key + "\" is already used by a " + currentType.toString());
+    context.getKeyRegistrar().validate(key, expectedDataType);
   }
 
   protected Query getQuery(ByteArrayWrapper key, Enum<?> type, ExecutionHandlerContext context) {
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/DBSizeExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/DBSizeExecutor.java
index 0a121cc..52bf769 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/DBSizeExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/DBSizeExecutor.java
@@ -22,7 +22,7 @@ public class DBSizeExecutor extends AbstractExecutor {
 
   @Override
   public void executeCommand(Command command, ExecutionHandlerContext context) {
-    int size = context.getRegionProvider().getMetaSize();
+    int size = context.getKeyRegistrar().numKeys();
     command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), size));
   }
 
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/DelExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/DelExecutor.java
index e0db651..209f7e6 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/DelExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/DelExecutor.java
@@ -42,7 +42,7 @@ public class DelExecutor extends AbstractExecutor {
     for (int i = 1; i < commandElems.size(); i++) {
       byte[] byteKey = commandElems.get(i);
       ByteArrayWrapper key = new ByteArrayWrapper(byteKey);
-      RedisDataType type = context.getRegionProvider().getRedisDataType(key);
+      RedisDataType type = context.getKeyRegistrar().getType(key);
       if (removeEntry(key, type, context))
         numRemoved++;
     }
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExistsExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExistsExecutor.java
index 96611dc..070e2e3 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExistsExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExistsExecutor.java
@@ -36,7 +36,7 @@ public class ExistsExecutor extends AbstractExecutor {
     }
 
     ByteArrayWrapper key = command.getKey();
-    boolean exists = context.getRegionProvider().existsKey(key);
+    boolean exists = context.getKeyRegistrar().isRegistered(key);
 
     if (exists)
       command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), EXISTS));
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/FlushAllExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/FlushAllExecutor.java
index f855166..43ad260 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/FlushAllExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/FlushAllExecutor.java
@@ -30,7 +30,7 @@ public class FlushAllExecutor extends AbstractExecutor {
     if (context.hasTransaction())
       throw new UnsupportedOperationInTransactionException();
 
-    for (Entry<String, RedisDataType> e : context.getRegionProvider().metaEntrySet()) {
+    for (Entry<String, RedisDataType> e : context.getKeyRegistrar().keyInfos()) {
       try {
         String skey = e.getKey();
         RedisDataType type = e.getValue();
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/KeysExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/KeysExecutor.java
index c4466fc..aa14d55 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/KeysExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/KeysExecutor.java
@@ -39,7 +39,7 @@ public class KeysExecutor extends AbstractExecutor {
     }
 
     String glob = Coder.bytesToString(commandElems.get(1));
-    Set<String> allKeys = context.getRegionProvider().metaKeySet();
+    Set<String> allKeys = context.getKeyRegistrar().keys();
     List<String> matchingKeys = new ArrayList<String>();
 
     Pattern pattern;
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ScanExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ScanExecutor.java
index 393f24b..d50947c 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ScanExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ScanExecutor.java
@@ -99,7 +99,7 @@ public class ScanExecutor extends AbstractScanExecutor {
     }
 
     @SuppressWarnings("unchecked")
-    List<String> returnList = (List<String>) getIteration(context.getRegionProvider().metaKeySet(),
+    List<String> returnList = (List<String>) getIteration(context.getKeyRegistrar().keys(),
         matchPattern, count, cursor);
 
     command.setResponse(Coder.getScanResponse(context.getByteBufAllocator(), returnList));
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TTLExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TTLExecutor.java
index 530e96a..c89a645 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TTLExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TTLExecutor.java
@@ -43,7 +43,7 @@ public class TTLExecutor extends AbstractExecutor implements Extendable {
     ByteArrayWrapper key = command.getKey();
     RegionProvider rC = context.getRegionProvider();
     boolean exists = false;
-    RedisDataType val = rC.getRedisDataType(key);
+    RedisDataType val = context.getKeyRegistrar().getType(key);
     if (val != null)
       exists = true;
 
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TypeExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TypeExecutor.java
index c42fd62..1091c39 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TypeExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TypeExecutor.java
@@ -35,7 +35,7 @@ public class TypeExecutor extends AbstractExecutor {
 
     ByteArrayWrapper key = command.getKey();
 
-    RedisDataType type = context.getRegionProvider().getRedisDataType(key);
+    RedisDataType type = context.getKeyRegistrar().getType(key);
     if (type == null)
       respondBulkStrings(command, context, "none");
     else
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hll/HllExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hll/HllExecutor.java
index c1b0488..9839452 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hll/HllExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hll/HllExecutor.java
@@ -17,7 +17,6 @@ package org.apache.geode.redis.internal.executor.hll;
 import org.apache.geode.redis.internal.ByteArrayWrapper;
 import org.apache.geode.redis.internal.ExecutionHandlerContext;
 import org.apache.geode.redis.internal.RedisDataType;
-import org.apache.geode.redis.internal.RedisDataTypeMismatchException;
 import org.apache.geode.redis.internal.executor.AbstractExecutor;
 
 public abstract class HllExecutor extends AbstractExecutor {
@@ -27,11 +26,7 @@ public abstract class HllExecutor extends AbstractExecutor {
   public static final Integer DEFAULT_HLL_SPARSE = 32;
 
   protected void checkAndSetDataType(ByteArrayWrapper key, ExecutionHandlerContext context) {
-    Object oldVal = context.getRegionProvider().metaPutIfAbsent(key, RedisDataType.REDIS_HLL);
-    if (oldVal == RedisDataType.REDIS_PROTECTED)
-      throw new RedisDataTypeMismatchException("The key name \"" + key + "\" is protected");
-    if (oldVal != null && oldVal != RedisDataType.REDIS_HLL)
-      throw new RedisDataTypeMismatchException(
-          "The key name \"" + key + "\" is already used by a " + oldVal.toString());
+    context.getKeyRegistrar().register(key, RedisDataType.REDIS_HLL);
+
   }
 }
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/BitOpExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/BitOpExecutor.java
index 49f0f5c..f5a8e72 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/BitOpExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/BitOpExecutor.java
@@ -22,6 +22,7 @@ import org.apache.geode.redis.internal.Coder;
 import org.apache.geode.redis.internal.Command;
 import org.apache.geode.redis.internal.ExecutionHandlerContext;
 import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+import org.apache.geode.redis.internal.RedisDataType;
 
 public class BitOpExecutor extends StringExecutor {
 
@@ -40,13 +41,13 @@ public class BitOpExecutor extends StringExecutor {
 
     String operation = command.getStringKey().toUpperCase();
     ByteArrayWrapper destKey = new ByteArrayWrapper(commandElems.get(2));
-    checkDataType(destKey, context);
+    checkDataType(destKey, RedisDataType.REDIS_STRING, context);
 
     byte[][] values = new byte[commandElems.size() - 3][];
     int maxLength = 0;
     for (int i = 3; i < commandElems.size(); i++) {
       ByteArrayWrapper key = new ByteArrayWrapper(commandElems.get(i));
-      checkDataType(key, context);
+      checkDataType(key, RedisDataType.REDIS_STRING, context);
       ByteArrayWrapper value = r.get(key);
       if (value == null) {
         values[i - 3] = null;
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/DecrExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/DecrExecutor.java
index c1287dc..ff914b4 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/DecrExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/DecrExecutor.java
@@ -22,7 +22,6 @@ import org.apache.geode.redis.internal.Coder;
 import org.apache.geode.redis.internal.Command;
 import org.apache.geode.redis.internal.ExecutionHandlerContext;
 import org.apache.geode.redis.internal.RedisConstants.ArityDef;
-import org.apache.geode.redis.internal.RedisDataType;
 import org.apache.geode.redis.internal.RegionProvider;
 
 public class DecrExecutor extends StringExecutor {
@@ -59,7 +58,6 @@ public class DecrExecutor extends StringExecutor {
     if (valueWrapper == null) {
       byte[] newValue = INIT_VALUE_BYTES;
       r.put(key, new ByteArrayWrapper(newValue));
-      rC.metaPut(key, RedisDataType.REDIS_STRING);
       command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), INIT_VALUE_INT));
       return;
     }
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/MSetNXExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/MSetNXExecutor.java
index 2928662..c7a036b 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/MSetNXExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/MSetNXExecutor.java
@@ -24,6 +24,7 @@ import org.apache.geode.redis.internal.Coder;
 import org.apache.geode.redis.internal.Command;
 import org.apache.geode.redis.internal.ExecutionHandlerContext;
 import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+import org.apache.geode.redis.internal.RedisDataType;
 import org.apache.geode.redis.internal.RedisDataTypeMismatchException;
 
 public class MSetNXExecutor extends StringExecutor {
@@ -50,7 +51,7 @@ public class MSetNXExecutor extends StringExecutor {
       byte[] keyArray = commandElems.get(i);
       ByteArrayWrapper key = new ByteArrayWrapper(keyArray);
       try {
-        checkDataType(key, context);
+        checkDataType(key, RedisDataType.REDIS_STRING, context);
       } catch (RedisDataTypeMismatchException e) {
         hasEntry = true;
         break;
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/SetExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/SetExecutor.java
index f82a4b7..bdb9007 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/SetExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/SetExecutor.java
@@ -22,6 +22,7 @@ import org.apache.geode.redis.internal.Coder;
 import org.apache.geode.redis.internal.Command;
 import org.apache.geode.redis.internal.ExecutionHandlerContext;
 import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+import org.apache.geode.redis.internal.RedisDataType;
 import org.apache.geode.redis.internal.executor.AbstractExecutor;
 
 public class SetExecutor extends StringExecutor {
@@ -42,7 +43,7 @@ public class SetExecutor extends StringExecutor {
     }
 
     ByteArrayWrapper key = command.getKey();
-    checkDataType(key, context);
+    checkDataType(key, RedisDataType.REDIS_STRING, context);
     byte[] value = commandElems.get(VALUE_INDEX);
     ByteArrayWrapper valueWrapper = new ByteArrayWrapper(value);
 
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/StringExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/StringExecutor.java
index eb17e41..08cc0eb 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/StringExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/StringExecutor.java
@@ -17,29 +17,11 @@ package org.apache.geode.redis.internal.executor.string;
 import org.apache.geode.redis.internal.ByteArrayWrapper;
 import org.apache.geode.redis.internal.ExecutionHandlerContext;
 import org.apache.geode.redis.internal.RedisDataType;
-import org.apache.geode.redis.internal.RedisDataTypeMismatchException;
 import org.apache.geode.redis.internal.executor.AbstractExecutor;
 
 public abstract class StringExecutor extends AbstractExecutor {
 
   protected void checkAndSetDataType(ByteArrayWrapper key, ExecutionHandlerContext context) {
-    Object oldVal = context.getRegionProvider().metaPutIfAbsent(key, RedisDataType.REDIS_STRING);
-    if (oldVal == RedisDataType.REDIS_PROTECTED)
-      throw new RedisDataTypeMismatchException("The key name \"" + key + "\" is protected");
-    if (oldVal != null && oldVal != RedisDataType.REDIS_STRING)
-      throw new RedisDataTypeMismatchException(
-          "The key name \"" + key + "\" is already used by a " + oldVal.toString());
+    context.getKeyRegistrar().register(key, RedisDataType.REDIS_STRING);
   }
-
-  protected void checkDataType(ByteArrayWrapper key, ExecutionHandlerContext context) {
-    RedisDataType currentType = context.getRegionProvider().getRedisDataType(key);
-    if (currentType == null)
-      return;
-    if (currentType == RedisDataType.REDIS_PROTECTED)
-      throw new RedisDataTypeMismatchException("The key name \"" + key + "\" is protected");
-    if (currentType != RedisDataType.REDIS_STRING)
-      throw new RedisDataTypeMismatchException(
-          "The key name \"" + key + "\" is already used by a " + currentType.toString());
-  }
-
 }