http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisConstants.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisConstants.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisConstants.java new file mode 100644 index 0000000..84dd44b --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisConstants.java @@ -0,0 +1,308 @@ +/* + * 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; + + +public class RedisConstants { + + public static final int NUM_DEFAULT_KEYS = 3; + + /* + * Responses + */ + public static final String QUIT_RESPONSE = "OK"; + public static final String COMMAND_QUEUED = "QUEUED"; + + + /* + * Error responses + */ + static final String PARSING_EXCEPTION_MESSAGE = + "The command recieved by GeodeRedisServiceImpl was improperly formatted"; + static final String SERVER_ERROR_MESSAGE = "The server had an internal error please try again"; + static final String SERVER_ERROR_UNKNOWN_RESPONSE = "Unkown response"; + static final String SERVER_ERROR_SHUTDOWN = "The server is shutting down"; + static final String ERROR_UNSUPPORTED_OPERATION_IN_TRANSACTION = + "This command is not supported within a transaction"; + static final String ERROR_TRANSACTION_EXCEPTION = + "This transcation cannot be initiated, make sure the command is executed against a replicate region or your data is collocated. If you are using persistent regions, make sure transactions are enabled"; + public static final String ERROR_NOT_NUMERIC = "Illegal non numeric argument"; + public static final String ERROR_UNKOWN_COMMAND = "Unable to process uknown command"; + public static final String ERROR_COMMIT_CONFLICT = + "There has been a conflict with another transaction"; + public static final String ERROR_REGION_CREATION = + "This key could not be created. Gemfire does not allow certain characters to used in keys"; + public static final String ERROR_UNWATCH = + "Keys cannot be watched or unwatched because GemFire watches all keys by default for transactions"; + public static final String ERROR_WATCH = + "Keys cannot be watched or unwatched because GemFire watches all keys by default for transactions"; + public static final String ERROR_ILLEGAL_GLOB = "Incorrect syntax for given glob regex"; + public static final String ERROR_OUT_OF_RANGE = "The number provided is out of range"; + public static final String ERROR_NESTED_MULTI = "The MULTI command cannot be nested"; + public static final String ERROR_NAN_INF_INCR = "increment would produce NaN or Infinity"; + public static final String ERROR_NO_PASS = + "Attempting to authenticate when no password has been set"; + public static final String ERROR_INVALID_PWD = + "Attemping to authenticate with an invalid password"; + public static final String ERROR_NOT_AUTH = "Must authenticate before sending any requests"; + + public static class ArityDef { + + /* + * General + */ + public static final int DBSIZE_ARITY = 0; + public static final String AUTH = + "The wrong number of arguments or syntax was provided, the format for the AUTH command is \"AUTH password\""; + public static final String DBSIZE = null; + public static final String DEL = + "The wrong number of arguments or syntax was provided, the format for the DEL command is \"DEL key [key ...]\""; + public static final String ECHO = + "The wrong number of arguments or syntax was provided, the format for the ECHO command is \"ECHO message\""; + public static final String EXISTS = + "The wrong number of arguments or syntax was provided, the format for the EXISTS command is \"EXISTS key\""; + public static final String EXPIREAT = + "The wrong number of arguments or syntax was provided, the format for the EXPIREAT command is \"EXPIREAT key timestamp\""; + public static final String EXPIRE = + "The wrong number of arguments or syntax was provided, the format for the EXPIRE command is \"EXPIRE key seconds\""; + public static final String FLUSHALL = null; + public static final String KEYS = + "The wrong number of arguments or syntax was provided, the format for the KEYS command is \"KEYS pattern\""; + public static final String PERSIST = + "The wrong number of arguments or syntax was provided, the format for the PERSIST command is \"PERSIST key\""; + public static final String PEXPIREAT = + "The wrong number of arguments or syntax was provided, the format for the PEXPIREAT command is \"PEXPIREAT key milliseconds-timestamp\""; + public static final String PEXPIRE = + "The wrong number of arguments or syntax was provided, the format for the PEXPIRE command is \"PEXPIRE key milliseconds\""; + public static final String PING = null; + public static final String PTTL = + "The wrong number of arguments or syntax was provided, the format for the PTTL command is \"PTTL key\""; + public static final String QUIT = null; + public static final String SCAN = + "The wrong number of arguments or syntax was provided, the format for the SCAN command is \"SCAN cursor [MATCH pattern] [COUNT count]\""; + public static final String SHUTDOWN = null; + public static final String TIME = null; + public static final String TTL = + "The wrong number of arguments or syntax was provided, the format for the TTL command is \"TTL key\""; + public static final String TYPE = + "The wrong number of arguments or syntax was provided, the format for the TYPE command is \"TYPE key\""; + public static final String UNKNOWN = null; + + /* + * Hash + */ + public static final String HDEL = + "The wrong number of arguments or syntax was provided, the format for the HDEL command is \"HDEL key field [field ...]\""; + public static final String HEXISTS = + "The wrong number of arguments or syntax was provided, the format for the HEXISTS command is \"HEXISTS key field\""; + public static final String HGETALL = + "The wrong number of arguments or syntax was provided, the format for the HGETALL command is \"HGETALL key\""; + public static final String HGET = + "The wrong number of arguments or syntax was provided, the format for the HGET command is \"HGET key field\""; + public static final String HINCRBY = + "The wrong number of arguments or syntax was provided, the format for the HINCRBY command is \"HINCRBY key field increment\""; + public static final String HINCRBYFLOAT = + "The wrong number of arguments or syntax was provided, the format for the HINCRBYFLOAT command is \"HINCRBYFLOAT key field increment\""; + public static final String HKEYS = + "The wrong number of arguments or syntax was provided, the format for the HKEYS command is \"HKEYS key\""; + public static final String HLEN = + "The wrong number of arguments or syntax was provided, the format for the HLEN command is \"HLEN key\""; + public static final String HMGET = + "The wrong number of arguments or syntax was provided, the format for the HMGET command is \"HMGET key field [field ...]\""; + public static final String HMSET = + "The wrong number of arguments or syntax was provided, the format for the HMSET command is \"HMSET key field value [field value ...]\", or not every field is associated with a value"; + public static final String HSCAN = + "The wrong number of arguments or syntax was provided, the format for the SSCAN command is \"SSCAN key cursor [MATCH pattern] [COUNT count]\""; + public static final String HSET = + "The wrong number of arguments or syntax was provided, the format for the HSET command is \"HSET key field value\""; + public static final String HSETNX = + "The wrong number of arguments or syntax was provided, the format for the HSETNX command is \"HSETNX key field value\""; + public static final String HVALS = + "The wrong number of arguments or syntax was provided, the format for the HVALS command is \"HVALS key\""; + + /* + * Hll + */ + public static final String PFADD = + "The wrong number of arguments or syntax was provided, the format for the PFADD command is \"PFADD key element [element ...]\""; + public static final String PFCOUNT = + "The wrong number of arguments or syntax was provided, the format for the PFCOUNT command is \"PFCOUNT key [key ...]\""; + public static final String PFMERGE = + "The wrong number of arguments or syntax was provided, the format for the PFMERGE command is \"PFMERGE destkey sourcekey [sourcekey ...]\""; + + /* + * List + */ + public static final String LINDEX = + "The wrong number of arguments or syntax was provided, the format for the LINDEX command is \"LINDEX key index"; + public static final String LINSERT = null; + public static final String LLEN = + "The wrong number of arguments or syntax was provided, the format for the LLEN command is \"LLEN key"; + public static final String LPOP = + "The wrong number of arguments or syntax was provided, the format for the LPOP command is \"LPOP key"; + public static final String LPUSH = + "The wrong number of arguments or syntax was provided, the format for the LPUSH command is \"LPUSH key value [value ...]"; + public static final String LPUSHX = + "The wrong number of arguments or syntax was provided, the format for the LPUSHX command is \"LPUSHX key value"; + public static final String LRANGE = + "The wrong number of arguments or syntax was provided, the format for the LRANGE command is \"LRANGE key start stop\""; + public static final String LREM = + "The wrong number of arguments or syntax was provided, the format for the LREM command is \"LREM key count value\""; + public static final String LSET = + "The wrong number of arguments or syntax was provided, the format for the LSET command is \"LSET key index value\""; + public static final String LTRIM = + "The wrong number of arguments or syntax was provided, the format for the LTRIM command is \"LTRIM key start stop\""; + public static final String RPOP = + "The wrong number of arguments or syntax was provided, the format for the RPOP command is \"RPOP key"; + public static final String RPUSH = + "The wrong number of arguments or syntax was provided, the format for the RPUSH command is \"RPUSH key value [value ...]"; + public static final String RPUSHX = + "The wrong number of arguments or syntax was provided, the format for the RPUSHX command is \"RPUSHX key value"; + + /* + * Set + */ + public static final String SADD = + "The wrong number of arguments or syntax was provided, the format for the SADD command is \"SADD key member [member ...]\""; + public static final String SCARD = + "The wrong number of arguments or syntax was provided, the format for the SCARD command is \"SCARD key\""; + public static final String SDIFF = + "The wrong number of arguments or syntax was provided, the format for the SDIFF command is \"SDIFF key [key ...]\""; + public static final String SDIFFSTORE = + "The wrong number of arguments or syntax was provided, the format for the SDIFF command is \"SDIFFSTORE destination key [key ...]\""; + public static final String SINTER = + "The wrong number of arguments or syntax was provided, the format for the SINTER command is \"SINTER key [key ...]\""; + public static final String SINTERSTORE = + "The wrong number of arguments or syntax was provided, the format for the SINTERSTORE command is \"SINTERSTORE destination key [key ...]\""; + public static final String SISMEMBER = + "The wrong number of arguments or syntax was provided, the format for the SISMEMBER command is \"SISMEMBER key member\""; + public static final String SMEMBERS = + "The wrong number of arguments or syntax was provided, the format for the SMEMBERS command is \"SMEMBERS key\""; + public static final String SMOVE = + "The wrong number of arguments or syntax was provided, the format for the SMOVE command is \"SMOVE source destination member\""; + public static final String SPOP = + "The wrong number of arguments or syntax was provided, the format for the SPOP command is \"SPOP key\""; + public static final String SRANDMEMBER = + "The wrong number of arguments or syntax was provided, the format for the SRANDMEMBER command is \"SRANDMEMBER key [count]\""; + public static final String SREM = + "The wrong number of arguments or syntax was provided, the format for the SREM command is \"SREM key member [member ...]\""; + public static final String SSCAN = + "The wrong number of arguments or syntax was provided, the format for the SSCAN command is \"SSCAN key cursor [MATCH pattern] [COUNT count]\""; + public static final String SUNION = + "The wrong number of arguments or syntax was provided, the format for the SUNION command is \"SUNION key [key ...]\""; + public static final String SUNIONSTORE = + "The wrong number of arguments or syntax was provided, the format for the SUNIONSTORE command is \"SUNIONSTORE destination key [key ...]\""; + + /* + * Sorted set + */ + public static final String ZADD = + "The wrong number of arguments or syntax was provided, the format for the ZADD command is \"ZADD key score member [score member ...]\", or not every score matches to a member"; + public static final String ZCARD = + "The wrong number of arguments or syntax was provided, the format for the ZCARD command is \"ZCARD key\""; + public static final String ZCOUNT = + "The wrong number of arguments or syntax was provided, the format for the ZCOUNT command is \"ZCOUNT key min max\""; + public static final String ZINCRBY = + "The wrong number of arguments or syntax was provided, the format for the ZINCRBY command is \"ZINCRBY key increment member\""; + public static final String ZLEXCOUNT = + "The wrong number of arguments or syntax was provided, the format for the ZLEXCOUNT command is \"ZLEXCOUNT key min max\""; + public static final String ZRANGEBYLEX = + "The wrong number of arguments or syntax was provided, the format for the ZRANGEBYLEX command is \"ZRANGEBYLEX key min max [LIMIT offset count]\""; + public static final String ZRANGEBYSCORE = + "The wrong number of arguments or syntax was provided, the format for the ZRANGEBYSCORE command is \"ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]\""; + public static final String ZRANGE = + "The wrong number of arguments or syntax was provided, the format for the ZRANGE command is \"ZRANGE key start stop [WITHSCORES]\""; + public static final String ZRANK = + "The wrong number of arguments or syntax was provided, the format for the ZRANK command is \"ZRANK key member\""; + public static final String ZREM = + "The wrong number of arguments or syntax was provided, the format for the ZREM command is \"ZREM key member [member ...]\""; + public static final String ZREMRANGEBYLEX = + "The wrong number of arguments or syntax was provided, the format for the ZREMRANGEBYLEX command is \"ZREMRANGEBYLEX key min max\""; + public static final String ZREMRANGEBYRANK = + "The wrong number of arguments or syntax was provided, the format for the ZREMRANGEBYRANK command is \"ZREMRANGEBYRANK key start stop\""; + public static final String ZREMRANGEBYSCORE = + "The wrong number of arguments or syntax was provided, the format for the ZREMRANGEBYSCORE command is \"ZREMRANGEBYSCORE key min max\""; + public static final String ZREVRANGEBYSCORE = + "The wrong number of arguments or syntax was provided, the format for the ZREVRANGEBYSCORE command is \"ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]\""; + public static final String ZREVRANGE = + "The wrong number of arguments or syntax was provided, the format for the ZREVRANGE command is \"ZREVRANGE key start stop [WITHSCORES]\""; + public static final String ZREVRANK = + "The wrong number of arguments or syntax was provided, the format for the ZREVRANK command is \"ZREVRANK key member\""; + public static final String ZSCAN = + "The wrong number of arguments or syntax was provided, the format for the SSCAN command is \"SSCAN key cursor [MATCH pattern] [COUNT count]\""; + public static final String ZSCORE = + "The wrong number of arguments or syntax was provided, the format for the ZSCORE command is \"ZSCORE key member\""; + + /* + * String + */ + public static final String APPEND = + "The wrong number of arguments or syntax was provided, the format for the APPEND command is \"APPEND key value\""; + public static final String BITCOUNT = + "The wrong number of arguments or syntax was provided, the format for the BITCOUNT command is \"BITCOUNT key [start end]\""; + public static final String BITOP = + "The wrong number of arguments or syntax was provided, the format for the BITOP command is \"BITOP operation destkey key [key ...]\""; + public static final String BITPOS = + "The wrong number of arguments or syntax was provided, the format for the BITOPS command is \"BITPOS key bit [start] [end]\""; + public static final String DECRBY = + "The wrong number of arguments or syntax was provided, the format for the DECRBY command is \"DECRRBY key decrement\""; + public static final String DECR = + "The wrong number of arguments or syntax was provided, the format for the DECR command is \"DECR key\""; + public static final String GETBIT = + "The wrong number of arguments or syntax was provided, the format for the GETBIT command is \"GETBIT key offset\""; + public static final String GETEXECUTOR = + "The wrong number of arguments or syntax was provided, the format for the GET command is \"GET key\""; + public static final String GETRANGE = + "The wrong number of arguments or syntax was provided, the format for the GETRANGE command is \"GETRANGE key start end\""; + public static final String GETSET = + "The wrong number of arguments or syntax was provided, the format for the GETSET command is \"GETSET key value\""; + public static final String INCRBY = + "The wrong number of arguments or syntax was provided, the format for the INCRBY command is \"INCRBY key increment\""; + public static final String INCRBYFLOAT = + "The wrong number of arguments or syntax was provided, the format for the INCRBY command is \"INCRBY key increment\""; + public static final String INCR = + "The wrong number of arguments or syntax was provided, the format for the INCR command is \"INCR key\""; + public static final String MGET = + "The wrong number of arguments or syntax was provided, the format for the MGET command is \"MGET key [key ...]\""; + public static final String MSET = + "The wrong number of arguments or syntax was provided, the format for the MSET command is \"MSET key value [key value ...]\", or not every key matches a value"; + public static final String MSETNX = + "The wrong number of arguments or syntax was provided, the format for the MSETNX command is \"MSETNX key value [key value ...]\", or not every key matches a value"; + public static final String PSETEX = + "The wrong number of arguments or syntax was provided, the format for the PSETEX command is \"PSETEX key milliseconds value\""; + public static final String SETBIT = + "The wrong number of arguments or syntax was provided, the format for the SETBIT command is \"SETBIT key offset value\""; + public static final String SET = + "The wrong number of arguments or syntax was provided, the format for the SET command is \"SET key value [EX seconds] [PX milliseconds] [NX|XX]\""; + public static final String SETEX = + "The wrong number of arguments or syntax was provided, the format for the SETEX command is \"SETEX key seconds value\""; + public static final String SETNX = + "The wrong number of arguments or syntax was provided, the format for the SETNX command is \"SETNX key value\""; + public static final String SETRANGE = + "The wrong number of arguments or syntax was provided, the format for the SETRANGE command is \"SETRANGE key offset value\""; + public static final String STRLEN = + "The wrong number of arguments or syntax was provided, the format for the STRELEN command is \"STRLEN key\""; + + /* + * Transaction + */ + public static final String DISCARD = null; + public static final String EXEC = null; + public static final String MULTI = null; + public static final String UNWATCH = null; + public static final String WATCH = null; + } + +}
http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisDataType.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisDataType.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisDataType.java new file mode 100644 index 0000000..9410642 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisDataType.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.redis.internal; + +import org.apache.geode.cache.Region; +import org.apache.geode.redis.GeodeRedisServiceImpl; + +/** + * The RedisDataType enum contains the choices to which every {@link Region} on the server must be. + * There is only one instance of {@link #REDIS_STRING} and {@link #REDIS_PROTECTED} defined by + * {@link GeodeRedisServiceImpl#STRING_REGION} and + * {@link GeodeRedisServiceImpl#REDIS_META_DATA_REGION} respectively. + * <p> + * The data types are: + * <li>{@link RedisDataType#REDIS_STRING}</li> + * <li>{@link RedisDataType#REDIS_HASH}</li> + * <li>{@link RedisDataType#REDIS_LIST}</li> + * <li>{@link RedisDataType#REDIS_SET}</li> + * <li>{@link RedisDataType#REDIS_SORTEDSET}</li> + * <li>{@link RedisDataType#REDIS_PROTECTED}</li> + * + */ +public enum RedisDataType { + /** + * Strings Regions + */ + REDIS_STRING { + @Override + public String toString() { + return "string"; + } + }, + + /** + * Hashes Regions + */ + REDIS_HASH { + @Override + public String toString() { + return "hash"; + } + }, + + /** + * Lists Regions + */ + REDIS_LIST { + @Override + public String toString() { + return "list"; + } + }, + + /** + * Sets Regions + */ + REDIS_SET { + @Override + public String toString() { + return "set"; + } + }, + + /** + * SortedSets Regions + */ + REDIS_SORTEDSET { + @Override + public String toString() { + return "zset"; + } + }, + + /** + * HyperLogLog Regions + */ + REDIS_HLL { + @Override + public String toString() { + return "hyperloglog"; + } + }, + + /** + * Regions protected from overwrite or deletion + */ + REDIS_PROTECTED { + @Override + public String toString() { + return "protected"; + } + }, + + /** + * None + */ + NONE { + @Override + public String toString() { + return "none"; + } + }; + +}; http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisDataTypeMismatchException.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisDataTypeMismatchException.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisDataTypeMismatchException.java new file mode 100644 index 0000000..727412b --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/RedisDataTypeMismatchException.java @@ -0,0 +1,35 @@ +/* + * 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; + +/** + * This exception is for the case that a client attempts to operate on a data structure of one + * {@link RedisDataType} with a command that is of another type + * + * + */ +public class RedisDataTypeMismatchException extends RuntimeException { + + private static final long serialVersionUID = -2451663685348513870L; + + public RedisDataTypeMismatchException() { + super(); + } + + public RedisDataTypeMismatchException(String message) { + super(message); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/RegionCreationException.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/RegionCreationException.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/RegionCreationException.java new file mode 100644 index 0000000..afc009e --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/RegionCreationException.java @@ -0,0 +1,37 @@ +/* + * 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; + +/** + * This exception is used when an error happens while creating a + * {@link org.apache.geode.cache.Region} globally + * + * + */ +public class RegionCreationException extends RuntimeException { + + public RegionCreationException() {} + + public RegionCreationException(String err) { + super(err); + } + + public RegionCreationException(String err, Throwable cause) { + super(err, cause); + } + + private static final long serialVersionUID = 8416820139078312997L; + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/RegionProvider.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/RegionProvider.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/RegionProvider.java new file mode 100644 index 0000000..deacee0 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/RegionProvider.java @@ -0,0 +1,567 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.redis.internal; + +import org.apache.geode.cache.Cache; +import org.apache.geode.cache.CacheTransactionManager; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.RegionShortcut; +import org.apache.geode.cache.TransactionId; +import org.apache.geode.cache.query.IndexExistsException; +import org.apache.geode.cache.query.IndexInvalidException; +import org.apache.geode.cache.query.IndexNameConflictException; +import org.apache.geode.cache.query.Query; +import org.apache.geode.cache.query.QueryInvalidException; +import org.apache.geode.cache.query.QueryService; +import org.apache.geode.cache.query.RegionNotFoundException; +import org.apache.geode.internal.cache.GemFireCacheImpl; +import org.apache.geode.management.cli.Result; +import org.apache.geode.management.cli.Result.Status; +import org.apache.geode.management.internal.cli.commands.CreateAlterDestroyRegionCommands; +import org.apache.geode.redis.GeodeRedisServiceImpl; +import org.apache.geode.redis.internal.executor.ExpirationExecutor; +import org.apache.geode.redis.internal.executor.ListQuery; +import org.apache.geode.redis.internal.executor.SortedSetQuery; +import org.apache.geode.redis.internal.hll.HyperLogLogPlus; + +import java.io.Closeable; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * This class stands between {@link Executor} and {@link Cache#getRegion(String)}. This is needed + * because some keys for Redis represented as a {@link Region} in {@link GeodeRedisServiceImpl} come + * with additional state. Therefore getting, creating, or destroying a {@link Region} needs to be + * synchronized, which is done away with and abstracted by this class. + * + * + */ +public class RegionProvider implements Closeable { + + private final ConcurrentHashMap<ByteArrayWrapper, Region<?, ?>> regions; + + /** + * This is the Redis meta data {@link Region} that holds the {@link RedisDataType} information for + * all Regions created. The mapping is a {@link String} key which is the name of the + * {@link Region} created to hold the data to the RedisDataType it contains. + */ + private final Region<String, RedisDataType> redisMetaRegion; + + /** + * This is the {@link RedisDataType#REDIS_STRING} {@link Region}. This is the Region that stores + * all string contents + */ + private final Region<ByteArrayWrapper, ByteArrayWrapper> stringsRegion; + + /** + * This is the {@link RedisDataType#REDIS_HLL} {@link Region}. This is the Region that stores all + * HyperLogLog contents + */ + private final Region<ByteArrayWrapper, HyperLogLogPlus> hLLRegion; + + private final Cache cache; + private final QueryService queryService; + private final ConcurrentMap<ByteArrayWrapper, Map<Enum<?>, Query>> preparedQueries = + new ConcurrentHashMap<ByteArrayWrapper, Map<Enum<?>, Query>>(); + private final ConcurrentMap<ByteArrayWrapper, ScheduledFuture<?>> expirationsMap; + private final ScheduledExecutorService expirationExecutor; + private final RegionShortcut defaultRegionType; + private static final CreateAlterDestroyRegionCommands cliCmds = + new CreateAlterDestroyRegionCommands(); + private final ConcurrentHashMap<String, Lock> locks; + + public RegionProvider(Region<ByteArrayWrapper, ByteArrayWrapper> stringsRegion, + Region<ByteArrayWrapper, HyperLogLogPlus> hLLRegion, + Region<String, RedisDataType> redisMetaRegion, + ConcurrentMap<ByteArrayWrapper, ScheduledFuture<?>> expirationsMap, + ScheduledExecutorService expirationExecutor, RegionShortcut defaultShortcut) { + if (stringsRegion == null || hLLRegion == null || redisMetaRegion == null) + throw new NullPointerException(); + this.regions = new ConcurrentHashMap<ByteArrayWrapper, Region<?, ?>>(); + this.stringsRegion = stringsRegion; + this.hLLRegion = hLLRegion; + this.redisMetaRegion = redisMetaRegion; + this.cache = GemFireCacheImpl.getInstance(); + this.queryService = cache.getQueryService(); + this.expirationsMap = expirationsMap; + this.expirationExecutor = expirationExecutor; + this.defaultRegionType = defaultShortcut; + this.locks = new ConcurrentHashMap<String, Lock>(); + } + + public boolean existsKey(ByteArrayWrapper key) { + return this.redisMetaRegion.containsKey(key.toString()); + } + + public Set<String> metaKeySet() { + return this.redisMetaRegion.keySet(); + } + + public Set<Entry<String, RedisDataType>> metaEntrySet() { + return this.redisMetaRegion.entrySet(); + } + + public int getMetaSize() { + return this.redisMetaRegion.size() - RedisConstants.NUM_DEFAULT_KEYS; + } + + private boolean metaRemoveEntry(ByteArrayWrapper key) { + return this.redisMetaRegion.remove(key.toString()) != null; + } + + public RedisDataType metaPutIfAbsent(ByteArrayWrapper key, RedisDataType value) { + return this.redisMetaRegion.putIfAbsent(key.toString(), value); + } + + public RedisDataType metaPut(ByteArrayWrapper key, RedisDataType value) { + return this.redisMetaRegion.put(key.toString(), value); + } + + public RedisDataType metaGet(ByteArrayWrapper key) { + return this.redisMetaRegion.get(key.toString()); + } + + public Region<?, ?> getRegion(ByteArrayWrapper key) { + return this.regions.get(key); + } + + public void removeRegionReferenceLocally(ByteArrayWrapper key, RedisDataType type) { + Lock lock = this.locks.get(key.toString()); + boolean locked = false; + try { + locked = lock.tryLock(); + // If we cannot get the lock we ignore this remote event, this key has local event + // that started independently, ignore this event to prevent deadlock + if (locked) { + cancelKeyExpiration(key); + removeRegionState(key, type); + } + } finally { + if (locked) { + lock.unlock(); + } + } + } + + public boolean removeKey(ByteArrayWrapper key) { + RedisDataType type = getRedisDataType(key); + return removeKey(key, type); + } + + public boolean removeKey(ByteArrayWrapper key, RedisDataType type) { + return removeKey(key, type, true); + } + + public boolean removeKey(ByteArrayWrapper key, RedisDataType type, boolean cancelExpiration) { + if (type == null || type == RedisDataType.REDIS_PROTECTED) + return false; + Lock lock = this.locks.get(key.toString()); + try { + if (lock != null) {// Strings/hlls will not have locks + lock.lock(); + } + metaRemoveEntry(key); + try { + if (type == RedisDataType.REDIS_STRING) { + return this.stringsRegion.remove(key) != null; + } else if (type == RedisDataType.REDIS_HLL) { + return this.hLLRegion.remove(key) != null; + } else { + return destroyRegion(key, type); + } + } catch (Exception exc) { + return false; + } finally { + if (cancelExpiration) + cancelKeyExpiration(key); + else + removeKeyExpiration(key); + if (lock != null) + this.locks.remove(key.toString()); + } + } finally { + if (lock != null) { + lock.unlock(); + } + } + } + + public Region<?, ?> getOrCreateRegion(ByteArrayWrapper key, RedisDataType type, + ExecutionHandlerContext context) { + return getOrCreateRegion0(key, type, context, true); + } + + public void createRemoteRegionReferenceLocally(ByteArrayWrapper key, RedisDataType type) { + if (type == null || type == RedisDataType.REDIS_STRING || type == RedisDataType.REDIS_HLL) + return; + Region<?, ?> r = this.regions.get(key); + if (r != null) + return; + if (!this.regions.contains(key)) { + String stringKey = key.toString(); + Lock lock = this.locks.get(stringKey); + if (lock == null) { + this.locks.putIfAbsent(stringKey, new ReentrantLock()); + lock = this.locks.get(stringKey); + } + boolean locked = false; + try { + locked = lock.tryLock(); + // If we cannot get the lock then this remote event may have been initialized + // independently on this machine, so if we wait on the lock it is more than + // likely we will deadlock just to do the same task. This event can be ignored + if (locked) { + r = cache.getRegion(key.toString()); + // If r is null, this implies that we are after a create/destroy + // simply ignore. Calls to getRegion or getOrCreate will work correctly + if (r == null) + return; + + if (type == RedisDataType.REDIS_LIST) { + doInitializeList(key, r); + } else if (type == RedisDataType.REDIS_SORTEDSET) { + try { + doInitializeSortedSet(key, r); + } catch (RegionNotFoundException | IndexInvalidException e) { + // ignore + } + } + this.regions.put(key, r); + } + } finally { + if (locked) { + lock.unlock(); + } + } + } + } + + private Region<?, ?> getOrCreateRegion0(ByteArrayWrapper key, RedisDataType type, + ExecutionHandlerContext context, boolean addToMeta) { + checkDataType(key, type); + Region<?, ?> r = this.regions.get(key); + if (r != null && r.isDestroyed()) { + removeKey(key, type); + r = null; + } + if (r == null) { + String stringKey = key.toString(); + Lock lock = this.locks.get(stringKey); + if (lock == null) { + this.locks.putIfAbsent(stringKey, new ReentrantLock()); + lock = this.locks.get(stringKey); + } + + try { + lock.lock(); + r = regions.get(key); + if (r == null) { + boolean hasTransaction = context != null && context.hasTransaction(); // Can create + // without context + CacheTransactionManager txm = null; + TransactionId transactionId = null; + try { + if (hasTransaction) { + txm = cache.getCacheTransactionManager(); + transactionId = txm.suspend(); + } + Exception concurrentCreateDestroyException = null; + do { + concurrentCreateDestroyException = null; + r = createRegionGlobally(stringKey); + try { + if (type == RedisDataType.REDIS_LIST) { + doInitializeList(key, r); + } else if (type == RedisDataType.REDIS_SORTEDSET) { + try { + doInitializeSortedSet(key, r); + } catch (RegionNotFoundException | IndexInvalidException e) { + concurrentCreateDestroyException = e; + } + } + } catch (QueryInvalidException e) { + if (e.getCause() instanceof RegionNotFoundException) { + concurrentCreateDestroyException = e; + } + } + } while (concurrentCreateDestroyException != null); + this.regions.put(key, r); + if (addToMeta) { + RedisDataType existingType = metaPutIfAbsent(key, type); + if (existingType != null && existingType != type) + throw new RedisDataTypeMismatchException( + "The key name \"" + key + "\" is already used by a " + existingType.toString()); + } + } finally { + if (hasTransaction) + txm.resume(transactionId); + } + } + } finally { + lock.unlock(); + } + } + return r; + } + + /** + * SYNCHRONIZE EXTERNALLY OF this.locks.get(key.toString())!!!!! + * + * @param key Key of region to destroy + * @param type Type of region to destroyu + * @return Flag if destroyed + */ + private boolean destroyRegion(ByteArrayWrapper key, RedisDataType type) { + Region<?, ?> r = this.regions.get(key); + if (r != null) { + try { + r.destroyRegion(); + } catch (Exception e) { + return false; + } finally { + removeRegionState(key, type); + } + } + return true; + } + + /** + * Do not call this method if you are not synchronized on the lock associated with this key + * + * @param key Key of region to remove + * @param type Type of key to remove all state + */ + private void removeRegionState(ByteArrayWrapper key, RedisDataType type) { + this.preparedQueries.remove(key); + this.regions.remove(key); + } + + private void doInitializeSortedSet(ByteArrayWrapper key, Region<?, ?> r) + throws RegionNotFoundException, IndexInvalidException { + String fullpath = r.getFullPath(); + try { + queryService.createIndex("scoreIndex", "entry.value.score", + r.getFullPath() + ".entrySet entry"); + queryService.createIndex("scoreIndex2", "value.score", r.getFullPath() + ".values value"); + } catch (IndexNameConflictException | IndexExistsException | UnsupportedOperationException e) { + // ignore, these indexes already exist or unsupported but make sure prepared queries are made + } + HashMap<Enum<?>, Query> queryList = new HashMap<Enum<?>, Query>(); + for (SortedSetQuery lq : SortedSetQuery.values()) { + String queryString = lq.getQueryString(fullpath); + Query query = this.queryService.newQuery(queryString); + queryList.put(lq, query); + } + this.preparedQueries.put(key, queryList); + } + + private void doInitializeList(ByteArrayWrapper key, Region r) { + r.put("head", Integer.valueOf(0)); + r.put("tail", Integer.valueOf(0)); + String fullpath = r.getFullPath(); + HashMap<Enum<?>, Query> queryList = new HashMap<Enum<?>, Query>(); + for (ListQuery lq : ListQuery.values()) { + String queryString = lq.getQueryString(fullpath); + Query query = this.queryService.newQuery(queryString); + queryList.put(lq, query); + } + this.preparedQueries.put(key, queryList); + } + + /** + * This method creates a Region globally with the given name. If there is an error in the + * creation, a runtime exception will be thrown. + * + * @param key Name of Region to create + * @return Region Region created globally + */ + private Region<?, ?> createRegionGlobally(String key) { + Region<?, ?> r = null; + r = cache.getRegion(key); + if (r != null) + return r; + do { + Result result = cliCmds.createRegion(key, defaultRegionType, null, null, true, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null); + r = cache.getRegion(key); + if (result.getStatus() == Status.ERROR && r == null) { + String err = ""; + while (result.hasNextLine()) + err += result.nextLine(); + throw new RegionCreationException(err); + } + } while (r == null); // The region can be null in the case that it is concurrently destroyed by + // a remote even triggered internally by Geode + return r; + } + + public Query getQuery(ByteArrayWrapper key, Enum<?> query) { + return this.preparedQueries.get(key).get(query); + /* + * if (query instanceof ListQuery) { return + * this.queryService.newQuery(((ListQuery)query).getQueryString(this.regions.get(key). + * getFullPath())); } else { return + * this.queryService.newQuery(((SortedSetQuery)query).getQueryString(this.regions.get(key). + * getFullPath())); } + */ + } + + /** + * Checks if the given key is associated with the passed data type. If there is a mismatch, a + * {@link RuntimeException} is thrown + * + * @param key Key to check + * @param type Type to check to + */ + protected void checkDataType(ByteArrayWrapper key, RedisDataType type) { + RedisDataType currentType = redisMetaRegion.get(key.toString()); + if (currentType == null) + return; + if (currentType == RedisDataType.REDIS_PROTECTED) + throw new RedisDataTypeMismatchException("The key name \"" + key + "\" is protected"); + if (currentType != type) + throw new RedisDataTypeMismatchException( + "The key name \"" + key + "\" is already used by a " + currentType.toString()); + } + + public boolean regionExists(ByteArrayWrapper key) { + return this.regions.containsKey(key); + } + + public Region<ByteArrayWrapper, ByteArrayWrapper> getStringsRegion() { + return this.stringsRegion; + } + + public Region<ByteArrayWrapper, HyperLogLogPlus> gethLLRegion() { + return this.hLLRegion; + } + + private RedisDataType getRedisDataType(String key) { + return this.redisMetaRegion.get(key); + } + + public RedisDataType getRedisDataType(ByteArrayWrapper key) { + return getRedisDataType(key.toString()); + } + + /** + * Sets the expiration for a key. The setting and modifying of a key expiration can only be set by + * a delay, which means that both expiring after a time and at a time can be done but the delay to + * expire at a time must be calculated before these calls. It is also important to note that the + * delay is always handled in milliseconds + * + * @param key The key to set the expiration for + * @param delay The delay in milliseconds of the expiration + * @return True is expiration set, false otherwise + */ + public final boolean setExpiration(ByteArrayWrapper key, long delay) { + RedisDataType type = getRedisDataType(key); + if (type == null) + return false; + ScheduledFuture<?> future = this.expirationExecutor + .schedule(new ExpirationExecutor(key, type, this), delay, TimeUnit.MILLISECONDS); + this.expirationsMap.put(key, future); + return true; + } + + /** + * Modifies an expiration on a key + * + * @param key String key to modify expiration on + * @param delay Delay in milliseconds to reset the expiration to + * @return True if reset, false if not + */ + public final boolean modifyExpiration(ByteArrayWrapper key, long delay) { + /* + * Attempt to cancel future task + */ + boolean canceled = cancelKeyExpiration(key); + + if (!canceled) + return false; + + RedisDataType type = getRedisDataType(key); + if (type == null) + return false; + + ScheduledFuture<?> future = this.expirationExecutor + .schedule(new ExpirationExecutor(key, type, this), delay, TimeUnit.MILLISECONDS); + this.expirationsMap.put(key, future); + return true; + } + + /** + * Removes an expiration from a key + * + * @param key Key + * @return True is expiration cancelled on the key, false otherwise + */ + public final boolean cancelKeyExpiration(ByteArrayWrapper key) { + ScheduledFuture<?> future = expirationsMap.remove(key); + if (future == null) + return false; + return future.cancel(false); + } + + private boolean removeKeyExpiration(ByteArrayWrapper key) { + return expirationsMap.remove(key) != null; + } + + /** + * Check method if key has expiration + * + * @param key Key + * @return True if key has expiration, false otherwise + */ + public boolean hasExpiration(ByteArrayWrapper key) { + return this.expirationsMap.containsKey(key); + } + + /** + * Get remaining expiration time + * + * @param key Key + * @return Remaining time in milliseconds or 0 if no delay or key doesn't exist + */ + public final long getExpirationDelayMillis(ByteArrayWrapper key) { + ScheduledFuture<?> future = this.expirationsMap.get(key); + return future != null ? future.getDelay(TimeUnit.MILLISECONDS) : 0L; + } + + @Override + public void close() { + this.preparedQueries.clear(); + } + + public String dumpRegionsCache() { + StringBuilder builder = new StringBuilder(); + for (Entry<ByteArrayWrapper, Region<?, ?>> e : this.regions.entrySet()) { + builder.append(e.getKey() + " --> {" + e.getValue() + "}\n"); + } + return builder.toString(); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/AbstractExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/AbstractExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/AbstractExecutor.java new file mode 100644 index 0000000..590ab06 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/AbstractExecutor.java @@ -0,0 +1,139 @@ +/* + * 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.cache.Region; +import org.apache.geode.cache.query.Query; +import org.apache.geode.redis.GeodeRedisServiceImpl; +import org.apache.geode.redis.internal.ByteArrayWrapper; +import org.apache.geode.redis.internal.ExecutionHandlerContext; +import org.apache.geode.redis.internal.Executor; +import org.apache.geode.redis.internal.RedisDataType; +import org.apache.geode.redis.internal.RedisDataTypeMismatchException; +import org.apache.geode.redis.internal.RegionProvider; + +/** + * The AbstractExecutor is the base of all {@link Executor} types for the + * {@link GeodeRedisServiceImpl}. + * + * + */ +public abstract class AbstractExecutor implements Executor { + + /** + * Number of Regions used by GeodeRedisServiceImpl internally + */ + public static final int NUM_DEFAULT_REGIONS = 3; + + /** + * Max length of a list + */ + protected static final Integer INFINITY_LIMIT = Integer.MAX_VALUE; + + /** + * Constant of number of milliseconds in a second + */ + protected static final int millisInSecond = 1000; + + /** + * Getter method for a {@link Region} in the case that a Region should be created if one with the + * given name does not exist. Before getting or creating a Region, a check is first done to make + * sure the desired key doesn't already exist with a different {@link RedisDataType}. If there is + * a data type mismatch this method will throw a {@link RuntimeException}. + * + * ********************** IMPORTANT NOTE ********************************************** This + * method will not fail in returning a Region unless an internal error occurs, so if a Region is + * destroyed right after it is created, it will attempt to retry until a reference to that Region + * is obtained + * ************************************************************************************* + * + * @param context Client client + * @param key String key of desired key + * @param type Type of data type desired + * @return Region with name key + */ + protected Region<?, ?> getOrCreateRegion(ExecutionHandlerContext context, ByteArrayWrapper key, + RedisDataType type) { + return context.getRegionProvider().getOrCreateRegion(key, type, context); + } + + /** + * Checks if the given key is associated with the passed data type. If there is a mismatch, a + * {@link RuntimeException} is thrown + * + * @param key Key to check + * @param type Type to check to + * @param context context + */ + protected void checkDataType(ByteArrayWrapper key, RedisDataType type, + ExecutionHandlerContext context) { + RedisDataType currentType = context.getRegionProvider().getRedisDataType(key); + if (currentType == null) + return; + if (currentType == RedisDataType.REDIS_PROTECTED) + throw new RedisDataTypeMismatchException("The key name \"" + key + "\" is protected"); + if (currentType != type) + throw new RedisDataTypeMismatchException( + "The key name \"" + key + "\" is already used by a " + currentType.toString()); + } + + protected Query getQuery(ByteArrayWrapper key, Enum<?> type, ExecutionHandlerContext context) { + return context.getRegionProvider().getQuery(key, type); + } + + protected boolean removeEntry(ByteArrayWrapper key, RedisDataType type, + ExecutionHandlerContext context) { + if (type == null || type == RedisDataType.REDIS_PROTECTED) + return false; + RegionProvider rC = context.getRegionProvider(); + return rC.removeKey(key, type); + } + + protected int getBoundedStartIndex(int index, int size) { + if (size < 0) + throw new IllegalArgumentException("Size < 0, really?"); + if (index >= 0) + return Math.min(index, size); + else + return Math.max(index + size, 0); + } + + protected int getBoundedEndIndex(int index, int size) { + if (size < 0) + throw new IllegalArgumentException("Size < 0, really?"); + if (index >= 0) + return Math.min(index, size); + else + return Math.max(index + size, -1); + } + + protected long getBoundedStartIndex(long index, long size) { + if (size < 0L) + throw new IllegalArgumentException("Size < 0, really?"); + if (index >= 0L) + return Math.min(index, size); + else + return Math.max(index + size, 0); + } + + protected long getBoundedEndIndex(long index, long size) { + if (size < 0L) + throw new IllegalArgumentException("Size < 0, really?"); + if (index >= 0L) + return Math.min(index, size); + else + return Math.max(index + size, -1); + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/AbstractScanExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/AbstractScanExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/AbstractScanExecutor.java new file mode 100644 index 0000000..02894aa --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/AbstractScanExecutor.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.org.apache.hadoop.fs.GlobPattern; + +import java.util.Collection; +import java.util.List; +import java.util.regex.Pattern; + + +public abstract class AbstractScanExecutor extends AbstractExecutor { + + protected final String ERROR_CURSOR = "Invalid cursor"; + + protected final String ERROR_COUNT = "Count must be numeric and positive"; + + protected final String ERROR_INVALID_CURSOR = + "Cursor is invalid, dataset may have been altered if this is cursor from a previous scan"; + + protected final int DEFUALT_COUNT = 10; + + protected abstract List<?> getIteration(Collection<?> list, Pattern matchPatter, int count, + int cursor); + + /** + * @param pattern A glob pattern. + * @return A regex pattern to recognize the given glob pattern. + */ + protected final Pattern convertGlobToRegex(String pattern) { + if (pattern == null) + return null; + return GlobPattern.compile(pattern); + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/AuthExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/AuthExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/AuthExecutor.java new file mode 100644 index 0000000..2a63fa8 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/AuthExecutor.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.redis.internal.executor; + +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.Executor; +import org.apache.geode.redis.internal.RedisConstants; +import org.apache.geode.redis.internal.RedisConstants.ArityDef; + +import java.util.Arrays; +import java.util.List; + +public class AuthExecutor implements Executor { + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + List<byte[]> commandElems = command.getProcessedCommand(); + + if (commandElems.size() < 2) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.AUTH)); + return; + } + byte[] pwd = context.getAuthPwd(); + if (pwd == null) { + command.setResponse( + Coder.getErrorResponse(context.getByteBufAllocator(), RedisConstants.ERROR_NO_PASS)); + return; + } + boolean correct = Arrays.equals(commandElems.get(1), pwd); + + if (correct) { + context.setAuthenticationVerified(); + command.setResponse(Coder.getSimpleStringResponse(context.getByteBufAllocator(), "OK")); + } else { + command.setResponse( + Coder.getErrorResponse(context.getByteBufAllocator(), RedisConstants.ERROR_INVALID_PWD)); + } + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/DBSizeExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/DBSizeExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/DBSizeExecutor.java new file mode 100644 index 0000000..0a121cc --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/DBSizeExecutor.java @@ -0,0 +1,29 @@ +/* + * 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 DBSizeExecutor extends AbstractExecutor { + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + int size = context.getRegionProvider().getMetaSize(); + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), size)); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/DelExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/DelExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/DelExecutor.java new file mode 100644 index 0000000..f827fa8 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/DelExecutor.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.redis.internal.executor; + +import org.apache.geode.cache.UnsupportedOperationInTransactionException; +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 DelExecutor extends AbstractExecutor { + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + if (context.hasTransaction()) + throw new UnsupportedOperationInTransactionException(); + + List<byte[]> commandElems = command.getProcessedCommand(); + if (commandElems.size() < 2) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.DEL)); + return; + } + + int numRemoved = 0; + + for (int i = 1; i < commandElems.size(); i++) { + byte[] byteKey = commandElems.get(i); + ByteArrayWrapper key = new ByteArrayWrapper(byteKey); + RedisDataType type = context.getRegionProvider().getRedisDataType(key); + if (removeEntry(key, type, context)) + numRemoved++; + } + + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), numRemoved)); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/EchoExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/EchoExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/EchoExecutor.java new file mode 100644 index 0000000..acbeb2a --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/EchoExecutor.java @@ -0,0 +1,38 @@ +/* + * 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.ArityDef; + +import java.util.List; + +public class EchoExecutor 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.ECHO)); + return; + } + + byte[] echoMessage = commandElems.get(1); + command.setResponse(Coder.getBulkStringResponse(context.getByteBufAllocator(), echoMessage)); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExistsExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExistsExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExistsExecutor.java new file mode 100644 index 0000000..ca7991e --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExistsExecutor.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 java.util.List; + +public class ExistsExecutor extends AbstractExecutor { + private final int EXISTS = 1; + + private final int NOT_EXISTS = 0; + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + List<byte[]> commandElems = command.getProcessedCommand(); + if (commandElems.size() < 2) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), ArityDef.EXISTS)); + return; + } + + ByteArrayWrapper key = command.getKey(); + boolean exists = context.getRegionProvider().existsKey(key); + + if (exists) + 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/ExpirationExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExpirationExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExpirationExecutor.java new file mode 100644 index 0000000..86503f1 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExpirationExecutor.java @@ -0,0 +1,39 @@ +/* + * 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.RedisDataType; +import org.apache.geode.redis.internal.RegionProvider; + + +public class ExpirationExecutor implements Runnable { + private final ByteArrayWrapper key; + private final RedisDataType type; + private final RegionProvider rC; + + public ExpirationExecutor(ByteArrayWrapper k, RedisDataType type, RegionProvider rC) { + this.key = k; + this.type = type; + this.rC = rC; + } + + @Override + public void run() { + rC.removeKey(key, type, false); + } + + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExpireAtExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExpireAtExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExpireAtExecutor.java new file mode 100644 index 0000000..dabec5e --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExpireAtExecutor.java @@ -0,0 +1,92 @@ +/* + * 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.RegionProvider; + +import java.util.List; + +public class ExpireAtExecutor extends AbstractExecutor implements Extendable { + + private final String ERROR_TIMESTAMP_NOT_USABLE = "The timestamp specified must be numeric"; + + private final int TIMESTAMP_INDEX = 2; + + private final int SET = 1; + + private final int NOT_SET = 0; + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + List<byte[]> commandElems = command.getProcessedCommand(); + + if (commandElems.size() < 3) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), getArgsError())); + return; + } + RegionProvider rC = context.getRegionProvider(); + ByteArrayWrapper wKey = command.getKey(); + + byte[] timestampByteArray = commandElems.get(TIMESTAMP_INDEX); + long timestamp; + try { + timestamp = Coder.bytesToLong(timestampByteArray); + } catch (NumberFormatException e) { + command.setResponse( + Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_TIMESTAMP_NOT_USABLE)); + return; + } + + if (!timeUnitMillis()) + timestamp = timestamp * millisInSecond; + + long currentTimeMillis = System.currentTimeMillis(); + + if (timestamp <= currentTimeMillis) { + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NOT_SET)); + return; + } + + long delayMillis = timestamp - currentTimeMillis; + + boolean expirationSet = false; + + if (rC.hasExpiration(wKey)) + expirationSet = rC.modifyExpiration(wKey, delayMillis); + else + expirationSet = rC.setExpiration(wKey, delayMillis); + + if (expirationSet) + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), SET)); + else + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NOT_SET)); + } + + protected boolean timeUnitMillis() { + return false; + } + + @Override + public String getArgsError() { + return ArityDef.EXPIREAT; + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExpireExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExpireExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExpireExecutor.java new file mode 100644 index 0000000..80866f9 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/ExpireExecutor.java @@ -0,0 +1,92 @@ +/* + * 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.RegionProvider; + +import java.util.List; + +public class ExpireExecutor extends AbstractExecutor implements Extendable { + + private final String ERROR_SECONDS_NOT_USABLE = "The number of seconds specified must be numeric"; + + private final int SECONDS_INDEX = 2; + + private final int SET = 1; + + private final int NOT_SET = 0; + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + List<byte[]> commandElems = command.getProcessedCommand(); + + if (commandElems.size() < 3) { + command.setResponse(Coder.getErrorResponse(context.getByteBufAllocator(), getArgsError())); + return; + } + ByteArrayWrapper wKey = command.getKey(); + RegionProvider rC = context.getRegionProvider(); + byte[] delayByteArray = commandElems.get(SECONDS_INDEX); + long delay; + try { + delay = Coder.bytesToLong(delayByteArray); + } catch (NumberFormatException e) { + command.setResponse( + Coder.getErrorResponse(context.getByteBufAllocator(), ERROR_SECONDS_NOT_USABLE)); + return; + } + + if (delay <= 0) { + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NOT_SET)); + return; + } + + // If time unit given is not in millis convert to millis + if (!timeUnitMillis()) + delay = delay * millisInSecond; + + boolean expirationSet = false; + + if (rC.hasExpiration(wKey)) + expirationSet = rC.modifyExpiration(wKey, delay); + else + expirationSet = rC.setExpiration(wKey, delay); + + + if (expirationSet) + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), SET)); + else + command.setResponse(Coder.getIntegerResponse(context.getByteBufAllocator(), NOT_SET)); + } + + /* + * Overridden by PExpire + */ + protected boolean timeUnitMillis() { + return false; + } + + @Override + public String getArgsError() { + return ArityDef.EXPIRE; + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/FlushAllExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/FlushAllExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/FlushAllExecutor.java new file mode 100644 index 0000000..90148ae --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/FlushAllExecutor.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.cache.EntryDestroyedException; +import org.apache.geode.cache.UnsupportedOperationInTransactionException; +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.RedisDataType; + +import java.util.Map.Entry; + +public class FlushAllExecutor extends AbstractExecutor { + + @Override + public void executeCommand(Command command, ExecutionHandlerContext context) { + if (context.hasTransaction()) + throw new UnsupportedOperationInTransactionException(); + + for (Entry<String, RedisDataType> e : context.getRegionProvider().metaEntrySet()) { + try { + String skey = e.getKey(); + RedisDataType type = e.getValue(); + removeEntry(Coder.stringToByteWrapper(skey), type, context); + } catch (EntryDestroyedException e1) { + continue; + } + + } + + command.setResponse(Coder.getSimpleStringResponse(context.getByteBufAllocator(), "OK")); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/KeysExecutor.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/KeysExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/KeysExecutor.java new file mode 100644 index 0000000..79ff5e2 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/KeysExecutor.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; + +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 org.apache.geode.redis.internal.org.apache.hadoop.fs.GlobPattern; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +public class KeysExecutor 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.KEYS)); + return; + } + + String glob = Coder.bytesToString(commandElems.get(1)); + Set<String> allKeys = context.getRegionProvider().metaKeySet(); + List<String> matchingKeys = new ArrayList<String>(); + + Pattern pattern; + try { + pattern = GlobPattern.compile(glob); + } catch (PatternSyntaxException e) { + command.setResponse( + Coder.getErrorResponse(context.getByteBufAllocator(), RedisConstants.ERROR_ILLEGAL_GLOB)); + return; + } + + for (String key : allKeys) { + if (!(key.equals(GeodeRedisServiceImpl.REDIS_META_DATA_REGION) + || key.equals(GeodeRedisServiceImpl.STRING_REGION) + || key.equals(GeodeRedisServiceImpl.HLL_REGION)) && pattern.matcher(key).matches()) + matchingKeys.add(key); + } + + if (matchingKeys.isEmpty()) + command.setResponse(Coder.getEmptyArrayResponse(context.getByteBufAllocator())); + else + command.setResponse( + Coder.getBulkStringArrayResponse(context.getByteBufAllocator(), matchingKeys)); + + + } +}
