geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From u..@apache.org
Subject [05/21] geode git commit: GEODE-2449: Moved Redis out of core with minimal Extension work added
Date Fri, 10 Feb 2017 21:34:08 GMT
http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRangeByScoreExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRangeByScoreExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRangeByScoreExecutor.java
new file mode 100644
index 0000000..8d0ecb2
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRangeByScoreExecutor.java
@@ -0,0 +1,214 @@
+/*
+ * 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.sortedset;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.query.FunctionDomainException;
+import org.apache.geode.cache.query.NameResolutionException;
+import org.apache.geode.cache.query.Query;
+import org.apache.geode.cache.query.QueryInvocationTargetException;
+import org.apache.geode.cache.query.SelectResults;
+import org.apache.geode.cache.query.Struct;
+import org.apache.geode.cache.query.TypeMismatchException;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.DoubleWrapper;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.Extendable;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+import org.apache.geode.redis.internal.RedisDataType;
+import org.apache.geode.redis.internal.executor.SortedSetQuery;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+
+public class ZRangeByScoreExecutor extends SortedSetExecutor implements Extendable {
+
+  private final String ERROR_NOT_NUMERIC = "The number provided is not numeric";
+
+  private final String ERROR_LIMIT = "The offset and count cannot be negative";
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 4) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), getArgsError()));
+      return;
+    }
+
+    boolean withScores = false;
+    byte[] elem4Array = null;
+    int offset = 0;
+    int limit = -1;
+    if (commandElems.size() >= 5) {
+      elem4Array = commandElems.get(4);
+      String elem4 = Coder.bytesToString(elem4Array);
+      int limitIndex = 4;
+      if (elem4.equalsIgnoreCase("WITHSCORES")) {
+        withScores = true;
+        limitIndex++;
+      }
+
+      if (commandElems.size() >= limitIndex + 2) {
+        String limitString = Coder.bytesToString(commandElems.get(limitIndex));
+        if (limitString.equalsIgnoreCase("LIMIT")) {
+          try {
+            byte[] offsetArray = commandElems.get(limitIndex + 1);
+            byte[] limitArray = commandElems.get(limitIndex + 2);
+            offset = Coder.bytesToInt(offsetArray);
+            limit = Coder.bytesToInt(limitArray);
+          } catch (NumberFormatException e) {
+            command.setResponse(
+                Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_NOT_NUMERIC));
+            return;
+          }
+        }
+
+        if (offset < 0 || limit < 0) {
+          command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_LIMIT));
+          return;
+        }
+
+        if (limitIndex == 4 && commandElems.size() >= 8) {
+          byte[] lastElemArray = commandElems.get(7);
+          String lastString = Coder.bytesToString(lastElemArray);
+          if (lastString.equalsIgnoreCase("WITHSCORES")) {
+            withScores = true;
+          }
+        }
+      }
+
+    }
+
+    ByteArrayWrapper key = command.getKey();
+
+    checkDataType(key, RedisDataType.REDIS_SORTEDSET, context);
+    Region<ByteArrayWrapper, DoubleWrapper> keyRegion = getRegion(context, key);
+
+    if (keyRegion == null) {
+      command.setResponse(Coder.getEmptyArrayResponse(context.getByteBufAllocator()));
+      return;
+    }
+
+    int startIndex = isReverse() ? 3 : 2;
+    int stopIndex = isReverse() ? 2 : 3;
+    boolean startInclusive = true;
+    boolean stopInclusive = true;
+    double start;
+    double stop;
+
+    byte[] startArray = commandElems.get(startIndex);
+    byte[] stopArray = commandElems.get(stopIndex);
+    String startString = Coder.bytesToString(startArray);
+    String stopString = Coder.bytesToString(stopArray);
+
+    if (startArray[0] == Coder.OPEN_BRACE_ID) {
+      startString = startString.substring(1);
+      startInclusive = false;
+    }
+    if (stopArray[0] == Coder.OPEN_BRACE_ID) {
+      stopString = stopString.substring(1);
+      stopInclusive = false;
+    }
+
+    try {
+      start = Coder.stringToDouble(startString);
+      stop = Coder.stringToDouble(stopString);
+    } catch (NumberFormatException e) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_NOT_NUMERIC));
+      return;
+    }
+
+    Collection<?> list;
+    try {
+      list = getKeys(key, keyRegion, context, start, stop, startInclusive, stopInclusive, offset,
+          limit);
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+
+    if (list == null)
+      command.setResponse(Coder.getEmptyArrayResponse(context.getByteBufAllocator()));
+    else
+      command.setResponse(Coder.zRangeResponse(context.getByteBufAllocator(), list, withScores));
+  }
+
+  private Collection<?> getKeys(ByteArrayWrapper key,
+      Region<ByteArrayWrapper, DoubleWrapper> keyRegion, ExecutionHandlerContext context,
+      double start, double stop, boolean startInclusive, boolean stopInclusive, int offset,
+      int limit) throws FunctionDomainException, TypeMismatchException, NameResolutionException,
+      QueryInvocationTargetException {
+    if (start == Double.POSITIVE_INFINITY || stop == Double.NEGATIVE_INFINITY || start > stop
+        || (start == stop && (!startInclusive || !stopInclusive)))
+      return null;
+    if (start == Double.NEGATIVE_INFINITY && stop == Double.POSITIVE_INFINITY)
+      return new HashSet(keyRegion.entrySet());
+
+    Query query;
+    Object[] params;
+    if (isReverse()) {
+      if (startInclusive) {
+        if (stopInclusive) {
+          query = getQuery(key, SortedSetQuery.ZREVRBSSTISI, context);
+        } else {
+          query = getQuery(key, SortedSetQuery.ZREVRBSSTI, context);
+        }
+      } else {
+        if (stopInclusive) {
+          query = getQuery(key, SortedSetQuery.ZREVRBSSI, context);
+        } else {
+          query = getQuery(key, SortedSetQuery.ZREVRBS, context);
+        }
+      }
+      params = new Object[] {start, stop, INFINITY_LIMIT};
+    } else {
+      if (startInclusive) {
+        if (stopInclusive) {
+          query = getQuery(key, SortedSetQuery.ZRBSSTISI, context);
+        } else {
+          query = getQuery(key, SortedSetQuery.ZRBSSTI, context);
+        }
+      } else {
+        if (stopInclusive) {
+          query = getQuery(key, SortedSetQuery.ZRBSSI, context);
+        } else {
+          query = getQuery(key, SortedSetQuery.ZRBS, context);
+        }
+      }
+      params = new Object[] {start, stop, INFINITY_LIMIT};
+    }
+    if (limit > 0)
+      params[params.length - 1] = (limit + offset);
+
+    SelectResults<?> results = (SelectResults<?>) query.execute(params);
+    if (offset < results.size())
+      return (Collection<Struct>) results.asList().subList(offset, results.size());
+    else
+      return null;
+  }
+
+  protected boolean isReverse() {
+    return false;
+  }
+
+  @Override
+  public String getArgsError() {
+    return ArityDef.ZRANGEBYSCORE;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRangeExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRangeExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRangeExecutor.java
new file mode 100644
index 0000000..d316faa
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRangeExecutor.java
@@ -0,0 +1,124 @@
+/*
+ * 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.sortedset;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.query.Query;
+import org.apache.geode.cache.query.SelectResults;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.DoubleWrapper;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.Extendable;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+import org.apache.geode.redis.internal.RedisDataType;
+import org.apache.geode.redis.internal.executor.SortedSetQuery;
+
+import java.util.List;
+
+public class ZRangeExecutor extends SortedSetExecutor implements Extendable {
+
+  private final String ERROR_NOT_NUMERIC = "The index provided is not numeric";
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 4) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), getArgsError()));
+      return;
+    }
+
+    boolean withScores = false;
+
+    if (commandElems.size() >= 5) {
+      byte[] fifthElem = commandElems.get(4);
+      withScores = Coder.bytesToString(fifthElem).equalsIgnoreCase("WITHSCORES");
+
+    }
+
+    ByteArrayWrapper key = command.getKey();
+
+    checkDataType(key, RedisDataType.REDIS_SORTEDSET, context);
+    Region<ByteArrayWrapper, DoubleWrapper> keyRegion = getRegion(context, key);
+
+    if (keyRegion == null) {
+      command.setResponse(Coder.getEmptyArrayResponse(context.getByteBufAllocator()));
+      return;
+    }
+
+
+    int start;
+    int stop;
+    int sSetSize = keyRegion.size();
+
+    try {
+      byte[] startArray = commandElems.get(2);
+      byte[] stopArray = commandElems.get(3);
+      start = Coder.bytesToInt(startArray);
+      stop = Coder.bytesToInt(stopArray);
+    } catch (NumberFormatException e) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_NOT_NUMERIC));
+      return;
+    }
+
+    start = getBoundedStartIndex(start, sSetSize);
+    stop = getBoundedEndIndex(stop, sSetSize);
+
+    if (start > stop || start == sSetSize) {
+      command.setResponse(Coder.getEmptyArrayResponse(context.getByteBufAllocator()));
+      return;
+    }
+    if (stop == sSetSize)
+      stop--;
+    List<?> list;
+    try {
+      list = getRange(context, key, start, stop);
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+
+    command.setResponse(Coder.zRangeResponse(context.getByteBufAllocator(), list, withScores));
+  }
+
+  private List<?> getRange(ExecutionHandlerContext context, ByteArrayWrapper key, int start,
+      int stop) throws Exception {
+    Query query;
+
+    if (isReverse())
+      query = getQuery(key, SortedSetQuery.ZRANGE, context);
+    else
+      query = getQuery(key, SortedSetQuery.ZREVRANGE, context);
+
+    Object[] params = {stop + 1};
+
+    SelectResults<?> results = (SelectResults<?>) query.execute(params);
+
+    List<?> list = results.asList();
+
+    return list.subList(start, stop + 1);
+
+  }
+
+  protected boolean isReverse() {
+    return false;
+  }
+
+  @Override
+  public String getArgsError() {
+    return ArityDef.ZRANGE;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRankExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRankExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRankExecutor.java
new file mode 100644
index 0000000..d3b6bee
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRankExecutor.java
@@ -0,0 +1,97 @@
+/*
+ * 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.sortedset;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.query.Query;
+import org.apache.geode.cache.query.SelectResults;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.DoubleWrapper;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.Extendable;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+import org.apache.geode.redis.internal.RedisDataType;
+import org.apache.geode.redis.internal.executor.SortedSetQuery;
+
+import java.util.List;
+
+public class ZRankExecutor extends SortedSetExecutor implements Extendable {
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 3) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), getArgsError()));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+
+    checkDataType(key, RedisDataType.REDIS_SORTEDSET, context);
+    Region<ByteArrayWrapper, DoubleWrapper> keyRegion = getRegion(context, key);
+
+    if (keyRegion == null) {
+      command.setResponse(Coder.getNilResponse(context.getByteBufAllocator()));
+      return;
+    }
+
+    ByteArrayWrapper member = new ByteArrayWrapper(commandElems.get(2));
+
+    DoubleWrapper value = keyRegion.get(member);
+
+    if (value == null) {
+      command.setResponse(Coder.getNilResponse(context.getByteBufAllocator()));
+      return;
+    }
+
+    int rank;
+    try {
+      rank = getRange(context, key, member, value);
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+
+    command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), rank));
+  }
+
+  private int getRange(ExecutionHandlerContext context, ByteArrayWrapper key,
+      ByteArrayWrapper member, DoubleWrapper valueWrapper) throws Exception {
+    Query query;
+    if (isReverse())
+      query = getQuery(key, SortedSetQuery.ZREVRANK, context);
+    else
+      query = getQuery(key, SortedSetQuery.ZRANK, context);
+
+    Object[] params = {valueWrapper.score, valueWrapper.score, member};
+
+    SelectResults<?> results = (SelectResults<?>) query.execute(params);
+
+    return (Integer) results.asList().get(0);
+
+  }
+
+  protected boolean isReverse() {
+    return false;
+  }
+
+  @Override
+  public String getArgsError() {
+    return ArityDef.ZRANK;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemExecutor.java
new file mode 100644
index 0000000..93e0c32
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemExecutor.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.executor.sortedset;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.DoubleWrapper;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+import org.apache.geode.redis.internal.RedisDataType;
+
+import java.util.List;
+
+public class ZRemExecutor extends SortedSetExecutor {
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 3) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.ZREM));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+
+    checkDataType(key, RedisDataType.REDIS_SORTEDSET, context);
+    Region<ByteArrayWrapper, DoubleWrapper> keyRegion = getRegion(context, key);
+
+    if (keyRegion == null) {
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), 0));
+      return;
+    }
+
+    int numDeletedMembers = 0;
+
+    for (int i = 2; i < commandElems.size(); i++) {
+      byte[] memberArray = commandElems.get(i);
+      ByteArrayWrapper member = new ByteArrayWrapper(memberArray);
+      Object oldVal = keyRegion.remove(member);
+      if (oldVal != null)
+        numDeletedMembers++;
+    }
+    if (keyRegion.isEmpty())
+      context.getRegionProvider().removeKey(key);
+    command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), numDeletedMembers));
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByLexExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByLexExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByLexExecutor.java
new file mode 100644
index 0000000..73f380b
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByLexExecutor.java
@@ -0,0 +1,161 @@
+/*
+ * 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.sortedset;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.query.Query;
+import org.apache.geode.cache.query.SelectResults;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.DoubleWrapper;
+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.SortedSetQuery;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public class ZRemRangeByLexExecutor extends SortedSetExecutor {
+
+  private final int ERROR_NOT_EXISTS = 0;
+
+  private final String ERROR_ILLEGAL_SYNTAX =
+      "The min and max strings must either start with a (, [ or be - or +";
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 4) {
+      command.setResponse(
+          Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.ZREMRANGEBYLEX));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+
+    checkDataType(key, RedisDataType.REDIS_SORTEDSET, context);
+    Region<ByteArrayWrapper, DoubleWrapper> keyRegion = getRegion(context, key);
+
+    if (keyRegion == null) {
+      command
+          .setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), ERROR_NOT_EXISTS));
+      return;
+    }
+
+    boolean minInclusive = false;
+    boolean maxInclusive = false;
+
+    byte[] minArray = commandElems.get(2);
+    byte[] maxArray = commandElems.get(3);
+    String startString = Coder.bytesToString(minArray);
+    String stopString = Coder.bytesToString(maxArray);
+
+    if (minArray[0] == Coder.OPEN_BRACE_ID) {
+      startString = startString.substring(1);
+      minInclusive = false;
+    } else if (minArray[0] == Coder.OPEN_BRACKET_ID) {
+      startString = startString.substring(1);
+      minInclusive = true;
+    } else if (minArray[0] != Coder.HYPHEN_ID) {
+      command
+          .setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_ILLEGAL_SYNTAX));
+      return;
+    }
+
+    if (maxArray[0] == Coder.OPEN_BRACE_ID) {
+      stopString = stopString.substring(1);
+      maxInclusive = false;
+    } else if (maxArray[0] == Coder.OPEN_BRACKET_ID) {
+      stopString = stopString.substring(1);
+      maxInclusive = true;
+    } else if (maxArray[0] != Coder.PLUS_ID) {
+      command
+          .setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_ILLEGAL_SYNTAX));
+      return;
+    }
+
+    Collection<ByteArrayWrapper> removeList;
+    try {
+      removeList = getRange(key, keyRegion, context, Coder.stringToByteArrayWrapper(startString),
+          Coder.stringToByteArrayWrapper(stopString), minInclusive, maxInclusive);
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+
+    int numRemoved = 0;
+
+    for (ByteArrayWrapper entry : removeList) {
+      Object oldVal = keyRegion.remove(entry);
+      if (oldVal != null)
+        numRemoved++;
+    }
+
+    command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), numRemoved));
+  }
+
+  private Collection<ByteArrayWrapper> getRange(ByteArrayWrapper key,
+      Region<ByteArrayWrapper, DoubleWrapper> keyRegion, ExecutionHandlerContext context,
+      ByteArrayWrapper start, ByteArrayWrapper stop, boolean startInclusive, boolean stopInclusive)
+      throws Exception {
+    if (start.equals("-") && stop.equals("+"))
+      return new ArrayList<ByteArrayWrapper>(keyRegion.keySet());
+    else if (start.equals("+") || stop.equals("-"))
+      return null;
+
+    Query query;
+    Object[] params;
+    if (start.equals("-")) {
+      if (stopInclusive) {
+        query = getQuery(key, SortedSetQuery.ZRANGEBYLEXNINFI, context);
+      } else {
+        query = getQuery(key, SortedSetQuery.ZRANGEBYLEXNINF, context);
+      }
+      params = new Object[] {stop, INFINITY_LIMIT};
+    } else if (stop.equals("+")) {
+      if (startInclusive) {
+        query = getQuery(key, SortedSetQuery.ZRANGEBYLEXPINFI, context);
+      } else {
+        query = getQuery(key, SortedSetQuery.ZRANGEBYLEXPINF, context);
+      }
+      params = new Object[] {start, INFINITY_LIMIT};
+    } else {
+      if (startInclusive) {
+        if (stopInclusive) {
+          query = getQuery(key, SortedSetQuery.ZRANGEBYLEXSTISI, context);
+        } else {
+          query = getQuery(key, SortedSetQuery.ZRANGEBYLEXSTI, context);
+        }
+      } else {
+        if (stopInclusive) {
+          query = getQuery(key, SortedSetQuery.ZRANGEBYLEXSI, context);
+        } else {
+          query = getQuery(key, SortedSetQuery.ZRANGEBYLEX, context);
+        }
+      }
+      params = new Object[] {start, stop, INFINITY_LIMIT};
+    }
+
+    @SuppressWarnings("unchecked")
+    SelectResults<ByteArrayWrapper> results =
+        (SelectResults<ByteArrayWrapper>) query.execute(params);
+
+    return results.asList();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByRankExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByRankExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByRankExecutor.java
new file mode 100644
index 0000000..abd2a96
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByRankExecutor.java
@@ -0,0 +1,121 @@
+/*
+ * 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.sortedset;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.Region.Entry;
+import org.apache.geode.cache.query.Query;
+import org.apache.geode.cache.query.SelectResults;
+import org.apache.geode.cache.query.Struct;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.DoubleWrapper;
+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.SortedSetQuery;
+
+import java.util.List;
+
+public class ZRemRangeByRankExecutor extends SortedSetExecutor {
+
+  private final int NONE_REMOVED = 0;
+
+  private final String ERROR_NOT_NUMERIC = "The index provided is not numeric";
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 4) {
+      command.setResponse(
+          Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.ZREMRANGEBYRANK));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+
+    checkDataType(key, RedisDataType.REDIS_SORTEDSET, context);
+    Region<ByteArrayWrapper, DoubleWrapper> keyRegion = getRegion(context, key);
+
+    if (keyRegion == null) {
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NONE_REMOVED));
+      return;
+    }
+
+    int startRank;
+    int stopRank;
+
+    try {
+      startRank = Coder.bytesToInt(commandElems.get(2));
+      stopRank = Coder.bytesToInt(commandElems.get(3));
+    } catch (NumberFormatException e) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_NOT_NUMERIC));
+      return;
+    }
+
+    int sSetSize = keyRegion.size();
+
+    startRank = getBoundedStartIndex(startRank, sSetSize);
+    stopRank = getBoundedEndIndex(stopRank, sSetSize);
+    if (stopRank > sSetSize - 1)
+      stopRank = sSetSize - 1;
+
+    if (startRank > stopRank) {
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), 0));
+      return;
+    }
+
+    int numRemoved = 0;
+    List<?> removeList = null;
+    try {
+      if (startRank == 0 && stopRank == sSetSize - 1) {
+        numRemoved = keyRegion.size();
+        context.getRegionProvider().removeKey(key);
+      } else {
+        removeList = getRemoveKeys(context, key, startRank, stopRank);
+      }
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+
+    if (removeList != null) {
+      for (Object entry : removeList) {
+        ByteArrayWrapper removeKey;
+        if (entry instanceof Entry)
+          removeKey = (ByteArrayWrapper) ((Entry<?, ?>) entry).getKey();
+        else
+          removeKey = (ByteArrayWrapper) ((Struct) entry).getFieldValues()[0];
+        Object oldVal = keyRegion.remove(removeKey);
+        if (oldVal != null)
+          numRemoved++;
+      }
+      if (keyRegion.isEmpty())
+        context.getRegionProvider().removeKey(key);
+    }
+    command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), numRemoved));
+  }
+
+  private List<?> getRemoveKeys(ExecutionHandlerContext context, ByteArrayWrapper key,
+      int startRank, int stopRank) throws Exception {
+    Query query = getQuery(key, SortedSetQuery.ZREMRANGEBYRANK, context);
+    Object[] params = {stopRank + 1};
+
+    SelectResults<?> results = (SelectResults<?>) query.execute(params);
+
+    return results.asList().subList(startRank, stopRank + 1);
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByScoreExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByScoreExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByScoreExecutor.java
new file mode 100644
index 0000000..514748d
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByScoreExecutor.java
@@ -0,0 +1,145 @@
+/*
+ * 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.sortedset;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.query.Query;
+import org.apache.geode.cache.query.SelectResults;
+import org.apache.geode.cache.query.Struct;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.DoubleWrapper;
+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.SortedSetQuery;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map.Entry;
+
+public class ZRemRangeByScoreExecutor extends SortedSetExecutor {
+
+  private final String ERROR_NOT_NUMERIC = "The number provided is not numeric";
+
+  private final int NOT_EXISTS = 0;
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 4) {
+      command.setResponse(
+          Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.ZREMRANGEBYSCORE));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+
+    checkDataType(key, RedisDataType.REDIS_SORTEDSET, context);
+    Region<ByteArrayWrapper, DoubleWrapper> keyRegion = getRegion(context, key);
+
+    if (keyRegion == null) {
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NOT_EXISTS));
+      return;
+    }
+
+    boolean startInclusive = true;
+    boolean stopInclusive = true;
+    double start;
+    double stop;
+
+    byte[] startArray = commandElems.get(2);
+    byte[] stopArray = commandElems.get(3);
+    String startString = Coder.bytesToString(startArray);
+    String stopString = Coder.bytesToString(stopArray);
+    if (startArray[0] == Coder.OPEN_BRACE_ID) {
+      startString = startString.substring(1);
+      startInclusive = false;
+    }
+    if (stopArray[0] == Coder.OPEN_BRACE_ID) {
+      stopString = stopString.substring(1);
+      stopInclusive = false;
+    }
+
+    try {
+      start = Coder.stringToDouble(startString);
+      stop = Coder.stringToDouble(stopString);
+    } catch (NumberFormatException e) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_NOT_NUMERIC));
+      return;
+    }
+
+    int numRemoved = 0;
+
+    Collection<?> removeList = null;
+    try {
+      if (start == Double.NEGATIVE_INFINITY && stop == Double.POSITIVE_INFINITY && startInclusive
+          && stopInclusive) {
+        numRemoved = keyRegion.size();
+        context.getRegionProvider().removeKey(key);
+      } else {
+        removeList = getKeys(context, key, keyRegion, start, stop, startInclusive, stopInclusive);
+      }
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+
+    if (removeList != null) {
+      for (Object entry : removeList) {
+        ByteArrayWrapper remove = null;
+        if (entry instanceof Entry)
+          remove = (ByteArrayWrapper) ((Entry<?, ?>) entry).getKey();
+        else if (entry instanceof Struct)
+          remove = (ByteArrayWrapper) ((Struct) entry).getFieldValues()[0];
+        Object oldVal = keyRegion.remove(remove);
+        if (oldVal != null)
+          numRemoved++;
+        if (keyRegion.isEmpty())
+          context.getRegionProvider().removeKey(key);
+      }
+    }
+    command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), numRemoved));
+  }
+
+  private Collection<?> getKeys(ExecutionHandlerContext context, ByteArrayWrapper key,
+      Region<ByteArrayWrapper, DoubleWrapper> keyRegion, double start, double stop,
+      boolean startInclusive, boolean stopInclusive) throws Exception {
+    if (start == Double.POSITIVE_INFINITY || stop == Double.NEGATIVE_INFINITY || (start > stop))
+      return null;
+
+    Query query;
+    Object[] params;
+    if (startInclusive) {
+      if (stopInclusive) {
+        query = getQuery(key, SortedSetQuery.ZRBSSTISI, context);
+      } else {
+        query = getQuery(key, SortedSetQuery.ZRBSSTI, context);
+      }
+    } else {
+      if (stopInclusive) {
+        query = getQuery(key, SortedSetQuery.ZRBSSI, context);
+      } else {
+        query = getQuery(key, SortedSetQuery.ZRBS, context);
+      }
+    }
+    params = new Object[] {start, stop, INFINITY_LIMIT};
+
+    SelectResults<?> results = (SelectResults<?>) query.execute(params);
+
+    return (Collection<?>) results.asList();
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRangeByScoreExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRangeByScoreExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRangeByScoreExecutor.java
new file mode 100644
index 0000000..652e784
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRangeByScoreExecutor.java
@@ -0,0 +1,31 @@
+/*
+ * 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.sortedset;
+
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+
+public class ZRevRangeByScoreExecutor extends ZRangeByScoreExecutor {
+
+  @Override
+  protected boolean isReverse() {
+    return true;
+  }
+
+  @Override
+  public String getArgsError() {
+    return ArityDef.ZREVRANGEBYSCORE;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRangeExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRangeExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRangeExecutor.java
new file mode 100644
index 0000000..8154570
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRangeExecutor.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.sortedset;
+
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+
+public class ZRevRangeExecutor extends ZRangeExecutor {
+
+  @Override
+  protected boolean isReverse() {
+    return true;
+  }
+
+  @Override
+  public String getArgsError() {
+    return ArityDef.ZREVRANGE;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRankExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRankExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRankExecutor.java
new file mode 100644
index 0000000..80ebfa4
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRankExecutor.java
@@ -0,0 +1,30 @@
+/*
+ * 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.sortedset;
+
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+public class ZRevRankExecutor extends ZRankExecutor {
+
+  @Override
+  protected boolean isReverse() {
+    return true;
+  }
+
+  @Override
+  public String getArgsError() {
+    return ArityDef.ZREVRANK;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZScanExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZScanExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZScanExecutor.java
new file mode 100644
index 0000000..1d50f17
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZScanExecutor.java
@@ -0,0 +1,164 @@
+/*
+ * 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.sortedset;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.DoubleWrapper;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.RedisConstants;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+import org.apache.geode.redis.internal.RedisDataType;
+import org.apache.geode.redis.internal.executor.AbstractScanExecutor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+public class ZScanExecutor extends AbstractScanExecutor {
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 3) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.ZSCAN));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+    Region<ByteArrayWrapper, DoubleWrapper> keyRegion =
+        (Region<ByteArrayWrapper, DoubleWrapper>) context.getRegionProvider().getRegion(key);
+    checkDataType(key, RedisDataType.REDIS_SORTEDSET, context);
+    if (keyRegion == null) {
+      command.setResponse(
+          Coder.getScanResponse(context.getByteBufAllocator(), new ArrayList<String>()));
+      return;
+    }
+    byte[] cAr = commandElems.get(2);
+    // String cursorString = ResponseToByteEncoder.bytesToString(cAr);
+
+    int cursor = 0;
+    Pattern matchPattern = null;
+    String globMatchPattern = null;
+    int count = DEFUALT_COUNT;
+    try {
+      cursor = Coder.bytesToInt(cAr);
+    } catch (NumberFormatException e) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_CURSOR));
+      return;
+    }
+    if (cursor < 0) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_CURSOR));
+      return;
+    }
+
+    if (commandElems.size() > 4) {
+      try {
+        byte[] bytes = commandElems.get(3);
+        if (Coder.bytesToString(bytes).equalsIgnoreCase("MATCH")) {
+          bytes = commandElems.get(4);
+          globMatchPattern = Coder.bytesToString(bytes);
+        } else if (Coder.bytesToString(bytes).equalsIgnoreCase("COUNT")) {
+          bytes = commandElems.get(4);
+          count = Coder.bytesToInt(bytes);
+        }
+      } catch (NumberFormatException e) {
+        command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_COUNT));
+        return;
+      }
+    }
+
+    if (commandElems.size() > 6) {
+      try {
+        byte[] bytes = commandElems.get(5);
+        if (Coder.bytesToString(bytes).equalsIgnoreCase("COUNT")) {
+          bytes = commandElems.get(6);
+          count = Coder.bytesToInt(bytes);
+        }
+      } catch (NumberFormatException e) {
+        command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_COUNT));
+        return;
+      }
+    }
+
+    if (count < 0) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_COUNT));
+      return;
+    }
+
+    try {
+      matchPattern = convertGlobToRegex(globMatchPattern);
+    } catch (PatternSyntaxException e) {
+      command.setResponse(
+          Coder.getErrorResponse(context.getByteBufAllocator(), RedisConstants.ERROR_ILLEGAL_GLOB));
+      return;
+    }
+
+    List<ByteArrayWrapper> returnList =
+        (List<ByteArrayWrapper>) getIteration(new HashSet(keyRegion.entrySet()), matchPattern,
+            count, cursor);
+
+    command.setResponse(Coder.getScanResponse(context.getByteBufAllocator(), returnList));
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  protected List<?> getIteration(Collection<?> list, Pattern matchPattern, int count, int cursor) {
+    List<Object> returnList = new ArrayList<Object>();
+    int size = list.size();
+    int beforeCursor = 0;
+    int numElements = 0;
+    int i = -1;
+    for (Entry<ByteArrayWrapper, DoubleWrapper> entry : (Collection<Entry<ByteArrayWrapper, DoubleWrapper>>) list) {
+      ByteArrayWrapper keyWrapper = entry.getKey();
+      String key = keyWrapper.toString();
+
+      DoubleWrapper value = entry.getValue();
+      i++;
+      if (beforeCursor < cursor) {
+        beforeCursor++;
+        continue;
+      } else if (numElements < count) {
+        if (matchPattern != null) {
+          if (matchPattern.matcher(key).matches()) {
+            returnList.add(keyWrapper);
+            returnList.add(value.toString());
+            numElements++;
+          }
+        } else {
+          returnList.add(keyWrapper);
+          returnList.add(value.toString());
+          numElements++;
+        }
+      } else
+        break;
+    }
+
+    if (i == size - 1)
+      returnList.add(0, String.valueOf(0));
+    else
+      returnList.add(0, String.valueOf(i));
+    return returnList;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZScoreExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZScoreExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZScoreExecutor.java
new file mode 100644
index 0000000..dbdaa0d
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZScoreExecutor.java
@@ -0,0 +1,58 @@
+/*
+ * 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.sortedset;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.DoubleWrapper;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+import org.apache.geode.redis.internal.RedisDataType;
+
+import java.util.List;
+
+public class ZScoreExecutor extends SortedSetExecutor {
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 3) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.ZSCORE));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+    ByteArrayWrapper member = new ByteArrayWrapper(commandElems.get(2));
+
+    checkDataType(key, RedisDataType.REDIS_SORTEDSET, context);
+    Region<ByteArrayWrapper, DoubleWrapper> keyRegion = getRegion(context, key);
+
+    if (keyRegion == null) {
+      command.setResponse(Coder.getNilResponse(context.getByteBufAllocator()));
+      return;
+    }
+    DoubleWrapper score = keyRegion.get(member);
+    if (score == null) {
+      command.setResponse(Coder.getNilResponse(context.getByteBufAllocator()));
+      return;
+    }
+    command
+        .setResponse(Coder.getBulkStringResponse(context.getByteBufAllocator(), score.toString()));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/AppendExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/AppendExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/AppendExecutor.java
new file mode 100644
index 0000000..7bd12d6
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/AppendExecutor.java
@@ -0,0 +1,68 @@
+/*
+ * 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.string;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+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 java.util.List;
+
+public class AppendExecutor extends StringExecutor {
+
+  private final int VALUE_INDEX = 2;
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    Region<ByteArrayWrapper, ByteArrayWrapper> r = context.getRegionProvider().getStringsRegion();;
+
+    if (commandElems.size() < 3) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.APPEND));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+    checkAndSetDataType(key, context);
+    ByteArrayWrapper string = r.get(key);
+
+    byte[] stringByteArray = commandElems.get(VALUE_INDEX);
+    if (string == null) {
+      r.put(key, new ByteArrayWrapper(stringByteArray));
+      command.setResponse(
+          Coder.getIntegerResponse(context.getByteBufAllocator(), stringByteArray.length));
+    } else {
+      byte[] newValue = concatArrays(string.toBytes(), stringByteArray);
+      string.setBytes(newValue);
+      r.put(key, string);
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), newValue.length));
+    }
+
+  }
+
+  private byte[] concatArrays(byte[] o, byte[] n) {
+    int oLen = o.length;
+    int nLen = n.length;
+    byte[] combined = new byte[oLen + nLen];
+    System.arraycopy(o, 0, combined, 0, oLen);
+    System.arraycopy(n, 0, combined, oLen, nLen);
+    return combined;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/BitCountExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/BitCountExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/BitCountExecutor.java
new file mode 100644
index 0000000..7461eea
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/BitCountExecutor.java
@@ -0,0 +1,97 @@
+/*
+ * 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.string;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+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;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+import java.util.List;
+
+public class BitCountExecutor extends StringExecutor {
+
+  private final String ERROR_NOT_INT = "The indexes provided must be numeric values";
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    Region<ByteArrayWrapper, ByteArrayWrapper> r = context.getRegionProvider().getStringsRegion();
+
+    if (commandElems.size() != 2 && commandElems.size() != 4) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.BITCOUNT));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+    checkAndSetDataType(key, context);
+    ByteArrayWrapper wrapper = r.get(key);
+    if (wrapper == null) {
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), 0));
+      return;
+    }
+    byte[] value = wrapper.toBytes();
+
+    long startL = 0;
+    long endL = value.length - 1;
+
+    if (commandElems.size() == 4) {
+      try {
+        startL = Coder.bytesToLong(commandElems.get(2));
+        endL = Coder.bytesToLong(commandElems.get(3));
+      } catch (NumberFormatException e) {
+        command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_NOT_INT));
+        return;
+      }
+    }
+    if (startL > Integer.MAX_VALUE || endL > Integer.MAX_VALUE) {
+      command.setResponse(
+          Coder.getErrorResponse(context.getByteBufAllocator(), RedisConstants.ERROR_OUT_OF_RANGE));
+      return;
+    }
+
+    int start = (int) startL;
+    int end = (int) endL;
+    if (start < 0)
+      start += value.length;
+    if (end < 0)
+      end += value.length;
+
+    if (start < 0)
+      start = 0;
+    if (end < 0)
+      end = 0;
+
+    if (end > value.length - 1)
+      end = value.length - 1;
+
+    if (end < start || start >= value.length) {
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), 0));
+      return;
+    }
+
+    long setBits = 0;
+    for (int j = start; j <= end; j++)
+      setBits += Integer.bitCount(0xFF & value[j]); // 0xFF keeps same bit sequence as the byte as
+                                                    // opposed to keeping the same value
+
+    command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), setBits));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/BitOpExecutor.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..d32a996
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/BitOpExecutor.java
@@ -0,0 +1,154 @@
+/*
+ * 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.string;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+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 java.util.List;
+
+public class BitOpExecutor extends StringExecutor {
+
+  private static final String ERROR_NO_SUCH_OP = "Please specify a legal operation";
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    Region<ByteArrayWrapper, ByteArrayWrapper> r = context.getRegionProvider().getStringsRegion();
+
+    if (commandElems.size() < 4) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.BITOP));
+      return;
+    }
+
+    String operation = command.getStringKey().toUpperCase();
+    ByteArrayWrapper destKey = new ByteArrayWrapper(commandElems.get(2));
+    checkDataType(destKey, 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);
+      ByteArrayWrapper value = r.get(key);
+      if (value == null) {
+        values[i - 3] = null;
+        continue;
+      }
+
+      byte[] val = value.toBytes();
+      values[i - 3] = val;
+      if (val.length > maxLength) {
+        maxLength = val.length;
+        byte[] tmp = values[0];
+        values[0] = val;
+        values[i - 3] = tmp;
+      }
+      if (i == 3 && operation.equalsIgnoreCase("NOT"))
+        break;
+    }
+
+
+    if (operation.equals("AND"))
+      and(context, r, destKey, values, maxLength);
+    else if (operation.equals("OR"))
+      or(context, r, destKey, values, maxLength);
+    else if (operation.equals("XOR"))
+      xor(context, r, destKey, values, maxLength);
+    else if (operation.equals("NOT"))
+      not(context, r, destKey, values, maxLength);
+    else {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_NO_SUCH_OP));
+      return;
+    }
+
+    command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), maxLength));
+  }
+
+  private void and(ExecutionHandlerContext context, Region<ByteArrayWrapper, ByteArrayWrapper> r,
+      ByteArrayWrapper destKey, byte[][] values, int max) {
+    byte[] dest = new byte[max];
+    outer: for (int i = 0; i < max; i++) {
+      byte b = values[0][i];
+      for (int j = 1; j < values.length; j++) {
+        if (values[j] == null) {
+          break outer;
+        } else if (i < values[j].length)
+          b &= values[j][i];
+        else
+          b &= 0;
+      }
+      dest[i] = b;
+    }
+    checkAndSetDataType(destKey, context);
+    r.put(destKey, new ByteArrayWrapper(dest));
+  }
+
+  private void or(ExecutionHandlerContext context, Region<ByteArrayWrapper, ByteArrayWrapper> r,
+      ByteArrayWrapper destKey, byte[][] values, int max) {
+    byte[] dest = new byte[max];
+    for (int i = 0; i < max; i++) {
+      byte b = values[0][i];
+      for (int j = 1; j < values.length; j++) {
+        byte[] cA = values[j];
+        if (cA != null && i < cA.length)
+          b |= cA[i];
+        else
+          b |= 0;
+      }
+      dest[i] = b;
+    }
+    checkAndSetDataType(destKey, context);
+    r.put(destKey, new ByteArrayWrapper(dest));
+  }
+
+  private void xor(ExecutionHandlerContext context, Region<ByteArrayWrapper, ByteArrayWrapper> r,
+      ByteArrayWrapper destKey, byte[][] values, int max) {
+    byte[] dest = new byte[max];
+    for (int i = 0; i < max; i++) {
+      byte b = values[0][i];
+      for (int j = 1; j < values.length; j++) {
+        byte[] cA = values[j];
+        if (cA != null && i < cA.length)
+          b ^= cA[i];
+        else
+          b ^= 0;
+      }
+      dest[i] = b;
+    }
+    checkAndSetDataType(destKey, context);
+    r.put(destKey, new ByteArrayWrapper(dest));
+  }
+
+  private void not(ExecutionHandlerContext context, Region<ByteArrayWrapper, ByteArrayWrapper> r,
+      ByteArrayWrapper destKey, byte[][] values, int max) {
+    byte[] dest = new byte[max];
+    byte[] cA = values[0];
+    for (int i = 0; i < max; i++) {
+      if (cA == null)
+        dest[i] = ~0;
+      else
+        dest[i] = (byte) (~cA[i] & 0xFF);
+    }
+    checkAndSetDataType(destKey, context);
+    r.put(destKey, new ByteArrayWrapper(dest));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/BitPosExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/BitPosExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/BitPosExecutor.java
new file mode 100644
index 0000000..4ea633a
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/BitPosExecutor.java
@@ -0,0 +1,140 @@
+/*
+ * 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.string;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+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 java.util.List;
+
+public class BitPosExecutor extends StringExecutor {
+
+  private final String ERROR_NOT_INT = "The numbers provided must be numeric values";
+
+  private final String ERROR_BIT = "The bit must either be a 0 or 1";
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    Region<ByteArrayWrapper, ByteArrayWrapper> r = context.getRegionProvider().getStringsRegion();
+
+    if (commandElems.size() < 3) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.BITPOS));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+    checkAndSetDataType(key, context);
+    ByteArrayWrapper string = r.get(key);
+
+    int bit;
+    int bitPosition = -1;
+    boolean endSet = false;
+
+    try {
+      byte[] bitAr = commandElems.get(2);
+      bit = Coder.bytesToInt(bitAr);
+    } catch (NumberFormatException e) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_NOT_INT));
+      return;
+    }
+
+    if (bit != 0 && bit != 1) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_BIT));
+      return;
+    }
+
+    if (string == null || string.length() == 0) {
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), -bit)); // Redis
+                                                                                          // returns
+                                                                                          // 0 when
+                                                                                          // key
+                                                                                          // does
+                                                                                          // not
+                                                                                          // exists
+                                                                                          // for
+                                                                                          // this
+                                                                                          // command
+      return;
+    }
+    byte[] bytes = string.toBytes();
+    int start = 0;
+    int end = bytes.length - 1;
+    if (commandElems.size() > 3) {
+      try {
+        byte[] startAr = commandElems.get(3);
+        start = Coder.bytesToInt(startAr);
+      } catch (NumberFormatException e) {
+        command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_NOT_INT));
+        return;
+      }
+    }
+
+
+    if (commandElems.size() > 4) {
+      try {
+        byte[] endAr = commandElems.get(4);
+        end = Coder.bytesToInt(endAr);
+        endSet = true;
+      } catch (NumberFormatException e) {
+        command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_NOT_INT));
+        return;
+      }
+    }
+
+    if (start < 0)
+      start += bytes.length;
+    if (end < 0)
+      end += bytes.length;
+
+    if (start < 0)
+      start = 0;
+    if (end < 0)
+      end = 0;
+
+    if (start > bytes.length)
+      start = bytes.length - 1;
+    if (end > bytes.length)
+      end = bytes.length - 1;
+
+    if (end < start) {
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), -1));
+      return;
+    }
+
+    outerLoop: for (int i = start; i <= end; i++) {
+      int cBit;
+      byte cByte = bytes[i];
+      for (int j = 0; j < 8; j++) {
+        cBit = (cByte & (0x80 >> j)) >> (7 - j);
+        if (cBit == bit) {
+          bitPosition = 8 * i + j;
+          break outerLoop;
+        }
+      }
+    }
+
+    if (bit == 0 && bitPosition == -1 && !endSet)
+      bitPosition = bytes.length * 8;
+
+    command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), bitPosition));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/DecrByExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/DecrByExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/DecrByExecutor.java
new file mode 100644
index 0000000..d632bc0
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/DecrByExecutor.java
@@ -0,0 +1,113 @@
+/*
+ * 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.string;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+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 java.util.List;
+
+public class DecrByExecutor extends StringExecutor {
+
+  private final String ERROR_VALUE_NOT_USABLE =
+      "The value at this key cannot be decremented numerically";
+
+  private final String ERROR_DECREMENT_NOT_USABLE =
+      "The decrementation on this key must be numeric";
+
+  private final String ERROR_OVERFLOW = "This decrementation cannot be performed due to overflow";
+
+  private final int DECREMENT_INDEX = 2;
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    Region<ByteArrayWrapper, ByteArrayWrapper> r = context.getRegionProvider().getStringsRegion();
+
+    if (commandElems.size() < 3) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.DECRBY));
+      return;
+    }
+    ByteArrayWrapper key = command.getKey();
+    checkAndSetDataType(key, context);
+    ByteArrayWrapper valueWrapper = r.get(key);
+
+    /*
+     * Try increment
+     */
+
+    byte[] decrArray = commandElems.get(DECREMENT_INDEX);
+    String decrString = Coder.bytesToString(decrArray);
+    Long decrement;
+
+    try {
+      decrement = Long.parseLong(decrString);
+    } catch (NumberFormatException e) {
+      command.setResponse(
+          Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_DECREMENT_NOT_USABLE));
+      return;
+    }
+
+    /*
+     * Value does not exist
+     */
+
+    if (valueWrapper == null) {
+      String negativeDecrString =
+          decrString.charAt(0) == Coder.HYPHEN_ID ? decrString.substring(1) : "-" + decrString;
+      r.put(key, new ByteArrayWrapper(Coder.stringToBytes(negativeDecrString)));
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), -decrement));
+      return;
+    }
+
+    /*
+     * Value exists
+     */
+
+    String stringValue = Coder.bytesToString(valueWrapper.toBytes());
+
+    Long value;
+    try {
+      value = Long.parseLong(stringValue);
+    } catch (NumberFormatException e) {
+      command.setResponse(
+          Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_VALUE_NOT_USABLE));
+      return;
+    }
+
+    /*
+     * Check for overflow Negative decrement is used because the decrement is stored as a positive
+     * long
+     */
+    if (value <= 0 && -decrement < (Long.MIN_VALUE - value)) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_OVERFLOW));
+      return;
+    }
+
+    value -= decrement;
+
+    stringValue = "" + value;
+    r.put(key, new ByteArrayWrapper(Coder.stringToBytes(stringValue)));
+
+    command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), value));
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/DecrExecutor.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..8c73616
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/DecrExecutor.java
@@ -0,0 +1,95 @@
+/*
+ * 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.string;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+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;
+
+import java.util.List;
+
+public class DecrExecutor extends StringExecutor {
+
+  private final String ERROR_VALUE_NOT_USABLE =
+      "The value at this key cannot be decremented numerically";
+
+  private final String ERROR_OVERFLOW = "This decrementation cannot be performed due to overflow";
+
+  private final byte[] INIT_VALUE_BYTES = Coder.stringToBytes("-1");
+
+  private final int INIT_VALUE_INT = -1;
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    RegionProvider rC = context.getRegionProvider();
+    Region<ByteArrayWrapper, ByteArrayWrapper> r = rC.getStringsRegion();;
+
+    if (commandElems.size() < 2) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.DECR));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+    checkAndSetDataType(key, context);
+    ByteArrayWrapper valueWrapper = r.get(key);
+
+    /*
+     * Value does not exist
+     */
+
+    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;
+    }
+
+    /*
+     * Value exists
+     */
+
+    String stringValue = valueWrapper.toString();
+    Long value;
+    try {
+      value = Long.parseLong(stringValue);
+    } catch (NumberFormatException e) {
+      command.setResponse(
+          Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_VALUE_NOT_USABLE));
+      return;
+    }
+
+    if (value == Long.MIN_VALUE) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_OVERFLOW));
+      return;
+    }
+
+    value--;
+
+    stringValue = "" + value;
+
+    r.put(key, new ByteArrayWrapper(Coder.stringToBytes(stringValue)));
+    command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), value));
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/GetBitExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/GetBitExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/GetBitExecutor.java
new file mode 100644
index 0000000..1220be1
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/GetBitExecutor.java
@@ -0,0 +1,80 @@
+/*
+ * 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.string;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+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 java.util.List;
+
+public class GetBitExecutor extends StringExecutor {
+
+  private final String ERROR_NOT_INT = "The offset provided must be numeric";
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    Region<ByteArrayWrapper, ByteArrayWrapper> r = context.getRegionProvider().getStringsRegion();
+
+    if (commandElems.size() < 3) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.GETBIT));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+    checkAndSetDataType(key, context);
+    ByteArrayWrapper wrapper = r.get(key);
+    if (wrapper == null) {
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), 0));
+      return;
+    }
+
+    int bit = 0;
+    byte[] bytes = wrapper.toBytes();
+    int offset;
+    try {
+      byte[] offAr = commandElems.get(2);
+      offset = Coder.bytesToInt(offAr);
+    } catch (NumberFormatException e) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_NOT_INT));
+      return;
+    }
+    if (offset < 0)
+      offset += bytes.length * 8;
+
+    if (offset < 0 || offset > bytes.length * 8) {
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), 0));
+      return;
+    }
+
+    int byteIndex = offset / 8;
+    offset %= 8;
+
+    if (byteIndex >= bytes.length) {
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), 0));
+      return;
+    }
+
+    bit = (bytes[byteIndex] & (0x80 >> offset)) >> (7 - offset);
+
+    command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), bit));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/GetExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/GetExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/GetExecutor.java
new file mode 100644
index 0000000..31aac75
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/string/GetExecutor.java
@@ -0,0 +1,51 @@
+/*
+ * 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.string;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+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 GetExecutor extends StringExecutor {
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    Region<ByteArrayWrapper, ByteArrayWrapper> r = context.getRegionProvider().getStringsRegion();
+
+    if (command.getProcessedCommand().size() < 2) {
+      command
+          .setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.GETEXECUTOR));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+    checkDataType(key, RedisDataType.REDIS_STRING, context);
+    ByteArrayWrapper wrapper = r.get(key);
+
+    if (wrapper == null) {
+      command.setResponse(Coder.getNilResponse(context.getByteBufAllocator()));
+      return;
+    } else {
+      command.setResponse(
+          Coder.getBulkStringResponse(context.getByteBufAllocator(), wrapper.toBytes()));
+    }
+
+  }
+
+}


Mime
View raw message