geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From u..@apache.org
Subject [06/21] geode git commit: GEODE-2449: Moved Redis out of core with minimal Extension work added
Date Fri, 10 Feb 2017 21:34:09 GMT
http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SCardExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SCardExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SCardExecutor.java
new file mode 100644
index 0000000..149a7eb
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SCardExecutor.java
@@ -0,0 +1,54 @@
+/*
+ * 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.set;
+
+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 java.util.List;
+
+public class SCardExecutor extends SetExecutor {
+
+  private final int NOT_EXISTS = 0;
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 2) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.SCARD));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+    checkDataType(key, RedisDataType.REDIS_SET, context);
+    Region<ByteArrayWrapper, Boolean> keyRegion =
+        (Region<ByteArrayWrapper, Boolean>) context.getRegionProvider().getRegion(key);
+
+    if (keyRegion == null) {
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NOT_EXISTS));
+      return;
+    }
+
+    command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), keyRegion.size()));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SDiffExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SDiffExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SDiffExecutor.java
new file mode 100644
index 0000000..5712237
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SDiffExecutor.java
@@ -0,0 +1,45 @@
+/*
+ * 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.set;
+
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+import java.util.List;
+import java.util.Set;
+
+public class SDiffExecutor extends SetOpExecutor {
+
+  @Override
+  protected boolean isStorage() {
+    return false;
+  }
+
+  @Override
+  protected Set<ByteArrayWrapper> setOp(Set<ByteArrayWrapper> firstSet,
+      List<Set<ByteArrayWrapper>> setList) {
+    if (firstSet == null)
+      return null;
+    for (Set<ByteArrayWrapper> set : setList)
+      firstSet.removeAll(set);
+    return firstSet;
+  }
+
+  @Override
+  public String getArgsError() {
+    return ArityDef.SDIFF;
+  }
+
+}

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

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SInterExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SInterExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SInterExecutor.java
new file mode 100644
index 0000000..cc4bbe3
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SInterExecutor.java
@@ -0,0 +1,48 @@
+/*
+ * 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.set;
+
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+import java.util.List;
+import java.util.Set;
+
+public class SInterExecutor extends SetOpExecutor {
+
+  @Override
+  protected boolean isStorage() {
+    return false;
+  }
+
+  @Override
+  protected Set<ByteArrayWrapper> setOp(Set<ByteArrayWrapper> firstSet,
+      List<Set<ByteArrayWrapper>> setList) {
+    if (firstSet == null)
+      return null;
+    for (Set<ByteArrayWrapper> set : setList) {
+      if (set == null || set.isEmpty())
+        return null;
+      firstSet.retainAll(set);
+    }
+    return firstSet;
+  }
+
+  @Override
+  public String getArgsError() {
+    return ArityDef.SINTER;
+  }
+
+}

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

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SIsMemberExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SIsMemberExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SIsMemberExecutor.java
new file mode 100644
index 0000000..38593c1
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SIsMemberExecutor.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.set;
+
+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 java.util.List;
+
+public class SIsMemberExecutor extends SetExecutor {
+
+  private final int EXISTS = 1;
+
+  private final int NOT_EXISTS = 0;
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 3) {
+      command
+          .setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.SISMEMBER));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+    ByteArrayWrapper member = new ByteArrayWrapper(commandElems.get(2));
+
+    checkDataType(key, RedisDataType.REDIS_SET, context);
+    @SuppressWarnings("unchecked")
+    Region<ByteArrayWrapper, Boolean> keyRegion =
+        (Region<ByteArrayWrapper, Boolean>) context.getRegionProvider().getRegion(key);
+
+    if (keyRegion == null) {
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NOT_EXISTS));
+      return;
+    }
+
+    if (keyRegion.containsKey(member))
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), EXISTS));
+    else
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NOT_EXISTS));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SMembersExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SMembersExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SMembersExecutor.java
new file mode 100644
index 0000000..73abb97
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SMembersExecutor.java
@@ -0,0 +1,55 @@
+/*
+ * 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.set;
+
+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 java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class SMembersExecutor extends SetExecutor {
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 2) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.SMEMBERS));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+    checkDataType(key, RedisDataType.REDIS_SET, context);
+    @SuppressWarnings("unchecked")
+    Region<ByteArrayWrapper, Boolean> keyRegion =
+        (Region<ByteArrayWrapper, Boolean>) context.getRegionProvider().getRegion(key);
+
+    if (keyRegion == null) {
+      command.setResponse(Coder.getEmptyArrayResponse(context.getByteBufAllocator()));
+      return;
+    }
+
+    Set<ByteArrayWrapper> members = new HashSet(keyRegion.keySet()); // Emulate copy on read
+
+    command.setResponse(Coder.getBulkStringArrayResponse(context.getByteBufAllocator(), members));
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SMoveExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SMoveExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SMoveExecutor.java
new file mode 100644
index 0000000..4917b7b
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SMoveExecutor.java
@@ -0,0 +1,74 @@
+/*
+ * 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.set;
+
+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 java.util.List;
+
+public class SMoveExecutor extends SetExecutor {
+
+  private final int MOVED = 1;
+
+  private final int NOT_MOVED = 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.SMOVE));
+      return;
+    }
+
+    ByteArrayWrapper source = command.getKey();
+    ByteArrayWrapper destination = new ByteArrayWrapper(commandElems.get(2));
+    ByteArrayWrapper mem = new ByteArrayWrapper(commandElems.get(3));
+
+    checkDataType(source, RedisDataType.REDIS_SET, context);
+    checkDataType(destination, RedisDataType.REDIS_SET, context);
+    @SuppressWarnings("unchecked")
+    Region<ByteArrayWrapper, Boolean> sourceRegion =
+        (Region<ByteArrayWrapper, Boolean>) context.getRegionProvider().getRegion(source);
+
+    if (sourceRegion == null) {
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NOT_MOVED));
+      return;
+    }
+
+    Object oldVal = sourceRegion.get(mem);
+    sourceRegion.remove(mem);
+
+    if (oldVal == null) {
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NOT_MOVED));
+      return;
+    }
+
+    @SuppressWarnings("unchecked")
+    Region<ByteArrayWrapper, Boolean> destinationRegion =
+        (Region<ByteArrayWrapper, Boolean>) getOrCreateRegion(context, destination,
+            RedisDataType.REDIS_SET);
+    destinationRegion.put(mem, true);
+
+    command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), MOVED));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SPopExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SPopExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SPopExecutor.java
new file mode 100644
index 0000000..bf1ffd9
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SPopExecutor.java
@@ -0,0 +1,60 @@
+/*
+ * 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.set;
+
+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;
+import java.util.Random;
+
+public class SPopExecutor extends SetExecutor {
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 2) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.SPOP));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+    @SuppressWarnings("unchecked")
+    Region<ByteArrayWrapper, Boolean> keyRegion =
+        (Region<ByteArrayWrapper, Boolean>) context.getRegionProvider().getRegion(key);
+    if (keyRegion == null || keyRegion.isEmpty()) {
+      command.setResponse(Coder.getNilResponse(context.getByteBufAllocator()));
+      return;
+    }
+
+    Random rand = new Random();
+
+    ByteArrayWrapper[] entries = keyRegion.keySet().toArray(new ByteArrayWrapper[keyRegion.size()]);
+
+    ByteArrayWrapper pop = entries[rand.nextInt(entries.length)];
+
+    keyRegion.remove(pop);
+    if (keyRegion.isEmpty()) {
+      context.getRegionProvider().removeKey(key);
+    }
+    command.setResponse(Coder.getBulkStringResponse(context.getByteBufAllocator(), pop.toBytes()));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SRandMemberExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SRandMemberExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SRandMemberExecutor.java
new file mode 100644
index 0000000..61f6305
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SRandMemberExecutor.java
@@ -0,0 +1,101 @@
+/*
+ * 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.set;
+
+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.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+
+public class SRandMemberExecutor extends SetExecutor {
+
+  private final static String ERROR_NOT_NUMERIC = "The count provided must be numeric";
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 2) {
+      command
+          .setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.SRANDMEMBER));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+    @SuppressWarnings("unchecked")
+    Region<ByteArrayWrapper, Boolean> keyRegion =
+        (Region<ByteArrayWrapper, Boolean>) context.getRegionProvider().getRegion(key);
+
+    int count = 1;
+
+    if (commandElems.size() > 2) {
+      try {
+        count = Coder.bytesToInt(commandElems.get(2));
+      } catch (NumberFormatException e) {
+        command
+            .setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_NOT_NUMERIC));
+        return;
+      }
+    }
+
+    if (keyRegion == null || count == 0) {
+      command.setResponse(Coder.getNilResponse(context.getByteBufAllocator()));
+      return;
+    }
+
+    int members = keyRegion.size();
+
+    if (members <= count && count != 1) {
+      command.setResponse(Coder.getBulkStringArrayResponse(context.getByteBufAllocator(),
+          new HashSet<ByteArrayWrapper>(keyRegion.keySet())));
+      return;
+    }
+
+    Random rand = new Random();
+
+    ByteArrayWrapper[] entries = keyRegion.keySet().toArray(new ByteArrayWrapper[members]);
+
+    if (count == 1) {
+      ByteArrayWrapper randEntry = entries[rand.nextInt(entries.length)];
+      command.setResponse(
+          Coder.getBulkStringResponse(context.getByteBufAllocator(), randEntry.toBytes()));
+    } else if (count > 0) {
+      Set<ByteArrayWrapper> randEntries = new HashSet<ByteArrayWrapper>();
+      do {
+        ByteArrayWrapper s = entries[rand.nextInt(entries.length)];
+        randEntries.add(s);
+      } while (randEntries.size() < count);
+      command.setResponse(
+          Coder.getBulkStringArrayResponse(context.getByteBufAllocator(), randEntries));
+    } else {
+      count = -count;
+      List<ByteArrayWrapper> randEntries = new ArrayList<ByteArrayWrapper>();
+      for (int i = 0; i < count; i++) {
+        ByteArrayWrapper s = entries[rand.nextInt(entries.length)];
+        randEntries.add(s);
+      }
+      command.setResponse(
+          Coder.getBulkStringArrayResponse(context.getByteBufAllocator(), randEntries));
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SRemExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SRemExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SRemExecutor.java
new file mode 100644
index 0000000..f9a97f0
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SRemExecutor.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.set;
+
+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 java.util.List;
+
+public class SRemExecutor extends SetExecutor {
+
+  private final int NONE_REMOVED = 0;
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 3) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.SREM));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+    checkDataType(key, RedisDataType.REDIS_SET, context);
+    @SuppressWarnings("unchecked")
+    Region<ByteArrayWrapper, Boolean> keyRegion =
+        (Region<ByteArrayWrapper, Boolean>) context.getRegionProvider().getRegion(key);
+
+    if (keyRegion == null) {
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NONE_REMOVED));
+      return;
+    }
+
+    int numRemoved = 0;
+
+    for (int i = 2; i < commandElems.size(); i++) {
+      Object oldVal;
+      oldVal = keyRegion.remove(new ByteArrayWrapper(commandElems.get(i)));
+      if (oldVal != null)
+        numRemoved++;
+    }
+
+    command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), numRemoved));
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SScanExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SScanExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SScanExecutor.java
new file mode 100644
index 0000000..585f75d
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SScanExecutor.java
@@ -0,0 +1,157 @@
+/*
+ * 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.set;
+
+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 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.List;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+public class SScanExecutor extends AbstractScanExecutor {
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 3) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.SSCAN));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+    checkDataType(key, RedisDataType.REDIS_SET, context);
+    @SuppressWarnings("unchecked")
+    Region<ByteArrayWrapper, Boolean> keyRegion =
+        (Region<ByteArrayWrapper, Boolean>) context.getRegionProvider().getRegion(key);
+    if (keyRegion == null) {
+      command.setResponse(
+          Coder.getScanResponse(context.getByteBufAllocator(), new ArrayList<String>()));
+      return;
+    }
+    byte[] cAr = commandElems.get(2);
+    String cursorString = Coder.bytesToString(cAr);
+    int cursor = 0;
+    Pattern matchPattern = null;
+    String globMatchPattern = null;
+    int count = DEFUALT_COUNT;
+    try {
+      cursor = Integer.parseInt(cursorString);
+    } 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);
+        String tmp = Coder.bytesToString(bytes);
+        if (tmp.equalsIgnoreCase("MATCH")) {
+          bytes = commandElems.get(4);
+          globMatchPattern = Coder.bytesToString(bytes);
+        } else if (tmp.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);
+        String tmp = Coder.bytesToString(bytes);
+        if (tmp.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;
+    }
+
+    @SuppressWarnings("unchecked")
+    List<ByteArrayWrapper> returnList =
+        (List<ByteArrayWrapper>) getIteration(new ArrayList(keyRegion.keySet()), 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 (ByteArrayWrapper value : (Collection<ByteArrayWrapper>) list) {
+      String key = Coder.bytesToString(value.toBytes());
+      i++;
+      if (beforeCursor < cursor) {
+        beforeCursor++;
+        continue;
+      } else if (numElements < count) {
+        if (matchPattern != null) {
+          if (matchPattern.matcher(key).matches()) {
+            returnList.add(value);
+            numElements++;
+          }
+        } else {
+          returnList.add(value);
+          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/set/SUnionExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SUnionExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SUnionExecutor.java
new file mode 100644
index 0000000..15705c1
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SUnionExecutor.java
@@ -0,0 +1,50 @@
+/*
+ * 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.set;
+
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class SUnionExecutor extends SetOpExecutor {
+
+  @Override
+  protected boolean isStorage() {
+    return false;
+  }
+
+  @Override
+  protected Set<ByteArrayWrapper> setOp(Set<ByteArrayWrapper> firstSet,
+      List<Set<ByteArrayWrapper>> setList) {
+    Set<ByteArrayWrapper> addSet = firstSet;
+    for (Set<ByteArrayWrapper> set : setList) {
+      if (addSet == null) {
+        addSet = new HashSet<ByteArrayWrapper>(set);
+        continue;
+      }
+      addSet.addAll(set);
+    }
+    return addSet;
+  }
+
+  @Override
+  public String getArgsError() {
+    return ArityDef.SUNION;
+  }
+
+}

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

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SetExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SetExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SetExecutor.java
new file mode 100644
index 0000000..0227e88
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SetExecutor.java
@@ -0,0 +1,21 @@
+/*
+ * 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.set;
+
+import org.apache.geode.redis.internal.executor.AbstractExecutor;
+
+public abstract class SetExecutor extends AbstractExecutor {
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SetOpExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SetOpExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SetOpExecutor.java
new file mode 100644
index 0000000..df757af
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/set/SetOpExecutor.java
@@ -0,0 +1,114 @@
+/*
+ * 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.set;
+
+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.Extendable;
+import org.apache.geode.redis.internal.RedisDataType;
+import org.apache.geode.redis.internal.RegionProvider;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public abstract class SetOpExecutor extends SetExecutor implements Extendable {
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+    int setsStartIndex = isStorage() ? 2 : 1;
+    if (commandElems.size() < setsStartIndex + 1) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), getArgsError()));
+      return;
+    }
+    RegionProvider rC = context.getRegionProvider();
+    ByteArrayWrapper destination = null;
+    if (isStorage())
+      destination = command.getKey();
+
+    ByteArrayWrapper firstSetKey = new ByteArrayWrapper(commandElems.get(setsStartIndex++));
+    if (!isStorage())
+      checkDataType(firstSetKey, RedisDataType.REDIS_SET, context);
+    Region<ByteArrayWrapper, Boolean> region =
+        (Region<ByteArrayWrapper, Boolean>) rC.getRegion(firstSetKey);
+    Set<ByteArrayWrapper> firstSet = null;
+    if (region != null) {
+      firstSet = new HashSet<ByteArrayWrapper>(region.keySet());
+    }
+    ArrayList<Set<ByteArrayWrapper>> setList = new ArrayList<Set<ByteArrayWrapper>>();
+    for (int i = setsStartIndex; i < commandElems.size(); i++) {
+      ByteArrayWrapper key = new ByteArrayWrapper(commandElems.get(i));
+      checkDataType(key, RedisDataType.REDIS_SET, context);
+      region = (Region<ByteArrayWrapper, Boolean>) rC.getRegion(key);
+      if (region != null)
+        setList.add(region.keySet());
+      else if (this instanceof SInterExecutor)
+        setList.add(null);
+    }
+    if (setList.isEmpty()) {
+      if (isStorage()) {
+        command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), 0));
+        context.getRegionProvider().removeKey(destination);
+      } else {
+        if (firstSet == null)
+          command.setResponse(Coder.getNilResponse(context.getByteBufAllocator()));
+        else
+          command.setResponse(
+              Coder.getBulkStringArrayResponse(context.getByteBufAllocator(), firstSet));
+      }
+      return;
+    }
+
+    Set<ByteArrayWrapper> resultSet = setOp(firstSet, setList);
+    if (isStorage()) {
+      Region<ByteArrayWrapper, Boolean> newRegion = null; // (Region<ByteArrayWrapper, Boolean>)
+                                                          // rC.getRegion(destination);
+      rC.removeKey(destination);
+      if (resultSet != null) {
+        Map<ByteArrayWrapper, Boolean> map = new HashMap<ByteArrayWrapper, Boolean>();
+        for (ByteArrayWrapper entry : resultSet)
+          map.put(entry, Boolean.TRUE);
+        if (!map.isEmpty()) {
+          newRegion = (Region<ByteArrayWrapper, Boolean>) rC.getOrCreateRegion(destination,
+              RedisDataType.REDIS_SET, context);
+          newRegion.putAll(map);
+        }
+        command
+            .setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), resultSet.size()));
+      } else {
+        command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), 0));
+      }
+    } else {
+      if (resultSet == null || resultSet.isEmpty())
+        command.setResponse(Coder.getEmptyArrayResponse(context.getByteBufAllocator()));
+      else
+        command.setResponse(
+            Coder.getBulkStringArrayResponse(context.getByteBufAllocator(), resultSet));
+    }
+  }
+
+  protected abstract boolean isStorage();
+
+  protected abstract Set<ByteArrayWrapper> setOp(Set<ByteArrayWrapper> firstSet,
+      List<Set<ByteArrayWrapper>> setList);
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/SortedSetExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/SortedSetExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/SortedSetExecutor.java
new file mode 100644
index 0000000..5330c80
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/SortedSetExecutor.java
@@ -0,0 +1,43 @@
+/*
+ * 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.DoubleWrapper;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.RedisDataType;
+import org.apache.geode.redis.internal.executor.AbstractExecutor;
+
+public abstract class SortedSetExecutor extends AbstractExecutor {
+
+  @Override
+  protected Region<ByteArrayWrapper, DoubleWrapper> getOrCreateRegion(
+      ExecutionHandlerContext context, ByteArrayWrapper key, RedisDataType type) {
+    @SuppressWarnings("unchecked")
+    Region<ByteArrayWrapper, DoubleWrapper> r = (Region<ByteArrayWrapper, DoubleWrapper>) context
+        .getRegionProvider().getOrCreateRegion(key, type, context);
+    return r;
+  }
+
+  protected Region<ByteArrayWrapper, DoubleWrapper> getRegion(ExecutionHandlerContext context,
+      ByteArrayWrapper key) {
+    @SuppressWarnings("unchecked")
+    Region<ByteArrayWrapper, DoubleWrapper> r =
+        (Region<ByteArrayWrapper, DoubleWrapper>) context.getRegionProvider().getRegion(key);
+    return r;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZAddExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZAddExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZAddExecutor.java
new file mode 100644
index 0000000..40fda1b
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZAddExecutor.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.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.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ZAddExecutor extends SortedSetExecutor {
+
+  private final String ERROR_NOT_NUMERICAL = "The inteded score is not a float";
+
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 4 || commandElems.size() % 2 == 1) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.ZADD));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+    int numberOfAdds = 0;
+
+    if (commandElems.size() > 4) {
+      Map<ByteArrayWrapper, DoubleWrapper> map = new HashMap<ByteArrayWrapper, DoubleWrapper>();
+      for (int i = 2; i < commandElems.size(); i++) {
+        byte[] scoreArray = commandElems.get(i++);
+        byte[] memberArray = commandElems.get(i);
+
+        Double score;
+        try {
+          score = Coder.bytesToDouble(scoreArray);
+        } catch (NumberFormatException e) {
+          command.setResponse(
+              Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_NOT_NUMERICAL));
+          return;
+        }
+
+        map.put(new ByteArrayWrapper(memberArray), new DoubleWrapper(score));
+        numberOfAdds++;
+      }
+      Region<ByteArrayWrapper, DoubleWrapper> keyRegion =
+          getOrCreateRegion(context, key, RedisDataType.REDIS_SORTEDSET);
+      keyRegion.putAll(map);
+    } else {
+      byte[] scoreArray = commandElems.get(2);
+      byte[] memberArray = commandElems.get(3);
+      Double score;
+      try {
+        score = Coder.bytesToDouble(scoreArray);
+      } catch (NumberFormatException e) {
+        command.setResponse(
+            Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_NOT_NUMERICAL));
+        return;
+      }
+      Region<ByteArrayWrapper, DoubleWrapper> keyRegion =
+          getOrCreateRegion(context, key, RedisDataType.REDIS_SORTEDSET);
+      Object oldVal = keyRegion.put(new ByteArrayWrapper(memberArray), new DoubleWrapper(score));
+
+      if (oldVal == null)
+        numberOfAdds = 1;
+    }
+
+    command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), numberOfAdds));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZCardExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZCardExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZCardExecutor.java
new file mode 100644
index 0000000..ad8130e
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZCardExecutor.java
@@ -0,0 +1,53 @@
+/*
+ * 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 ZCardExecutor extends SortedSetExecutor {
+
+  private final int NOT_EXISTS = 0;
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() < 2) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.ZCARD));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+
+    Region<ByteArrayWrapper, DoubleWrapper> keyRegion = getRegion(context, key);
+    checkDataType(key, RedisDataType.REDIS_SORTEDSET, context);
+
+    if (keyRegion == null)
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NOT_EXISTS));
+    else
+      command
+          .setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), keyRegion.size()));
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZCountExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZCountExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZCountExecutor.java
new file mode 100644
index 0000000..21c62c8
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZCountExecutor.java
@@ -0,0 +1,146 @@
+/*
+ * 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.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.RedisConstants.ArityDef;
+import org.apache.geode.redis.internal.RedisDataType;
+import org.apache.geode.redis.internal.executor.SortedSetQuery;
+
+import java.util.List;
+
+public class ZCountExecutor 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.ZCOUNT));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+
+    Region<ByteArrayWrapper, DoubleWrapper> keyRegion = getRegion(context, key);
+    checkDataType(key, RedisDataType.REDIS_SORTEDSET, context);
+
+    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 count;
+    try {
+      count = getCount(key, keyRegion, context, start, stop, startInclusive, stopInclusive);
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+
+
+    command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), count));
+  }
+
+  private int getCount(ByteArrayWrapper key, Region<ByteArrayWrapper, DoubleWrapper> keyRegion,
+      ExecutionHandlerContext context, double start, double stop, boolean startInclusive,
+      boolean stopInclusive) throws FunctionDomainException, TypeMismatchException,
+      NameResolutionException, QueryInvocationTargetException {
+    if (start == Double.NEGATIVE_INFINITY && stop == Double.POSITIVE_INFINITY)
+      return keyRegion.size();
+    else if (start == Double.POSITIVE_INFINITY || stop == Double.NEGATIVE_INFINITY)
+      return 0;
+
+    Query query;
+    Object[] params;
+    if (start == Double.NEGATIVE_INFINITY) {
+      if (stopInclusive) {
+        query = getQuery(key, SortedSetQuery.ZCOUNTNINFI, context);
+      } else {
+        query = getQuery(key, SortedSetQuery.ZCOUNTNINF, context);
+      }
+      params = new Object[] {stop};
+    } else if (stop == Double.POSITIVE_INFINITY) {
+      if (startInclusive) {
+        query = getQuery(key, SortedSetQuery.ZCOUNTPINFI, context);
+      } else {
+        query = getQuery(key, SortedSetQuery.ZCOUNTPINF, context);
+      }
+      params = new Object[] {start};
+    } else {
+      if (startInclusive) {
+        if (stopInclusive) {
+          query = getQuery(key, SortedSetQuery.ZCOUNTSTISI, context);
+        } else {
+          query = getQuery(key, SortedSetQuery.ZCOUNTSTI, context);
+        }
+      } else {
+        if (stopInclusive) {
+          query = getQuery(key, SortedSetQuery.ZCOUNTSI, context);
+        } else {
+          query = getQuery(key, SortedSetQuery.ZCOUNT, context);
+        }
+      }
+      params = new Object[] {start, stop};
+    }
+
+    SelectResults<?> results = (SelectResults<?>) query.execute(params);
+
+    return (Integer) results.asList().get(0);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZIncrByExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZIncrByExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZIncrByExecutor.java
new file mode 100644
index 0000000..ff3195a
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZIncrByExecutor.java
@@ -0,0 +1,76 @@
+/*
+ * 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 ZIncrByExecutor extends SortedSetExecutor {
+
+  private final String ERROR_NOT_NUMERIC = "The number provided is not numeric";
+  private final String ERROR_NAN = "This increment is illegal because it would result in a NaN";
+
+  @Override
+  public void executeCommand(Command command, ExecutionHandlerContext context) {
+    List<byte[]> commandElems = command.getProcessedCommand();
+
+    if (commandElems.size() != 4) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.ZINCRBY));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+
+    Region<ByteArrayWrapper, DoubleWrapper> keyRegion =
+        getOrCreateRegion(context, key, RedisDataType.REDIS_SORTEDSET);
+
+    ByteArrayWrapper member = new ByteArrayWrapper(commandElems.get(3));
+
+    double incr;
+
+    try {
+      byte[] incrArray = commandElems.get(2);
+      incr = Coder.bytesToDouble(incrArray);
+    } catch (NumberFormatException e) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_NOT_NUMERIC));
+      return;
+    }
+
+    DoubleWrapper score = keyRegion.get(member);
+
+    if (score == null) {
+      keyRegion.put(member, new DoubleWrapper(incr));
+      command.setResponse(Coder.getBulkStringResponse(context.getByteBufAllocator(), incr));
+      return;
+    }
+    double result = score.score + incr;
+    if (Double.isNaN(result)) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_NAN));
+      return;
+    }
+    score.score = result;
+    keyRegion.put(member, score);
+    command.setResponse(Coder.getBulkStringResponse(context.getByteBufAllocator(), score.score));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZLexCountExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZLexCountExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZLexCountExecutor.java
new file mode 100644
index 0000000..df326c7
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZLexCountExecutor.java
@@ -0,0 +1,148 @@
+/*
+ * 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.List;
+
+public class ZLexCountExecutor extends SortedSetExecutor {
+
+  private final String ERROR_ILLEGAL_SYNTAX =
+      "The min and max strings must either start with a (, [ or be - or +";
+
+  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.ZLEXCOUNT));
+      return;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+
+    Region<ByteArrayWrapper, DoubleWrapper> keyRegion = getRegion(context, key);
+    checkDataType(key, RedisDataType.REDIS_SORTEDSET, context);
+
+    if (keyRegion == null) {
+      command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), 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;
+    }
+
+
+    int count;
+    try {
+      count = getCount(key, keyRegion, context, Coder.stringToByteArrayWrapper(startString),
+          Coder.stringToByteArrayWrapper(stopString), minInclusive, maxInclusive);
+    } catch (Exception e) {
+      command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), e.toString()));
+      return;
+    }
+
+    command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), count));
+  }
+
+  private int getCount(ByteArrayWrapper key, Region<ByteArrayWrapper, DoubleWrapper> keyRegion,
+      ExecutionHandlerContext context, ByteArrayWrapper start, ByteArrayWrapper stop,
+      boolean startInclusive, boolean stopInclusive) throws Exception {
+    if (start.equals("-") && stop.equals("+"))
+      return keyRegion.size();
+    else if (start.equals("+") || stop.equals("-"))
+      return 0;
+
+    Query query;
+    Object[] params;
+    if (start.equals("-")) {
+      if (stopInclusive) {
+        query = getQuery(key, SortedSetQuery.ZLEXCOUNTNINFI, context);
+      } else {
+        query = getQuery(key, SortedSetQuery.ZLEXCOUNTNINF, context);
+      }
+      params = new Object[] {stop};
+    } else if (stop.equals("+")) {
+      if (startInclusive) {
+        query = getQuery(key, SortedSetQuery.ZLEXCOUNTPINFI, context);
+      } else {
+        query = getQuery(key, SortedSetQuery.ZLEXCOUNTPINF, context);
+      }
+      params = new Object[] {start};
+    } else {
+      if (startInclusive) {
+        if (stopInclusive) {
+          query = getQuery(key, SortedSetQuery.ZLEXCOUNTSTISI, context);
+        } else {
+          query = getQuery(key, SortedSetQuery.ZLEXCOUNTSTI, context);
+        }
+      } else {
+        if (stopInclusive) {
+          query = getQuery(key, SortedSetQuery.ZLEXCOUNTSI, context);
+        } else {
+          query = getQuery(key, SortedSetQuery.ZLEXCOUNT, context);
+        }
+      }
+      params = new Object[] {start, stop};
+    }
+
+    SelectResults<?> results = (SelectResults<?>) query.execute(params);
+
+    return (Integer) results.asList().get(0);
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRangeByLexExecutor.java
----------------------------------------------------------------------
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRangeByLexExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRangeByLexExecutor.java
new file mode 100644
index 0000000..e41b730
--- /dev/null
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRangeByLexExecutor.java
@@ -0,0 +1,220 @@
+/*
+ * 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 io.netty.buffer.ByteBuf;
+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.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.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.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+public class ZRangeByLexExecutor extends SortedSetExecutor {
+
+  private final String ERROR_NOT_NUMERIC = "The index provided is not numeric";
+
+  private final String ERROR_ILLEGAL_SYNTAX =
+      "The min and max strings must either start with a (, [ or be - or +";
+
+  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(), ArityDef.ZRANGEBYLEX));
+      return;
+    }
+
+    boolean existsLimit = false;
+
+    if (commandElems.size() >= 7) {
+      byte[] fifthElem = commandElems.get(4);
+      existsLimit = Coder.bytesToString(fifthElem).equalsIgnoreCase("LIMIT");
+    }
+
+    int offset = 0;
+    int limit = 0;
+
+    if (existsLimit) {
+      try {
+        byte[] offsetArray = commandElems.get(5);
+        byte[] limitArray = commandElems.get(6);
+        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;
+    }
+
+    ByteArrayWrapper key = command.getKey();
+    Region<ByteArrayWrapper, DoubleWrapper> keyRegion =
+        getOrCreateRegion(context, key, RedisDataType.REDIS_SORTEDSET);
+
+    if (keyRegion == null) {
+      command.setResponse(Coder.getEmptyArrayResponse(context.getByteBufAllocator()));
+      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> list = null;
+    if (!(existsLimit && limit == 0)) {
+      try {
+        list = getRange(key, keyRegion, context, Coder.stringToByteArrayWrapper(startString),
+            Coder.stringToByteArrayWrapper(stopString), minInclusive, maxInclusive, offset, limit);
+      } catch (Exception e) {
+        throw new RuntimeException(e);
+      }
+    }
+    if (list == null)
+      command.setResponse(Coder.getEmptyArrayResponse(context.getByteBufAllocator()));
+    else
+      command.setResponse(getCustomBulkStringArrayResponse(list, context));
+  }
+
+  private List<ByteArrayWrapper> getRange(ByteArrayWrapper key,
+      Region<ByteArrayWrapper, DoubleWrapper> keyRegion, ExecutionHandlerContext context,
+      ByteArrayWrapper start, ByteArrayWrapper stop, boolean startInclusive, boolean stopInclusive,
+      int offset, int limit) throws FunctionDomainException, TypeMismatchException,
+      NameResolutionException, QueryInvocationTargetException {
+    if (start.equals("-") && stop.equals("+")) {
+      List<ByteArrayWrapper> l = new ArrayList<ByteArrayWrapper>(keyRegion.keySet());
+      int size = l.size();
+      Collections.sort(l);
+      if (limit == 0)
+        limit += size;
+      l = l.subList(Math.min(size, offset), Math.min(offset + limit, size));
+      return l;
+    } 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};
+    }
+    if (limit > 0)
+      params[params.length - 1] = (limit + offset);
+    SelectResults<ByteArrayWrapper> results =
+        (SelectResults<ByteArrayWrapper>) query.execute(params);
+    List<ByteArrayWrapper> list = results.asList();
+    int size = list.size();
+    return list.subList(Math.min(size, offset), size);
+
+  }
+
+  private final ByteBuf getCustomBulkStringArrayResponse(Collection<ByteArrayWrapper> items,
+      ExecutionHandlerContext context) {
+    Iterator<ByteArrayWrapper> it = items.iterator();
+    ByteBuf response = context.getByteBufAllocator().buffer();
+    response.writeByte(Coder.ARRAY_ID);
+    response.writeBytes(Coder.intToBytes(items.size()));
+    response.writeBytes(Coder.CRLFar);
+
+    while (it.hasNext()) {
+      ByteArrayWrapper next = it.next();
+      byte[] byteAr = next.toBytes();
+      response.writeByte(Coder.BULK_STRING_ID);
+      response.writeBytes(Coder.intToBytes(byteAr.length));
+      response.writeBytes(Coder.CRLFar);
+      response.writeBytes(byteAr);
+      response.writeBytes(Coder.CRLFar);
+    }
+
+    return response;
+  }
+
+}


Mime
View raw message