You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kl...@apache.org on 2016/07/08 18:21:14 UTC
[06/21] incubator-geode git commit: GEODE-1566: rename
GeodeRedisServer and repackage redis code into org.apache.geode
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByLexExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByLexExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByLexExecutor.java
new file mode 100755
index 0000000..5980bd6
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByLexExecutor.java
@@ -0,0 +1,153 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.cache.query.Query;
+import com.gemstone.gemfire.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;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByRankExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByRankExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByRankExecutor.java
new file mode 100755
index 0000000..37fde5d
--- /dev/null
+++ b/geode-core/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 java.util.List;
+
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.cache.Region.Entry;
+import com.gemstone.gemfire.cache.query.Query;
+import com.gemstone.gemfire.cache.query.SelectResults;
+import com.gemstone.gemfire.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;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByScoreExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByScoreExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByScoreExecutor.java
new file mode 100755
index 0000000..e68a01d
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRemRangeByScoreExecutor.java
@@ -0,0 +1,143 @@
+/*
+ * 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 java.util.Collection;
+import java.util.List;
+import java.util.Map.Entry;
+
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.cache.query.Query;
+import com.gemstone.gemfire.cache.query.SelectResults;
+import com.gemstone.gemfire.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;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRangeByScoreExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRangeByScoreExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRangeByScoreExecutor.java
new file mode 100755
index 0000000..271cca6
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRangeByScoreExecutor.java
@@ -0,0 +1,33 @@
+/*
+ * 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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRangeExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRangeExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRangeExecutor.java
new file mode 100755
index 0000000..a4adadf
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRangeExecutor.java
@@ -0,0 +1,34 @@
+/*
+ * 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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRankExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRankExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRankExecutor.java
new file mode 100755
index 0000000..87e07e7
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZRevRankExecutor.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 ZRevRankExecutor extends ZRankExecutor {
+
+ @Override
+ protected boolean isReverse() {
+ return true;
+ }
+
+ @Override
+ public String getArgsError() {
+ return ArityDef.ZREVRANK;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZScanExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZScanExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZScanExecutor.java
new file mode 100755
index 0000000..453fadb
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZScanExecutor.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 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;
+
+import com.gemstone.gemfire.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;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZScoreExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZScoreExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZScoreExecutor.java
new file mode 100755
index 0000000..a28fbb9
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/sortedset/ZScoreExecutor.java
@@ -0,0 +1,59 @@
+/*
+ * 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 java.util.List;
+
+import com.gemstone.gemfire.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;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/AppendExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/AppendExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/AppendExecutor.java
new file mode 100755
index 0000000..2884b68
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/AppendExecutor.java
@@ -0,0 +1,69 @@
+/*
+ * 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 java.util.List;
+
+import com.gemstone.gemfire.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/BitCountExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/BitCountExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/BitCountExecutor.java
new file mode 100755
index 0000000..aebfae6
--- /dev/null
+++ b/geode-core/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 java.util.List;
+
+import com.gemstone.gemfire.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.RedisConstants;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/BitOpExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/BitOpExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/BitOpExecutor.java
new file mode 100755
index 0000000..d764237
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/BitOpExecutor.java
@@ -0,0 +1,153 @@
+/*
+ * 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 java.util.List;
+
+import com.gemstone.gemfire.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;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/BitPosExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/BitPosExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/BitPosExecutor.java
new file mode 100755
index 0000000..20ebeda
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/BitPosExecutor.java
@@ -0,0 +1,134 @@
+/*
+ * 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 java.util.List;
+
+import com.gemstone.gemfire.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/DecrByExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/DecrByExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/DecrByExecutor.java
new file mode 100755
index 0000000..f51ffff
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/DecrByExecutor.java
@@ -0,0 +1,110 @@
+/*
+ * 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 java.util.List;
+
+import com.gemstone.gemfire.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/DecrExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/DecrExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/DecrExecutor.java
new file mode 100755
index 0000000..a865017
--- /dev/null
+++ b/geode-core/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 java.util.List;
+
+import com.gemstone.gemfire.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;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/GetBitExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/GetBitExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/GetBitExecutor.java
new file mode 100755
index 0000000..9c60044
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/GetBitExecutor.java
@@ -0,0 +1,82 @@
+/*
+ * 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 java.util.List;
+
+import com.gemstone.gemfire.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;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/GetExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/GetExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/GetExecutor.java
new file mode 100755
index 0000000..b4a0ddb
--- /dev/null
+++ b/geode-core/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 com.gemstone.gemfire.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.RedisDataType;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+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()));
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/GetRangeExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/GetRangeExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/GetRangeExecutor.java
new file mode 100755
index 0000000..a70c569
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/GetRangeExecutor.java
@@ -0,0 +1,98 @@
+/*
+ * 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 java.util.Arrays;
+import java.util.List;
+
+import com.gemstone.gemfire.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.RedisDataType;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+public class GetRangeExecutor extends StringExecutor {
+
+ private final String ERROR_NOT_INT = "The indexes provided must be numeric values";
+
+ private final int startIndex = 2;
+
+ private final int stopIndex = 3;
+
+ @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.GETRANGE));
+ return;
+ }
+
+ ByteArrayWrapper key = command.getKey();
+ checkDataType(key, RedisDataType.REDIS_STRING, context);
+ ByteArrayWrapper valueWrapper = r.get(key);
+
+ if (valueWrapper == null) {
+ command.setResponse(Coder.getNilResponse(context.getByteBufAllocator()));
+ return;
+ }
+
+ byte[] value = valueWrapper.toBytes();
+ int length = value.length;
+
+ long start;
+ long end;
+
+
+ try {
+ byte[] startI = commandElems.get(startIndex);
+ byte[] stopI = commandElems.get(stopIndex);
+ start = Coder.bytesToLong(startI);
+ end = Coder.bytesToLong(stopI);
+ } catch (NumberFormatException e) {
+ command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_NOT_INT));
+ return;
+ }
+ start = getBoundedStartIndex(start, length);
+ end = getBoundedEndIndex(end, length);
+
+ /*
+ * If the properly formatted indexes are illegal, send nil
+ */
+ if (start > end || start == length) {
+ command.setResponse(Coder.getNilResponse(context.getByteBufAllocator()));
+ return;
+ }
+ /*
+ * 1 is added to end because the end in copyOfRange is exclusive
+ * but in Redis it is inclusive
+ */
+ if (end != length) end++;
+ byte[] returnRange = Arrays.copyOfRange(value, (int) start, (int) end);
+ if (returnRange == null || returnRange.length == 0) {
+ command.setResponse(Coder.getNilResponse(context.getByteBufAllocator()));
+ return;
+ }
+
+ command.setResponse(Coder.getBulkStringResponse(context.getByteBufAllocator(), returnRange));
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/GetSetExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/GetSetExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/GetSetExecutor.java
new file mode 100755
index 0000000..fa0ca7f
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/GetSetExecutor.java
@@ -0,0 +1,59 @@
+/*
+ * 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 java.util.List;
+
+import com.gemstone.gemfire.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+public class GetSetExecutor 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.GETSET));
+ return;
+ }
+
+ ByteArrayWrapper key = command.getKey();
+ checkAndSetDataType(key, context);
+
+ byte[] newCharValue = commandElems.get(VALUE_INDEX);
+ ByteArrayWrapper newValueWrapper = new ByteArrayWrapper(newCharValue);
+
+ ByteArrayWrapper oldValueWrapper = r.get(key);
+ r.put(key, newValueWrapper);
+
+ if (oldValueWrapper == null) {
+ command.setResponse(Coder.getNilResponse(context.getByteBufAllocator()));
+ } else {
+ command.setResponse(Coder.getBulkStringResponse(context.getByteBufAllocator(), oldValueWrapper.toBytes()));
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/IncrByExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/IncrByExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/IncrByExecutor.java
new file mode 100755
index 0000000..583812c
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/IncrByExecutor.java
@@ -0,0 +1,107 @@
+/*
+ * 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 java.util.List;
+
+import com.gemstone.gemfire.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+public class IncrByExecutor extends StringExecutor {
+
+ private final String ERROR_VALUE_NOT_USABLE = "The value at this key cannot be incremented numerically";
+
+ private final String ERROR_INCREMENT_NOT_USABLE = "The increment on this key must be numeric";
+
+ private final String ERROR_OVERFLOW = "This incrementation cannot be performed due to overflow";
+
+ private final int INCREMENT_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.INCRBY));
+ return;
+ }
+
+ ByteArrayWrapper key = command.getKey();
+ checkAndSetDataType(key, context);
+ ByteArrayWrapper valueWrapper = r.get(key);
+
+ /*
+ * Try increment
+ */
+
+ byte[] incrArray = commandElems.get(INCREMENT_INDEX);
+ Long increment;
+
+ try {
+ increment = Coder.bytesToLong(incrArray);
+ } catch (NumberFormatException e) {
+ command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_INCREMENT_NOT_USABLE));
+ return;
+ }
+
+ /*
+ * Value does not exist
+ */
+
+ if (valueWrapper == null) {
+ r.put(key, new ByteArrayWrapper(incrArray));
+ command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), increment));
+ 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
+ */
+ if (value >= 0 && increment > (Long.MAX_VALUE - value)) {
+ command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_OVERFLOW));
+ return;
+ }
+
+ value += increment;
+
+ 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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/IncrByFloatExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/IncrByFloatExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/IncrByFloatExecutor.java
new file mode 100755
index 0000000..028a223
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/IncrByFloatExecutor.java
@@ -0,0 +1,122 @@
+/*
+ * 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 java.util.List;
+
+import com.gemstone.gemfire.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;
+
+public class IncrByFloatExecutor extends StringExecutor {
+
+ private final String ERROR_VALUE_NOT_USABLE = "Invalid value at this key and cannot be incremented numerically";
+
+ private final String ERROR_INCREMENT_NOT_USABLE = "The increment on this key must be a valid floating point numeric";
+
+ private final String ERROR_OVERFLOW = "This incrementation cannot be performed due to overflow";
+
+ private final int INCREMENT_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.INCRBYFLOAT));
+ return;
+ }
+
+ ByteArrayWrapper key = command.getKey();
+ checkAndSetDataType(key, context);
+ ByteArrayWrapper valueWrapper = r.get(key);
+
+ /*
+ * Try increment
+ */
+
+ byte[] incrArray = commandElems.get(INCREMENT_INDEX);
+ String doub = Coder.bytesToString(incrArray).toLowerCase();
+ if (doub.contains("inf") || doub.contains("nan")) {
+ command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), "Increment would produce NaN or infinity"));
+ return;
+ } else if (valueWrapper != null && valueWrapper.toString().contains(" ")) {
+ command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_VALUE_NOT_USABLE));
+ return;
+ }
+
+
+ Double increment;
+
+ try {
+ increment = Coder.stringToDouble(doub);
+ } catch (NumberFormatException e) {
+ command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_INCREMENT_NOT_USABLE));
+ return;
+ }
+
+ /*
+ * Value does not exist
+ */
+
+ if (valueWrapper == null) {
+ r.put(key, new ByteArrayWrapper(incrArray));
+ command.setResponse(Coder.getBulkStringResponse(context.getByteBufAllocator(), increment));
+ return;
+ }
+
+ /*
+ * Value exists
+ */
+
+ String stringValue = Coder.bytesToString(valueWrapper.toBytes());
+
+ Double value;
+ try {
+ value = Coder.stringToDouble(stringValue);
+ } catch (NumberFormatException e) {
+ command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_VALUE_NOT_USABLE));
+ return;
+ }
+
+ /*
+ * Check for overflow
+ */
+ if (value >= 0 && increment > (Double.MAX_VALUE - value)) {
+ command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_OVERFLOW));
+ return;
+ }
+
+ double result = value + increment;
+ if (Double.isNaN(result) || Double.isInfinite(result)) {
+ command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), RedisConstants.ERROR_NAN_INF_INCR));
+ return;
+ }
+ value += increment;
+
+ stringValue = "" + value;
+ r.put(key, new ByteArrayWrapper(Coder.stringToBytes(stringValue)));
+
+ command.setResponse(Coder.getBulkStringResponse(context.getByteBufAllocator(), value));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/IncrExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/IncrExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/IncrExecutor.java
new file mode 100755
index 0000000..d739561
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/string/IncrExecutor.java
@@ -0,0 +1,91 @@
+/*
+ * 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 java.util.List;
+
+import com.gemstone.gemfire.cache.Region;
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+public class IncrExecutor extends StringExecutor {
+
+ private final String ERROR_VALUE_NOT_USABLE = "The value at this key cannot be incremented numerically";
+
+ private final String ERROR_OVERFLOW = "This incrementation cannot be performed due to overflow";
+
+ private final int INIT_VALUE_INT = 1;
+
+ @Override
+ public void executeCommand(Command command, ExecutionHandlerContext context) {
+ List<byte[]> commandElems = command.getProcessedCommand();
+
+ Region<ByteArrayWrapper, ByteArrayWrapper> r = context.getRegionProvider().getStringsRegion();
+
+ if (commandElems.size() < 2) {
+ command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.INCR));
+ return;
+ }
+
+ ByteArrayWrapper key = command.getKey();
+ checkAndSetDataType(key, context);
+ ByteArrayWrapper valueWrapper = r.get(key);
+
+ /*
+ * Value does not exist
+ */
+
+ if (valueWrapper == null) {
+ byte[] newValue = {Coder.NUMBER_1_BYTE};
+ r.put(key, new ByteArrayWrapper(newValue));
+ 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.MAX_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));
+
+ }
+
+}