http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ListQuery.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ListQuery.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ListQuery.java new file mode 100644 index 0000000..dcd062a --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ListQuery.java @@ -0,0 +1,64 @@ +/* + * 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; + +public enum ListQuery { + + LINDEX { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE key != 'head' AND key != 'tail' ORDER BY key asc LIMIT $1"; + } + }, + LRANGE { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE key != 'head' AND key != 'tail' ORDER BY key asc LIMIT $1"; + } + }, + LREMG { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE value = $1 AND key != 'head' AND key != 'tail' ORDER BY key asc LIMIT $2"; + } + }, + LREML { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE value = $1 AND key != 'head' AND key != 'tail' ORDER BY key desc LIMIT $2"; + } + }, + LREME { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE value = $1 ORDER BY key asc"; + } + }, + LSET { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT * FROM " + fullpath + + ".keySet key WHERE key != 'head' AND key != 'tail' ORDER BY key asc LIMIT $1"; + } + }, + LTRIM { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT * FROM " + fullpath + + ".keySet key WHERE key != 'head' AND key != 'tail' ORDER BY key asc LIMIT $1"; + } + }; + + public abstract String getQueryString(String fullpath); + +}
http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PExpireAtExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PExpireAtExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PExpireAtExecutor.java new file mode 100644 index 0000000..fa68d13 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PExpireAtExecutor.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.redis.internal.executor; + +import org.apache.geode.redis.internal.RedisConstants.ArityDef; + +public class PExpireAtExecutor extends ExpireAtExecutor { + + @Override + protected boolean timeUnitMillis() { + return true; + } + + @Override + public String getArgsError() { + return ArityDef.PEXPIREAT; + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PExpireExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PExpireExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PExpireExecutor.java new file mode 100644 index 0000000..3581d5d --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PExpireExecutor.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.redis.internal.executor; + +import org.apache.geode.redis.internal.RedisConstants.ArityDef; + +public class PExpireExecutor extends ExpireExecutor { + + @Override + protected boolean timeUnitMillis() { + return true; + } + + @Override + public String getArgsError() { + return ArityDef.PEXPIRE; + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PTTLExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PTTLExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PTTLExecutor.java new file mode 100644 index 0000000..9e15d56 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PTTLExecutor.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; + +import org.apache.geode.redis.internal.RedisConstants.ArityDef; + +public class PTTLExecutor extends TTLExecutor { + + + @Override + protected boolean timeUnitMillis() { + return true; + } + + @Override + public String getArgsError() { + return ArityDef.PTTL; + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PersistExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PersistExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PersistExecutor.java new file mode 100644 index 0000000..16bbc0f --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PersistExecutor.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; + +import org.apache.geode.redis.internal.ByteArrayWrapper; +import org.apache.geode.redis.internal.Coder; +import org.apache.geode.redis.internal.Command; +import org.apache.geode.redis.internal.ExecutionHandlerContext; +import org.apache.geode.redis.internal.RedisConstants.ArityDef; + +import java.util.List; + +public class PersistExecutor extends AbstractExecutor { + + private final int TIMEOUT_REMOVED = 1; + + private final int KEY_NOT_EXIST_OR_NO_TIMEOUT = 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.PERSIST)); + return; + } + + ByteArrayWrapper key = command.getKey(); + + boolean canceled = context.getRegionProvider().cancelKeyExpiration(key); + + if (canceled) + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), TIMEOUT_REMOVED)); + else + command.setResponse( + Coder.getIntegerResponse(context.getByteBufAllocator(), KEY_NOT_EXIST_OR_NO_TIMEOUT)); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PingExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PingExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PingExecutor.java new file mode 100644 index 0000000..4561b5c --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/PingExecutor.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.redis.internal.executor; + +import org.apache.geode.redis.internal.Coder; +import org.apache.geode.redis.internal.Command; +import org.apache.geode.redis.internal.ExecutionHandlerContext; + +public class PingExecutor extends AbstractExecutor { + + private final String PING_RESPONSE = "PONG"; + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + command + .setResponse(Coder.getSimpleStringResponse(context.getByteBufAllocator(), PING_RESPONSE)); + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/QuitExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/QuitExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/QuitExecutor.java new file mode 100644 index 0000000..84ad241 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/QuitExecutor.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.redis.internal.executor; + +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; + +public class QuitExecutor extends AbstractExecutor { + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + command.setResponse( + Coder.getSimpleStringResponse(context.getByteBufAllocator(), RedisConstants.QUIT_RESPONSE)); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ScanExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ScanExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ScanExecutor.java new file mode 100644 index 0000000..3f8ea4d --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ScanExecutor.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; + +import org.apache.geode.redis.GeodeRedisServiceImpl; +import org.apache.geode.redis.internal.Coder; +import org.apache.geode.redis.internal.Command; +import org.apache.geode.redis.internal.ExecutionHandlerContext; +import org.apache.geode.redis.internal.RedisConstants; +import org.apache.geode.redis.internal.RedisConstants.ArityDef; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +public class ScanExecutor extends AbstractScanExecutor { + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + List<byte[]> commandElems = command.getProcessedCommand(); + + if (commandElems.size() < 2) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.SCAN)); + return; + } + + String cursorString = command.getStringKey(); + int cursor = 0; + Pattern matchPattern = null; + String globMatchString = 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() > 3) { + try { + byte[] bytes = commandElems.get(2); + String tmp = Coder.bytesToString(bytes); + if (tmp.equalsIgnoreCase("MATCH")) { + bytes = commandElems.get(3); + globMatchString = Coder.bytesToString(bytes); + } else if (tmp.equalsIgnoreCase("COUNT")) { + bytes = commandElems.get(3); + count = Coder.bytesToInt(bytes); + } + } catch (NumberFormatException e) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_COUNT)); + return; + } + } + + if (commandElems.size() > 5) { + try { + byte[] bytes = commandElems.get(4); + String tmp = Coder.bytesToString(bytes); + if (tmp.equalsIgnoreCase("COUNT")) { + bytes = commandElems.get(5); + 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(globMatchString); + } catch (PatternSyntaxException e) { + command.setResponse( + Coder.getErrorResponse(context.getByteBufAllocator(), RedisConstants.ERROR_ILLEGAL_GLOB)); + return; + } + + @SuppressWarnings("unchecked") + List<String> returnList = (List<String>) getIteration(context.getRegionProvider().metaKeySet(), + 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<String> returnList = new ArrayList<String>(); + int size = list.size(); + int beforeCursor = 0; + int numElements = 0; + int i = -1; + for (String key : (Collection<String>) list) { + if (key.equals(GeodeRedisServiceImpl.REDIS_META_DATA_REGION) + || key.equals(GeodeRedisServiceImpl.STRING_REGION) + || key.equals(GeodeRedisServiceImpl.HLL_REGION)) + continue; + i++; + if (beforeCursor < cursor) { + beforeCursor++; + continue; + } else if (numElements < count) { + if (matchPattern != null) { + if (matchPattern.matcher(key).matches()) { + returnList.add(key); + numElements++; + } + } else { + returnList.add(key); + numElements++; + } + } else + break; + } + + if (i == size - (NUM_DEFAULT_REGIONS + 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/ShutDownExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ShutDownExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ShutDownExecutor.java new file mode 100644 index 0000000..0392095 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ShutDownExecutor.java @@ -0,0 +1,25 @@ +/* + * 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; + +import org.apache.geode.redis.internal.Command; +import org.apache.geode.redis.internal.ExecutionHandlerContext; + +public class ShutDownExecutor extends AbstractExecutor { + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) {} + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/SortedSetQuery.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/SortedSetQuery.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/SortedSetQuery.java new file mode 100644 index 0000000..a0a8f63 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/SortedSetQuery.java @@ -0,0 +1,283 @@ +/* + * 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; + +public enum SortedSetQuery { + + ZCOUNTNINFI { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + ".values value WHERE value.score <= $1"; + } + }, + ZCOUNTNINF { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + ".values value WHERE value.score < $1"; + } + }, + ZCOUNTPINFI { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + ".values value WHERE value.score >= $1"; + } + }, + ZCOUNTPINF { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + ".values value WHERE value.score > $1"; + } + }, + ZCOUNTSTI { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + + ".values value WHERE value.score >= $1 AND value.score < $2"; + } + }, + ZCOUNTSTISI { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + + ".values value WHERE value.score >= $1 AND value.score <= $2"; + } + }, + ZCOUNTSI { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + + ".values value WHERE value.score > $1 AND value.score <= $2"; + } + }, + ZCOUNT { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + + ".values value WHERE value.score > $1 AND value.score < $2"; + } + }, + ZLEXCOUNTNINFI { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + ".keySet key WHERE key.compareTo($1) <= 0"; + } + }, + ZLEXCOUNTNINF { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + ".keySet key WHERE key.compareTo($1) < 0"; + } + }, + ZLEXCOUNTPINFI { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + ".keySet key WHERE key.compareTo($1) >= 0"; + } + }, + ZLEXCOUNTPINF { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + ".keySet key WHERE key.compareTo($1) > 0"; + } + }, + ZLEXCOUNTSTI { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + + ".keySet key WHERE key.compareTo($1) >= 0 AND key.compareTo($2) < 0"; + } + }, + ZLEXCOUNTSTISI { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + + ".keySet key WHERE key.compareTo($1) >= 0 AND key.compareTo($2) <= 0"; + } + }, + ZLEXCOUNTSI { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + + ".keySet key WHERE key.compareTo($1) > 0 AND key.compareTo($2) <= 0"; + } + }, + ZLEXCOUNT { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + + ".keySet key WHERE key.compareTo($1) > 0 AND key.compareTo($2) < 0"; + } + }, + ZRANGEBYLEXNINFI { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT * FROM " + fullpath + + ".keySet key WHERE key.compareTo($1) <= 0 ORDER BY key asc LIMIT $2"; + } + }, + ZRANGEBYLEXNINF { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT * FROM " + fullpath + + ".keySet key WHERE key.compareTo($1) < 0 ORDER BY key asc LIMIT $2"; + } + }, + ZRANGEBYLEXPINFI { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT * FROM " + fullpath + + ".keySet key WHERE key.compareTo($1) >= 0 ORDER BY key asc LIMIT $2"; + } + }, + ZRANGEBYLEXPINF { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT * FROM " + fullpath + + ".keySet key WHERE key.compareTo($1) > 0 ORDER BY key asc LIMIT $2"; + } + }, + ZRANGEBYLEXSTI { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT * FROM " + fullpath + + ".keySet key WHERE key.compareTo($1) >= 0 AND key.compareTo($2) < 0 ORDER BY key asc LIMIT $3"; + } + }, + ZRANGEBYLEXSTISI { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT * FROM " + fullpath + + ".keySet key WHERE key.compareTo($1) >= 0 AND key.compareTo($2) <= 0 ORDER BY key asc LIMIT $3"; + } + }, + ZRANGEBYLEXSI { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT * FROM " + fullpath + + ".keySet key WHERE key.compareTo($1) > 0 AND key.compareTo($2) <= 0 ORDER BY key asc LIMIT $3"; + } + }, + ZRANGEBYLEX { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT * FROM " + fullpath + + ".keySet key WHERE key.compareTo($1) > 0 AND key.compareTo($2) < 0 ORDER BY key asc LIMIT $3"; + } + }, + ZREMRANGEBYRANK { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry ORDER BY entry.value asc LIMIT $1"; + } + }, + ZRBSNINFI { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE value.score <= $1 ORDER BY entry.value asc LIMIT $2"; + } + }, + ZRBSNINF { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE entry.value.score < $1 ORDER BY entry.value asc LIMIT $2"; + } + }, + ZRBSPINFI { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE entry.value.score >= $1 ORDER BY entry.value asc LIMIT $2"; + } + }, + ZRBSPINF { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE entry.value.score > $1 ORDER BY entry.value asc LIMIT $2"; + } + }, + ZRBSSTISI { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE entry.value.score >= $1 AND entry.value.score <= $2 ORDER BY entry.value asc LIMIT $3"; + } + }, + ZRBSSTI { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE entry.value.score >= $1 AND entry.value.score < $2 ORDER BY entry.value asc LIMIT $3"; + } + }, + ZRBSSI { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE entry.value.score > $1 AND entry.value.score <= $2 ORDER BY entry.value asc LIMIT $3"; + } + }, + ZRBS { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE entry.value.score > $1 AND entry.value.score < $2 ORDER BY entry.value asc LIMIT $3"; + } + }, + ZREVRBSNINFI { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE value <= $1 ORDER BY entry.value desc, entry.key desc LIMIT $2"; + } + }, + ZREVRBSNINF { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE entry.value.score < $1 ORDER BY entry.value desc, entry.key desc LIMIT $2"; + } + }, + ZREVRBSPINFI { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE entry.value.score >= $1 ORDER BY entry.value desc, entry.key desc LIMIT $2"; + } + }, + ZREVRBSPINF { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE entry.value.score > $1 ORDER BY entry.value desc, entry.key desc LIMIT $2"; + } + }, + ZREVRBSSTISI { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE entry.value.score >= $1 AND entry.value.score <= $2 ORDER BY entry.value desc, entry.key desc LIMIT $3"; + } + }, + ZREVRBSSTI { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE entry.value.score >= $1 AND entry.value.score < $2 ORDER BY entry.value desc, entry.key desc LIMIT $3"; + } + }, + ZREVRBSSI { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE entry.value.score > $1 AND entry.value.score <= $2 ORDER BY entry.value desc, entry.key desc LIMIT $3"; + } + }, + ZREVRBS { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry WHERE entry.value.score > $1 AND entry.value.score < $2 ORDER BY entry.value desc, entry.key desc LIMIT $3"; + } + }, + ZREVRANGE { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry ORDER BY entry.value asc, entry.key asc LIMIT $1"; + } + }, + ZRANGE { + public String getQueryString(String fullpath) { + return "SELECT DISTINCT entry.key, entry.value FROM " + fullpath + + ".entrySet entry ORDER BY entry.value desc, entry.key desc LIMIT $1"; + } + }, + ZRANK { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + + ".entrySet entry WHERE entry.value < $1 OR (entry.value = $2 AND entry.key.compareTo($3) < 0)"; + } + }, + ZREVRANK { + public String getQueryString(String fullpath) { + return "SELECT COUNT(*) FROM " + fullpath + + ".entrySet entry WHERE entry.value > $1 OR (entry.value = $2 AND entry.key.compareTo($3) > 0)"; + } + }; + + public abstract String getQueryString(String fullpath); +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TTLExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TTLExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TTLExecutor.java new file mode 100644 index 0000000..f237342 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TTLExecutor.java @@ -0,0 +1,75 @@ +/* + * 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; + +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.RedisConstants.ArityDef; +import org.apache.geode.redis.internal.RedisDataType; +import org.apache.geode.redis.internal.RegionProvider; + +import java.util.List; + +public class TTLExecutor extends AbstractExecutor implements Extendable { + + private final int NOT_EXISTS = -2; + + private final int NO_TIMEOUT = -1; + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + List<byte[]> commandElems = command.getProcessedCommand(); + + if (commandElems.size() < 2) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), getArgsError())); + return; + } + + ByteArrayWrapper key = command.getKey(); + RegionProvider rC = context.getRegionProvider(); + boolean exists = false; + RedisDataType val = rC.getRedisDataType(key); + if (val != null) + exists = true; + + if (!exists) { + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NOT_EXISTS)); + return; + } + long ttl = rC.getExpirationDelayMillis(key); + + if (ttl == 0L) { + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NO_TIMEOUT)); + return; + } + + if (!timeUnitMillis()) + ttl = ttl / millisInSecond; + + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), ttl)); + } + + protected boolean timeUnitMillis() { + return false; + } + + @Override + public String getArgsError() { + return ArityDef.TTL; + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TimeExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TimeExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TimeExecutor.java new file mode 100644 index 0000000..4094200 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TimeExecutor.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; + +import io.netty.buffer.ByteBuf; +import org.apache.geode.redis.internal.Coder; +import org.apache.geode.redis.internal.Command; +import org.apache.geode.redis.internal.ExecutionHandlerContext; + +public class TimeExecutor extends AbstractExecutor { + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + long timeStamp = System.currentTimeMillis(); + long seconds = timeStamp / 1000; + long microSeconds = (timeStamp - (seconds * 1000)) * 1000; + byte[] secAr = Coder.longToBytes(seconds); + byte[] micAr = Coder.longToBytes(microSeconds); + + ByteBuf response = context.getByteBufAllocator().buffer(50); + response.writeByte(Coder.ARRAY_ID); + response.writeByte(50); // #2 + response.writeBytes(Coder.CRLFar); + response.writeByte(Coder.BULK_STRING_ID); + response.writeBytes(Coder.intToBytes(secAr.length)); + response.writeBytes(Coder.CRLFar); + response.writeBytes(secAr); + response.writeBytes(Coder.CRLFar); + response.writeByte(Coder.BULK_STRING_ID); + response.writeBytes(Coder.intToBytes(micAr.length)); + response.writeBytes(Coder.CRLFar); + response.writeBytes(micAr); + response.writeBytes(Coder.CRLFar); + command.setResponse(response); + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TypeExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TypeExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TypeExecutor.java new file mode 100644 index 0000000..f6a0313 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/TypeExecutor.java @@ -0,0 +1,47 @@ +/* + * 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; + +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 TypeExecutor extends AbstractExecutor { + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + List<byte[]> commandElems = command.getProcessedCommand(); + if (commandElems.size() < 2) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.TYPE)); + return; + } + + ByteArrayWrapper key = command.getKey(); + + RedisDataType type = context.getRegionProvider().getRedisDataType(key); + + if (type == null) + command.setResponse(Coder.getBulkStringResponse(context.getByteBufAllocator(), "none")); + else + command + .setResponse(Coder.getBulkStringResponse(context.getByteBufAllocator(), type.toString())); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/UnkownExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/UnkownExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/UnkownExecutor.java new file mode 100644 index 0000000..d5c2bba --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/UnkownExecutor.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.redis.internal.executor; + +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; + +public class UnkownExecutor extends AbstractExecutor { + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + command.setResponse( + Coder.getErrorResponse(context.getByteBufAllocator(), RedisConstants.ERROR_UNKOWN_COMMAND)); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HDelExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HDelExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HDelExecutor.java new file mode 100644 index 0000000..c034334 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HDelExecutor.java @@ -0,0 +1,65 @@ +/* + * 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.hash; + +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 HDelExecutor extends HashExecutor { + + private final int START_FIELDS_INDEX = 2; + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + List<byte[]> commandElems = command.getProcessedCommand(); + + if (commandElems.size() < 3) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.HDEL)); + return; + } + + int numDeleted = 0; + + ByteArrayWrapper key = command.getKey(); + + checkDataType(key, RedisDataType.REDIS_HASH, context); + Region<ByteArrayWrapper, ByteArrayWrapper> keyRegion = getRegion(context, key); + + if (keyRegion == null) { + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), numDeleted)); + return; + } + + + for (int i = START_FIELDS_INDEX; i < commandElems.size(); i++) { + ByteArrayWrapper field = new ByteArrayWrapper(commandElems.get(i)); + Object oldValue = keyRegion.remove(field); + if (oldValue != null) + numDeleted++; + } + if (keyRegion.isEmpty()) { + context.getRegionProvider().removeKey(key, RedisDataType.REDIS_HASH); + } + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), numDeleted)); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HExistsExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HExistsExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HExistsExecutor.java new file mode 100644 index 0000000..e1eb0e7 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HExistsExecutor.java @@ -0,0 +1,64 @@ +/* + * 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.hash; + +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 HExistsExecutor extends HashExecutor { + + private final int NOT_EXISTS = 0; + + private final int EXISTS = 1; + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + List<byte[]> commandElems = command.getProcessedCommand(); + + if (commandElems.size() < 3) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.HEXISTS)); + return; + } + + ByteArrayWrapper key = command.getKey(); + + checkDataType(key, RedisDataType.REDIS_HASH, context); + Region<ByteArrayWrapper, ByteArrayWrapper> keyRegion = getRegion(context, key); + + if (keyRegion == null) { + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NOT_EXISTS)); + return; + } + + byte[] byteField = commandElems.get(FIELD_INDEX); + ByteArrayWrapper field = new ByteArrayWrapper(byteField); + + boolean hasField = keyRegion.containsKey(field); + + if (hasField) + 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/hash/HGetAllExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HGetAllExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HGetAllExecutor.java new file mode 100644 index 0000000..99138de --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HGetAllExecutor.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.hash; + +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.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +public class HGetAllExecutor extends HashExecutor { + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + List<byte[]> commandElems = command.getProcessedCommand(); + + if (commandElems.size() < 2) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.HGETALL)); + return; + } + + ByteArrayWrapper key = command.getKey(); + + checkDataType(key, RedisDataType.REDIS_HASH, context); + Region<ByteArrayWrapper, ByteArrayWrapper> keyRegion = getRegion(context, key); + + if (keyRegion == null) { + command.setResponse(Coder.getEmptyArrayResponse(context.getByteBufAllocator())); + return; + } + + Collection<Map.Entry<ByteArrayWrapper, ByteArrayWrapper>> entries = + new ArrayList(keyRegion.entrySet()); // This creates a CopyOnRead behavior + + if (entries.isEmpty()) { + command.setResponse(Coder.getEmptyArrayResponse(context.getByteBufAllocator())); + return; + } + + command.setResponse(Coder.getKeyValArrayResponse(context.getByteBufAllocator(), entries)); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HGetExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HGetExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HGetExecutor.java new file mode 100644 index 0000000..858fe80 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HGetExecutor.java @@ -0,0 +1,61 @@ +/* + * 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.hash; + +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 HGetExecutor extends HashExecutor { + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + List<byte[]> commandElems = command.getProcessedCommand(); + + if (commandElems.size() < 3) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.HGET)); + return; + } + + ByteArrayWrapper key = command.getKey(); + + checkDataType(key, RedisDataType.REDIS_HASH, context); + Region<ByteArrayWrapper, ByteArrayWrapper> keyRegion = getRegion(context, key); + + if (keyRegion == null) { + command.setResponse(Coder.getNilResponse(context.getByteBufAllocator())); + return; + } + + byte[] byteField = commandElems.get(FIELD_INDEX); + ByteArrayWrapper field = new ByteArrayWrapper(byteField); + + ByteArrayWrapper valueWrapper = keyRegion.get(field); + + if (valueWrapper != null) { + command.setResponse( + Coder.getBulkStringResponse(context.getByteBufAllocator(), valueWrapper.toBytes())); + } else + command.setResponse(Coder.getNilResponse(context.getByteBufAllocator())); + + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HIncrByExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HIncrByExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HIncrByExecutor.java new file mode 100644 index 0000000..faf9945 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HIncrByExecutor.java @@ -0,0 +1,111 @@ +/* + * 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.hash; + +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 HIncrByExecutor extends HashExecutor { + + private final String ERROR_FIELD_NOT_USABLE = "The value at this field is not an integer"; + + 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 FIELD_INDEX = 2; + + private final int INCREMENT_INDEX = 3; + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + List<byte[]> commandElems = command.getProcessedCommand(); + + if (commandElems.size() < 4) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.HINCRBY)); + return; + } + + 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; + } + + ByteArrayWrapper key = command.getKey(); + + Region<ByteArrayWrapper, ByteArrayWrapper> keyRegion = + getOrCreateRegion(context, key, RedisDataType.REDIS_HASH); + + byte[] byteField = commandElems.get(FIELD_INDEX); + ByteArrayWrapper field = new ByteArrayWrapper(byteField); + + /* + * Put incrememnt as value if field doesn't exist + */ + + ByteArrayWrapper oldValue = keyRegion.get(field); + + if (oldValue == null) { + keyRegion.put(field, new ByteArrayWrapper(incrArray)); + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), increment)); + return; + } + + /* + * If the field did exist then increment the field + */ + + long value; + + try { + value = Long.parseLong(oldValue.toString()); + } catch (NumberFormatException e) { + command.setResponse( + Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_FIELD_NOT_USABLE)); + return; + } + + /* + * Check for overflow + */ + if ((value >= 0 && increment > (Long.MAX_VALUE - value)) + || (value <= 0 && increment < (Long.MIN_VALUE - value))) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_OVERFLOW)); + return; + } + + value += increment; + // String newValue = String.valueOf(value); + + keyRegion.put(field, new ByteArrayWrapper(Coder.longToBytes(value))); + + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), value)); + + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HIncrByFloatExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HIncrByFloatExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HIncrByFloatExecutor.java new file mode 100644 index 0000000..3be182e --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HIncrByFloatExecutor.java @@ -0,0 +1,104 @@ +/* + * 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.hash; + +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 HIncrByFloatExecutor extends HashExecutor { + + private final String ERROR_FIELD_NOT_USABLE = + "The value at this field cannot be incremented numerically because it is not a float"; + + private final String ERROR_INCREMENT_NOT_USABLE = + "The increment on this key must be floating point numeric"; + + private final int FIELD_INDEX = 2; + + private final int INCREMENT_INDEX = 3; + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + List<byte[]> commandElems = command.getProcessedCommand(); + + if (commandElems.size() < 4) { + command.setResponse( + Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.HINCRBYFLOAT)); + return; + } + + byte[] incrArray = commandElems.get(INCREMENT_INDEX); + Double increment; + + try { + increment = Coder.bytesToDouble(incrArray); + } catch (NumberFormatException e) { + command.setResponse( + Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_INCREMENT_NOT_USABLE)); + return; + } + + ByteArrayWrapper key = command.getKey(); + + Region<ByteArrayWrapper, ByteArrayWrapper> keyRegion = + getOrCreateRegion(context, key, RedisDataType.REDIS_HASH); + + byte[] byteField = commandElems.get(FIELD_INDEX); + ByteArrayWrapper field = new ByteArrayWrapper(byteField); + + /* + * Put incrememnt as value if field doesn't exist + */ + + ByteArrayWrapper oldValue = keyRegion.get(field); + + if (oldValue == null) { + keyRegion.put(field, new ByteArrayWrapper(incrArray)); + command.setResponse(Coder.getBulkStringResponse(context.getByteBufAllocator(), increment)); + return; + } + + /* + * If the field did exist then increment the field + */ + String valueS = oldValue.toString(); + if (valueS.contains(" ")) { + command.setResponse( + Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_FIELD_NOT_USABLE)); + return; + } + Double value; + + try { + value = Coder.stringToDouble(valueS); + } catch (NumberFormatException e) { + command.setResponse( + Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_FIELD_NOT_USABLE)); + return; + } + + value += increment; + keyRegion.put(field, new ByteArrayWrapper(Coder.doubleToBytes(value))); + command.setResponse(Coder.getBulkStringResponse(context.getByteBufAllocator(), value)); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HKeysExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HKeysExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HKeysExecutor.java new file mode 100644 index 0000000..01ac817 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HKeysExecutor.java @@ -0,0 +1,61 @@ +/* + * 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.hash; + +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 HKeysExecutor extends HashExecutor { + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + List<byte[]> commandElems = command.getProcessedCommand(); + + if (commandElems.size() < 2) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.HKEYS)); + return; + } + + ByteArrayWrapper key = command.getKey(); + + checkDataType(key, RedisDataType.REDIS_HASH, context); + Region<ByteArrayWrapper, ByteArrayWrapper> keyRegion = getRegion(context, key); + + if (keyRegion == null) { + command.setResponse(Coder.getEmptyArrayResponse(context.getByteBufAllocator())); + return; + } + + Set<ByteArrayWrapper> keys = new HashSet(keyRegion.keySet()); + + if (keys.isEmpty()) { + command.setResponse(Coder.getEmptyArrayResponse(context.getByteBufAllocator())); + return; + } + + // String response = getBulkStringArrayResponse(keys); + + command.setResponse(Coder.getBulkStringArrayResponse(context.getByteBufAllocator(), keys)); + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HLenExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HLenExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HLenExecutor.java new file mode 100644 index 0000000..945a715 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HLenExecutor.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.hash; + +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 HLenExecutor extends HashExecutor { + + 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.HLEN)); + return; + } + + ByteArrayWrapper key = command.getKey(); + checkDataType(key, RedisDataType.REDIS_HASH, context); + + Region<ByteArrayWrapper, ByteArrayWrapper> keyRegion = getRegion(context, key); + + if (keyRegion == null) { + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NOT_EXISTS)); + return; + } + + final int regionSize = keyRegion.size(); + + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), regionSize)); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HMGetExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HMGetExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HMGetExecutor.java new file mode 100644 index 0000000..132e7d5 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HMGetExecutor.java @@ -0,0 +1,71 @@ +/* + * 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.hash; + +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.ArrayList; +import java.util.List; +import java.util.Map; + +public class HMGetExecutor extends HashExecutor { + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + List<byte[]> commandElems = command.getProcessedCommand(); + + if (commandElems.size() < 3) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.HMGET)); + return; + } + + ByteArrayWrapper key = command.getKey(); + + Region<ByteArrayWrapper, ByteArrayWrapper> keyRegion = getRegion(context, key); + checkDataType(key, RedisDataType.REDIS_HASH, context); + + if (keyRegion == null) { + command.setResponse( + Coder.getArrayOfNils(context.getByteBufAllocator(), commandElems.size() - 2)); + return; + } + + ArrayList<ByteArrayWrapper> fields = new ArrayList<ByteArrayWrapper>(); + for (int i = 2; i < commandElems.size(); i++) { + byte[] fieldArray = commandElems.get(i); + ByteArrayWrapper field = new ByteArrayWrapper(fieldArray); + fields.add(field); + } + + Map<ByteArrayWrapper, ByteArrayWrapper> results = keyRegion.getAll(fields); + + ArrayList<ByteArrayWrapper> values = new ArrayList<ByteArrayWrapper>(); + + /* + * This is done to preserve order in the output + */ + for (ByteArrayWrapper field : fields) + values.add(results.get(field)); + + command.setResponse(Coder.getBulkStringArrayResponse(context.getByteBufAllocator(), values)); + + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HMSetExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HMSetExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HMSetExecutor.java new file mode 100644 index 0000000..7cbe1ba --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HMSetExecutor.java @@ -0,0 +1,61 @@ +/* + * 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.hash; + +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.HashMap; +import java.util.List; +import java.util.Map; + +public class HMSetExecutor extends HashExecutor { + + private final String SUCCESS = "OK"; + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + List<byte[]> commandElems = command.getProcessedCommand(); + + if (commandElems.size() < 3 || commandElems.size() % 2 == 1) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.HMSET)); + return; + } + + ByteArrayWrapper key = command.getKey(); + + Region<ByteArrayWrapper, ByteArrayWrapper> keyRegion = + getOrCreateRegion(context, key, RedisDataType.REDIS_HASH); + + Map<ByteArrayWrapper, ByteArrayWrapper> map = new HashMap<ByteArrayWrapper, ByteArrayWrapper>(); + for (int i = 2; i < commandElems.size(); i += 2) { + byte[] fieldArray = commandElems.get(i); + ByteArrayWrapper field = new ByteArrayWrapper(fieldArray); + byte[] value = commandElems.get(i + 1); + map.put(field, new ByteArrayWrapper(value)); + } + + keyRegion.putAll(map); + + command.setResponse(Coder.getSimpleStringResponse(context.getByteBufAllocator(), SUCCESS)); + + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HScanExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HScanExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HScanExecutor.java new file mode 100644 index 0000000..1a8dddc --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HScanExecutor.java @@ -0,0 +1,166 @@ +/* + * 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.hash; + +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.HashSet; +import java.util.List; +import java.util.Map.Entry; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +public class HScanExecutor 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.HSCAN)); + return; + } + + ByteArrayWrapper key = command.getKey(); + @SuppressWarnings("unchecked") + Region<ByteArrayWrapper, ByteArrayWrapper> keyRegion = + (Region<ByteArrayWrapper, ByteArrayWrapper>) context.getRegionProvider().getRegion(key); + checkDataType(key, RedisDataType.REDIS_HASH, context); + 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("MATCH")) { + bytes = commandElems.get(6); + globMatchPattern = Coder.bytesToString(bytes); + } else 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; + } + + List<Object> returnList = + getIteration(new HashSet(keyRegion.entrySet()), matchPattern, count, cursor); + + command.setResponse(Coder.getScanResponse(context.getByteBufAllocator(), returnList)); + } + + @SuppressWarnings("unchecked") + @Override + protected List<Object> 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, ByteArrayWrapper> entry : (Collection<Entry<ByteArrayWrapper, ByteArrayWrapper>>) list) { + ByteArrayWrapper key = entry.getKey(); + ByteArrayWrapper value = entry.getValue(); + i++; + if (beforeCursor < cursor) { + beforeCursor++; + continue; + } else if (numElements < count) { + if (matchPattern != null) { + if (matchPattern.matcher(key.toString()).matches()) { + returnList.add(key); + returnList.add(value); + numElements++; + } + } else { + returnList.add(key); + 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/hash/HSetExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HSetExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HSetExecutor.java new file mode 100644 index 0000000..64952db --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HSetExecutor.java @@ -0,0 +1,77 @@ +/* + * 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.hash; + +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.RedisConstants.ArityDef; +import org.apache.geode.redis.internal.RedisDataType; + +import java.util.List; + +public class HSetExecutor extends HashExecutor implements Extendable { + + private final int EXISTING_FIELD = 0; + + private final int NEW_FIELD = 1; + + private final int VALUE_INDEX = 3; + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + List<byte[]> commandElems = command.getProcessedCommand(); + + if (commandElems.size() < 4) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), getArgsError())); + return; + } + + ByteArrayWrapper key = command.getKey(); + + Region<ByteArrayWrapper, ByteArrayWrapper> keyRegion = + getOrCreateRegion(context, key, RedisDataType.REDIS_HASH); + + byte[] byteField = commandElems.get(FIELD_INDEX); + ByteArrayWrapper field = new ByteArrayWrapper(byteField); + + byte[] value = commandElems.get(VALUE_INDEX); + + Object oldValue; + + if (onlySetOnAbsent()) + oldValue = keyRegion.putIfAbsent(field, new ByteArrayWrapper(value)); + else + oldValue = keyRegion.put(field, new ByteArrayWrapper(value)); + + if (oldValue == null) + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NEW_FIELD)); + else + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), EXISTING_FIELD)); + + } + + protected boolean onlySetOnAbsent() { + return false; + } + + @Override + public String getArgsError() { + return ArityDef.HSET; + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HSetNXExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HSetNXExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HSetNXExecutor.java new file mode 100644 index 0000000..5312527 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/hash/HSetNXExecutor.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.hash; + +import org.apache.geode.redis.internal.RedisConstants.ArityDef; + + +public class HSetNXExecutor extends HSetExecutor { + + @Override + protected boolean onlySetOnAbsent() { + return true; + } + + @Override + public String getArgsError() { + return ArityDef.HSETNX; + } +}
