Repository: ignite
Updated Branches:
  refs/heads/master 31448be0d -> a029997b3


IGNITE-4226 Redis SET command to handle expirations. - Fixes #1510.

Signed-off-by: Andrey Novikov <[email protected]>


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/a029997b
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/a029997b
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/a029997b

Branch: refs/heads/master
Commit: a029997b3c62333d5d2279b0e3c877c663d40609
Parents: 31448be
Author: shtykh_roman <[email protected]>
Authored: Wed Feb 22 10:42:07 2017 +0700
Committer: Andrey Novikov <[email protected]>
Committed: Wed Feb 22 10:49:22 2017 +0700

----------------------------------------------------------------------
 .../tcp/redis/RedisProtocolSelfTest.java        | 13 +++++-
 .../handlers/cache/GridCacheCommandHandler.java | 27 +++++++++---
 .../redis/GridRedisRestCommandHandler.java      | 36 ++++++++++++++++
 .../string/GridRedisSetCommandHandler.java      | 43 +++++++++-----------
 4 files changed, 88 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/a029997b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/RedisProtocolSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/RedisProtocolSelfTest.java
 
b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/RedisProtocolSelfTest.java
index a0066aa..59cbe76 100644
--- 
a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/RedisProtocolSelfTest.java
+++ 
b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/RedisProtocolSelfTest.java
@@ -221,6 +221,9 @@ public class RedisProtocolSelfTest extends 
GridCommonAbstractTest {
      * @throws Exception If failed.
      */
     public void testSet() throws Exception {
+        long EXPIRE_MS = 5000L;
+        int EXPIRE_SEC = 5;
+
         try (Jedis jedis = pool.getResource()) {
             jedis.set("setKey1", "1");
             jedis.set("setKey2".getBytes(), "b0".getBytes());
@@ -230,16 +233,22 @@ public class RedisProtocolSelfTest extends 
GridCommonAbstractTest {
 
             // test options.
             jedis.set("setKey1", "2", "nx");
-            jedis.set("setKey3", "3", "nx");
+            jedis.set("setKey3", "3", "nx", "px", EXPIRE_MS);
 
             Assert.assertEquals("1", jcache().get("setKey1"));
             Assert.assertEquals("3", jcache().get("setKey3"));
 
-            jedis.set("setKey1", "2", "xx");
+            jedis.set("setKey1", "2", "xx", "ex", EXPIRE_SEC);
             jedis.set("setKey4", "4", "xx");
 
             Assert.assertEquals("2", jcache().get("setKey1"));
             Assert.assertNull(jcache().get("setKey4"));
+
+            // wait for expiration.
+            Thread.sleep(EXPIRE_MS);
+
+            Assert.assertNull(jcache().get("setKey1"));
+            Assert.assertNull(jcache().get("setKey3"));
         }
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/a029997b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java
index 31dac12..79b395d 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java
@@ -35,7 +35,6 @@ import javax.cache.processor.EntryProcessor;
 import javax.cache.processor.EntryProcessorException;
 import javax.cache.processor.EntryProcessorResult;
 import javax.cache.processor.MutableEntry;
-
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteException;
@@ -452,7 +451,7 @@ public class GridCacheCommandHandler extends 
GridRestCommandHandlerAdapter {
 
                 case CACHE_PUT_IF_ABSENT: {
                     fut = executeCommand(req.destinationId(), req.clientId(), 
cacheName, skipStore, key,
-                        new PutIfAbsentCommand(key, getValue(req0)));
+                        new PutIfAbsentCommand(key, ttl, getValue(req0)));
 
                     break;
                 }
@@ -1148,20 +1147,38 @@ public class GridCacheCommandHandler extends 
GridRestCommandHandlerAdapter {
     }
 
     /** */
-    private static class PutIfAbsentCommand extends GetAndPutCommand {
+    private static class PutIfAbsentCommand extends CacheProjectionCommand {
         /** */
         private static final long serialVersionUID = 0L;
 
+        /** */
+        private final Object key;
+
+        /** */
+        private final Long ttl;
+
+        /** */
+        private final Object val;
+
         /**
          * @param key Key.
+         * @param ttl TTL.
          * @param val Value.
          */
-        PutIfAbsentCommand(Object key, Object val) {
-            super(key, val);
+        PutIfAbsentCommand(Object key, Long ttl, Object val) {
+            this.val = val;
+            this.ttl = ttl;
+            this.key = key;
         }
 
         /** {@inheritDoc} */
         @Override public IgniteInternalFuture<?> 
applyx(IgniteInternalCache<Object, Object> c, GridKernalContext ctx) {
+            if (ttl != null && ttl > 0) {
+                Duration duration = new Duration(MILLISECONDS, ttl);
+
+                c = c.withExpiryPolicy(new ModifiedExpiryPolicy(duration));
+            }
+
             return c.putIfAbsentAsync(key, val);
         }
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/a029997b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/GridRedisRestCommandHandler.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/GridRedisRestCommandHandler.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/GridRedisRestCommandHandler.java
index d632252..4446bc1 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/GridRedisRestCommandHandler.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/GridRedisRestCommandHandler.java
@@ -18,18 +18,21 @@
 package org.apache.ignite.internal.processors.rest.handlers.redis;
 
 import java.nio.ByteBuffer;
+import java.util.Iterator;
 import java.util.List;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.processors.rest.GridRestProtocolHandler;
 import org.apache.ignite.internal.processors.rest.GridRestResponse;
+import 
org.apache.ignite.internal.processors.rest.handlers.redis.exception.GridRedisGenericException;
 import 
org.apache.ignite.internal.processors.rest.handlers.redis.exception.GridRedisTypeException;
 import 
org.apache.ignite.internal.processors.rest.protocols.tcp.redis.GridRedisMessage;
 import 
org.apache.ignite.internal.processors.rest.protocols.tcp.redis.GridRedisProtocolParser;
 import org.apache.ignite.internal.processors.rest.request.GridRestRequest;
 import org.apache.ignite.internal.util.future.GridFinishedFuture;
 import org.apache.ignite.internal.util.typedef.CX1;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Redis command handler done via REST.
@@ -83,6 +86,39 @@ public abstract class GridRedisRestCommandHandler implements 
GridRedisCommandHan
     }
 
     /**
+     * Retrieves long value following the parameter name from parameters list.
+     *
+     * @param name Parameter name.
+     * @param params Parameters list.
+     * @return Long value from parameters list or null if not exists.
+     * @throws GridRedisGenericException If parsing failed.
+     */
+    @Nullable protected Long longValue(String name, List<String> params) 
throws GridRedisGenericException {
+        assert name != null;
+
+        Iterator<String> it = params.iterator();
+
+        while (it.hasNext()) {
+            if (name.equalsIgnoreCase(it.next())) {
+                if (it.hasNext()) {
+                    String val = it.next();
+
+                    try {
+                        return Long.valueOf(val);
+                    }
+                    catch (NumberFormatException ignore) {
+                        throw new GridRedisGenericException("Failed to parse 
parameter of Long type [" + name + "=" + val + "]");
+                    }
+                }
+                else
+                    throw new GridRedisGenericException("Syntax error. Missing 
value for parameter: " + name);
+            }
+        }
+
+        return null;
+    }
+
+    /**
      * Converts {@link GridRedisMessage} to {@link GridRestRequest}.
      *
      * @param msg {@link GridRedisMessage}

http://git-wip-us.apache.org/repos/asf/ignite/blob/a029997b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/string/GridRedisSetCommandHandler.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/string/GridRedisSetCommandHandler.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/string/GridRedisSetCommandHandler.java
index 7caadb8..4108721 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/string/GridRedisSetCommandHandler.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/string/GridRedisSetCommandHandler.java
@@ -81,6 +81,9 @@ public class GridRedisSetCommandHandler extends 
GridRedisRestCommandHandler {
     @Override public GridRestRequest asRestRequest(GridRedisMessage msg) 
throws IgniteCheckedException {
         assert msg != null;
 
+        if (msg.messageSize() < 3)
+            throw new GridRedisGenericException("Wrong number of arguments");
+
         // check if an atomic long with the key exists (related to incr/decr).
         IgniteAtomicLong l = ctx.grid().atomicLong(msg.key(), 0, false);
 
@@ -89,7 +92,7 @@ public class GridRedisSetCommandHandler extends 
GridRedisRestCommandHandler {
                 l.close();
             }
             catch (IgniteException ignored) {
-                U.warn(log, "Failed to remove atomic long for key [" + 
msg.key() + "]");
+                U.warn(log, "Failed to remove atomic long for key: " + 
msg.key());
             }
         }
 
@@ -100,9 +103,6 @@ public class GridRedisSetCommandHandler extends 
GridRedisRestCommandHandler {
 
         restReq.command(CACHE_PUT);
 
-        if (msg.messageSize() < 3)
-            throw new GridRedisGenericException("Wrong number of arguments");
-
         restReq.value(msg.aux(VAL_POS));
 
         if (msg.messageSize() >= 4) {
@@ -111,37 +111,32 @@ public class GridRedisSetCommandHandler extends 
GridRedisRestCommandHandler {
             // get rid of SET value.
             params.remove(0);
 
-            if (isNx(params))
+            if (U.containsStringCollection(params, "nx", true))
                 restReq.command(CACHE_PUT_IF_ABSENT);
-            else if (isXx(params))
+            else if (U.containsStringCollection(params, "xx", true))
                 restReq.command(CACHE_REPLACE);
 
-            // TODO: IGNITE-4226: Need properly handle expiration parameter.
+            setExpire(restReq, params);
         }
 
         return restReq;
     }
 
     /**
+     * Attempts to set expiration when EX or PX parameters are specified.
+     *
+     * @param restReq {@link GridRestCacheRequest}.
      * @param params Command parameters.
-     * @return True if NX option is available, otherwise false.
-     */
-    private boolean isNx(List<String> params) {
-        if (params.size() >= 3)
-            return "nx".equalsIgnoreCase(params.get(0)) || 
"nx".equalsIgnoreCase(params.get(2));
-
-        return "nx".equalsIgnoreCase(params.get(0));
-    }
-
-    /**
-     * @param params Command parameters.
-     * @return True if XX option is available, otherwise false.
+     * @throws GridRedisGenericException When parameters are not valid.
      */
-    private boolean isXx(List<String> params) {
-        if (params.size() >= 3)
-            return "xx".equalsIgnoreCase(params.get(0)) || 
"xx".equalsIgnoreCase(params.get(2));
-
-        return "xx".equalsIgnoreCase(params.get(0));
+    private void setExpire(GridRestCacheRequest restReq, List<String> params) 
throws GridRedisGenericException {
+        Long px = longValue("px", params);
+        Long ex = longValue("ex", params);
+
+        if (px != null)
+            restReq.ttl(px);
+        else if (ex != null)
+            restReq.ttl(ex * 1000L);
     }
 
     /** {@inheritDoc} */

Reply via email to