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} */
