geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kl...@apache.org
Subject [10/21] incubator-geode git commit: GEODE-1566: rename GeodeRedisServer and repackage redis code into org.apache.geode
Date Fri, 08 Jul 2016 18:21:18 GMT
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/RedisDataTypeMismatchException.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/RedisDataTypeMismatchException.java b/geode-core/src/main/java/org/apache/geode/redis/internal/RedisDataTypeMismatchException.java
new file mode 100755
index 0000000..e4dbbf7
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/RedisDataTypeMismatchException.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;
+
+/**
+ * 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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/RegionCreationException.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/RegionCreationException.java b/geode-core/src/main/java/org/apache/geode/redis/internal/RegionCreationException.java
new file mode 100644
index 0000000..0a4b2a2
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/RegionCreationException.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;
+
+/**
+ * This exception is used when an error happens while creating a {@link com.gemstone.gemfire.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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/RegionProvider.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/RegionProvider.java b/geode-core/src/main/java/org/apache/geode/redis/internal/RegionProvider.java
new file mode 100644
index 0000000..bcab323
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/RegionProvider.java
@@ -0,0 +1,552 @@
+/*
+ * 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 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;
+
+import com.gemstone.gemfire.cache.Cache;
+import com.gemstone.gemfire.cache.CacheTransactionManager;
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.cache.RegionShortcut;
+import com.gemstone.gemfire.cache.TransactionId;
+import com.gemstone.gemfire.cache.query.IndexExistsException;
+import com.gemstone.gemfire.cache.query.IndexInvalidException;
+import com.gemstone.gemfire.cache.query.IndexNameConflictException;
+import com.gemstone.gemfire.cache.query.Query;
+import com.gemstone.gemfire.cache.query.QueryInvalidException;
+import com.gemstone.gemfire.cache.query.QueryService;
+import com.gemstone.gemfire.cache.query.RegionNotFoundException;
+import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
+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 com.gemstone.gemfire.internal.hll.HyperLogLogPlus;
+import com.gemstone.gemfire.management.cli.Result;
+import com.gemstone.gemfire.management.cli.Result.Status;
+import com.gemstone.gemfire.management.internal.cli.commands.CreateAlterDestroyRegionCommands;
+import org.apache.geode.redis.GeodeRedisServer;
+
+/**
+ * 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 GeodeRedisServer} 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<Map.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);
+      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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/AbstractExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/AbstractExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/AbstractExecutor.java
new file mode 100755
index 0000000..1575c1b
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/AbstractExecutor.java
@@ -0,0 +1,138 @@
+/*
+ * 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 com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.cache.query.Query;
+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;
+import org.apache.geode.redis.GeodeRedisServer;
+
+/**
+ * The AbstractExecutor is the base of all {@link Executor} types for the 
+ * {@link GeodeRedisServer}.
+ * 
+ *
+ */
+public abstract class AbstractExecutor implements Executor {
+
+  /**
+   * Number of Regions used by GeodeRedisServer 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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/AbstractScanExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/AbstractScanExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/AbstractScanExecutor.java
new file mode 100755
index 0000000..d059328
--- /dev/null
+++ b/geode-core/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 java.util.Collection;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.apache.geode.redis.internal.org.apache.hadoop.fs.GlobPattern;
+
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/AuthExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/AuthExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/AuthExecutor.java
new file mode 100644
index 0000000..6349ac4
--- /dev/null
+++ b/geode-core/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 java.util.Arrays;
+import java.util.List;
+
+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;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/DBSizeExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/DBSizeExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/DBSizeExecutor.java
new file mode 100755
index 0000000..085e2bf
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/DBSizeExecutor.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.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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/DelExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/DelExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/DelExecutor.java
new file mode 100755
index 0000000..de3cce6
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/DelExecutor.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;
+
+import java.util.List;
+
+import com.gemstone.gemfire.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;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/EchoExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/EchoExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/EchoExecutor.java
new file mode 100755
index 0000000..ecba833
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/EchoExecutor.java
@@ -0,0 +1,40 @@
+/*
+ * 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 java.util.List;
+
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+public class 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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ExistsExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ExistsExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ExistsExecutor.java
new file mode 100755
index 0000000..c04fc84
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ExistsExecutor.java
@@ -0,0 +1,49 @@
+/*
+ * 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 java.util.List;
+
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+public class 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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ExpirationExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ExpirationExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ExpirationExecutor.java
new file mode 100755
index 0000000..ef14588
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ExpirationExecutor.java
@@ -0,0 +1,41 @@
+/*
+ * 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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ExpireAtExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ExpireAtExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ExpireAtExecutor.java
new file mode 100755
index 0000000..fd9d723
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ExpireAtExecutor.java
@@ -0,0 +1,93 @@
+/*
+ * 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 java.util.List;
+
+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;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ExpireExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ExpireExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ExpireExecutor.java
new file mode 100755
index 0000000..efed934
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ExpireExecutor.java
@@ -0,0 +1,93 @@
+/*
+ * 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 java.util.List;
+
+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;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/FlushAllExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/FlushAllExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/FlushAllExecutor.java
new file mode 100755
index 0000000..a01425e
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/FlushAllExecutor.java
@@ -0,0 +1,49 @@
+/*
+ * 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 java.util.Map.Entry;
+
+import com.gemstone.gemfire.cache.EntryDestroyedException;
+import com.gemstone.gemfire.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;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/KeysExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/KeysExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/KeysExecutor.java
new file mode 100755
index 0000000..578d49a
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/KeysExecutor.java
@@ -0,0 +1,70 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+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 org.apache.geode.redis.GeodeRedisServer;
+
+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(GeodeRedisServer.REDIS_META_DATA_REGION) ||
+              key.equals(GeodeRedisServer.STRING_REGION) ||
+              key.equals(GeodeRedisServer.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));
+
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ListQuery.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ListQuery.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ListQuery.java
new file mode 100644
index 0000000..ae8d3e2
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ListQuery.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;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PExpireAtExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PExpireAtExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PExpireAtExecutor.java
new file mode 100755
index 0000000..7f40ee4
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PExpireAtExecutor.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geode.redis.internal.executor;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PExpireExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PExpireExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PExpireExecutor.java
new file mode 100755
index 0000000..507ba98
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PExpireExecutor.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geode.redis.internal.executor;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PTTLExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PTTLExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PTTLExecutor.java
new file mode 100755
index 0000000..5202757
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PTTLExecutor.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geode.redis.internal.executor;
+
+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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PersistExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PersistExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PersistExecutor.java
new file mode 100755
index 0000000..9f0853e
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PersistExecutor.java
@@ -0,0 +1,52 @@
+/*
+ * 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 java.util.List;
+
+import org.apache.geode.redis.internal.ByteArrayWrapper;
+import org.apache.geode.redis.internal.Coder;
+import org.apache.geode.redis.internal.Command;
+import org.apache.geode.redis.internal.ExecutionHandlerContext;
+import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+
+public class 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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PingExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PingExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PingExecutor.java
new file mode 100755
index 0000000..7ebf90c
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/PingExecutor.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.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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/QuitExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/QuitExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/QuitExecutor.java
new file mode 100755
index 0000000..260091d
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/QuitExecutor.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.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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ScanExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ScanExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ScanExecutor.java
new file mode 100755
index 0000000..f70bd3e
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ScanExecutor.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geode.redis.internal.executor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+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.GeodeRedisServer;
+
+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(GeodeRedisServer.REDIS_META_DATA_REGION) || key.equals(GeodeRedisServer.STRING_REGION) || key.equals(
+        GeodeRedisServer.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/incubator-geode/blob/dfd481e0/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ShutDownExecutor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ShutDownExecutor.java b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ShutDownExecutor.java
new file mode 100755
index 0000000..ad89d81
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/executor/ShutDownExecutor.java
@@ -0,0 +1,28 @@
+/*
+ * 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) {
+  }
+
+}


Mime
View raw message