Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 81303200BD1 for ; Mon, 28 Nov 2016 08:57:10 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id 7FD23160B0D; Mon, 28 Nov 2016 07:57:10 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 5193D160B06 for ; Mon, 28 Nov 2016 08:57:09 +0100 (CET) Received: (qmail 86898 invoked by uid 500); 28 Nov 2016 07:57:08 -0000 Mailing-List: contact commits-help@ignite.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ignite.apache.org Delivered-To: mailing list commits@ignite.apache.org Received: (qmail 86889 invoked by uid 99); 28 Nov 2016 07:57:08 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 28 Nov 2016 07:57:08 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 6A484EABE2; Mon, 28 Nov 2016 07:57:08 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: shroman@apache.org To: commits@ignite.apache.org Message-Id: <23f980d322074d22846c7964c113fa7f@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: ignite git commit: IGNITE-4244: INCR/DECR to operate on AtomicLong. Date: Mon, 28 Nov 2016 07:57:08 +0000 (UTC) archived-at: Mon, 28 Nov 2016 07:57:10 -0000 Repository: ignite Updated Branches: refs/heads/ignite-1.8 2ca709f8e -> d1cc29258 IGNITE-4244: INCR/DECR to operate on AtomicLong. Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/d1cc2925 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/d1cc2925 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/d1cc2925 Branch: refs/heads/ignite-1.8 Commit: d1cc292583b9358ffb7efab5f15ab84bcfb67e9e Parents: 2ca709f Author: shtykh_roman Authored: Mon Nov 28 16:55:47 2016 +0900 Committer: shtykh_roman Committed: Mon Nov 28 16:55:47 2016 +0900 ---------------------------------------------------------------------- .../tcp/redis/RedisProtocolSelfTest.java | 101 ++++++++++++++++--- .../string/GridRedisGetCommandHandler.java | 27 ++++- .../string/GridRedisIncrDecrCommandHandler.java | 63 ++++++++++-- .../string/GridRedisSetCommandHandler.java | 24 ++++- .../tcp/redis/GridRedisNioListener.java | 4 +- 5 files changed, 193 insertions(+), 26 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/d1cc2925/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 c059205..a0066aa 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 @@ -17,7 +17,6 @@ package org.apache.ignite.internal.processors.rest.protocols.tcp.redis; -import java.math.BigInteger; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -264,15 +263,20 @@ public class RedisProtocolSelfTest extends GridCommonAbstractTest { Assert.assertEquals(1, (long)jedis.incr("newKeyIncr")); Assert.assertEquals(-1, (long)jedis.decr("newKeyDecr")); - jcache().put("incrKey1", 1L); + Assert.assertEquals("1", jedis.get("newKeyIncr")); + Assert.assertEquals("-1", jedis.get("newKeyDecr")); - Assert.assertEquals(2L, (long)jedis.incr("incrKey1")); + Assert.assertEquals(1, (long)jedis.incr("incrKey1")); - jcache().put("decrKey1", 1L); + jedis.set("incrKey1", "10"); - Assert.assertEquals(0L, (long)jedis.decr("decrKey1")); + Assert.assertEquals(11L, (long)jedis.incr("incrKey1")); - jcache().put("nonInt", "abc"); + jedis.set("decrKey1", "10"); + + Assert.assertEquals(9L, (long)jedis.decr("decrKey1")); + + jedis.set("nonInt", "abc"); try { jedis.incr("nonInt"); @@ -282,6 +286,7 @@ public class RedisProtocolSelfTest extends GridCommonAbstractTest { catch (JedisDataException e) { assertTrue(e.getMessage().startsWith("ERR")); } + try { jedis.decr("nonInt"); @@ -291,9 +296,39 @@ public class RedisProtocolSelfTest extends GridCommonAbstractTest { assertTrue(e.getMessage().startsWith("ERR")); } - jcache().put("outOfRange", new BigInteger("234293482390480948029348230948")); + jedis.set("outOfRangeIncr1", "9223372036854775808"); try { - jedis.incr("outOfRange"); + jedis.incr("outOfRangeIncr1"); + + assert false : "Exception has to be thrown!"; + } + catch (JedisDataException e) { + assertTrue(e.getMessage().startsWith("ERR")); + } + + jedis.set("outOfRangeDecr1", "-9223372036854775809"); + try { + jedis.decr("outOfRangeDecr1"); + + assert false : "Exception has to be thrown!"; + } + catch (JedisDataException e) { + assertTrue(e.getMessage().startsWith("ERR")); + } + + jedis.set("outOfRangeInc2", String.valueOf(Long.MAX_VALUE)); + try { + jedis.incr("outOfRangeInc2"); + + assert false : "Exception has to be thrown!"; + } + catch (JedisDataException e) { + assertTrue(e.getMessage().startsWith("ERR")); + } + + jedis.set("outOfRangeDecr2", String.valueOf(Long.MIN_VALUE)); + try { + jedis.decr("outOfRangeDecr2"); assert false : "Exception has to be thrown!"; } @@ -308,16 +343,54 @@ public class RedisProtocolSelfTest extends GridCommonAbstractTest { */ public void testIncrDecrBy() throws Exception { try (Jedis jedis = pool.getResource()) { - Assert.assertEquals(2, (long)jedis.incrBy("newKeyIncr1", 2)); - Assert.assertEquals(-2, (long)jedis.decrBy("newKeyDecr1", 2)); + Assert.assertEquals(2, (long)jedis.incrBy("newKeyIncrBy", 2)); + Assert.assertEquals(-2, (long)jedis.decrBy("newKeyDecrBy", 2)); + + jedis.set("incrDecrKeyBy", "1"); + + Assert.assertEquals(11L, (long)jedis.incrBy("incrDecrKeyBy", 10)); - jcache().put("incrKey2", 1L); + Assert.assertEquals(9L, (long)jedis.decrBy("incrDecrKeyBy", 2)); - Assert.assertEquals(3L, (long)jedis.incrBy("incrKey2", 2)); + jedis.set("outOfRangeIncrBy", "1"); + try { + jedis.incrBy("outOfRangeIncrBy", Long.MAX_VALUE); + + assert false : "Exception has to be thrown!"; + } + catch (JedisDataException e) { + assertTrue(e.getMessage().startsWith("ERR")); + } - jcache().put("decrKey2", 2L); + jedis.set("outOfRangeDecrBy", "-1"); + try { + jedis.decrBy("outOfRangeDecrBy", Long.MIN_VALUE); - Assert.assertEquals(0L, (long)jedis.decrBy("decrKey2", 2)); + assert false : "Exception has to be thrown!"; + } + catch (JedisDataException e) { + assertTrue(e.getMessage().startsWith("ERR")); + } + + jedis.set("outOfRangeIncBy2", String.valueOf(Long.MAX_VALUE)); + try { + jedis.incrBy("outOfRangeIncBy2", Long.MAX_VALUE); + + assert false : "Exception has to be thrown!"; + } + catch (JedisDataException e) { + assertTrue(e.getMessage().startsWith("ERR")); + } + + jedis.set("outOfRangeDecrBy2", String.valueOf(Long.MIN_VALUE)); + try { + jedis.decrBy("outOfRangeDecrBy2", Long.MIN_VALUE); + + assert false : "Exception has to be thrown!"; + } + catch (JedisDataException e) { + assertTrue(e.getMessage().startsWith("ERR")); + } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/d1cc2925/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/string/GridRedisGetCommandHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/string/GridRedisGetCommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/string/GridRedisGetCommandHandler.java index a275522..aac4170 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/string/GridRedisGetCommandHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/string/GridRedisGetCommandHandler.java @@ -20,8 +20,10 @@ package org.apache.ignite.internal.processors.rest.handlers.redis.string; import java.nio.ByteBuffer; import java.util.Collection; import java.util.List; +import org.apache.ignite.IgniteAtomicLong; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteLogger; +import org.apache.ignite.internal.GridKernalContext; 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.GridRedisRestCommandHandler; @@ -44,14 +46,21 @@ public class GridRedisGetCommandHandler extends GridRedisRestCommandHandler { GET ); + /** Grid context. */ + private final GridKernalContext ctx; + /** * Constructor. * * @param log Logger. * @param hnd Handler. + * @param ctx Context. */ - public GridRedisGetCommandHandler(IgniteLogger log, GridRestProtocolHandler hnd) { + public GridRedisGetCommandHandler(final IgniteLogger log, final GridRestProtocolHandler hnd, + GridKernalContext ctx) { super(log, hnd); + + this.ctx = ctx; } /** {@inheritDoc} */ @@ -75,8 +84,20 @@ public class GridRedisGetCommandHandler extends GridRedisRestCommandHandler { /** {@inheritDoc} */ @Override public ByteBuffer makeResponse(final GridRestResponse restRes, List params) { - if (restRes.getResponse() == null) - return GridRedisProtocolParser.nil(); + if (restRes.getResponse() == null) { + // check if an atomic long with the key exists (related to incr/decr). + IgniteAtomicLong l = ctx.grid().atomicLong(params.get(0), 0, false); + + long val; + try { + val = l.get(); + } + catch (Exception ignored) { + return GridRedisProtocolParser.nil(); + } + + return GridRedisProtocolParser.toBulkString(val); + } if (restRes.getResponse() instanceof String) return GridRedisProtocolParser.toBulkString(restRes.getResponse()); http://git-wip-us.apache.org/repos/asf/ignite/blob/d1cc2925/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/string/GridRedisIncrDecrCommandHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/string/GridRedisIncrDecrCommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/string/GridRedisIncrDecrCommandHandler.java index 4052ad5..2036d76 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/string/GridRedisIncrDecrCommandHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/string/GridRedisIncrDecrCommandHandler.java @@ -26,6 +26,7 @@ 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.GridRedisRestCommandHandler; 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.GridRedisCommand; import org.apache.ignite.internal.processors.rest.protocols.tcp.redis.GridRedisMessage; import org.apache.ignite.internal.processors.rest.protocols.tcp.redis.GridRedisProtocolParser; @@ -37,6 +38,7 @@ import org.apache.ignite.internal.util.typedef.internal.U; import static org.apache.ignite.internal.processors.rest.GridRestCommand.ATOMIC_DECREMENT; import static org.apache.ignite.internal.processors.rest.GridRestCommand.ATOMIC_INCREMENT; import static org.apache.ignite.internal.processors.rest.GridRestCommand.CACHE_GET; +import static org.apache.ignite.internal.processors.rest.GridRestCommand.CACHE_REMOVE; import static org.apache.ignite.internal.processors.rest.protocols.tcp.redis.GridRedisCommand.DECR; import static org.apache.ignite.internal.processors.rest.protocols.tcp.redis.GridRedisCommand.DECRBY; import static org.apache.ignite.internal.processors.rest.protocols.tcp.redis.GridRedisCommand.INCR; @@ -89,10 +91,38 @@ public class GridRedisIncrDecrCommandHandler extends GridRedisRestCommandHandler if (getResp.getResponse() == null) restReq.initial(0L); else { - if (getResp.getResponse() instanceof Long && (Long)getResp.getResponse() <= Long.MAX_VALUE) - restReq.initial((Long)getResp.getResponse()); + if (getResp.getResponse() instanceof String) { + Long init; + + try { + init = Long.parseLong((String)getResp.getResponse()); + + restReq.initial(init); + } + catch (Exception e) { + U.error(log, "An initial value must be numeric and in range", e); + + throw new GridRedisGenericException("An initial value must be numeric and in range"); + } + + if ((init == Long.MAX_VALUE && (msg.command() == INCR || msg.command() == INCRBY)) + || (init == Long.MIN_VALUE && (msg.command() == DECR || msg.command() == DECRBY))) + throw new GridRedisGenericException("Increment or decrement would overflow"); + } else - throw new GridRedisGenericException("An initial value must be numeric and in range"); + throw new GridRedisTypeException("Operation against a key holding the wrong kind of value"); + + // remove from cache. + GridRestCacheRequest rmReq = new GridRestCacheRequest(); + + rmReq.clientId(msg.clientId()); + rmReq.key(msg.key()); + rmReq.command(CACHE_REMOVE); + + Object rmResp = hnd.handle(rmReq).getResponse(); + + if (rmResp == null || !(boolean)rmResp) + throw new GridRedisGenericException("Cannot incr/decr on the non-atomiclong key"); } restReq.clientId(msg.clientId()); @@ -101,10 +131,16 @@ public class GridRedisIncrDecrCommandHandler extends GridRedisRestCommandHandler if (msg.messageSize() > 2) { try { - restReq.delta(Long.valueOf(msg.aux(DELTA_POS))); + Long delta = Long.valueOf(msg.aux(DELTA_POS)); + + // check if it can be safely added. + safeAdd(restReq.initial(), delta); + + restReq.delta(delta); } - catch (NumberFormatException e) { - U.error(log, "Wrong increment delta", e); + catch (NumberFormatException | ArithmeticException e) { + U.error(log, "An increment value must be numeric and in range", e); + throw new GridRedisGenericException("An increment value must be numeric and in range"); } } @@ -139,4 +175,19 @@ public class GridRedisIncrDecrCommandHandler extends GridRedisRestCommandHandler else return GridRedisProtocolParser.toTypeError("Value is non-numeric or out of range"); } + + /** + * Safely add long values. + * + * @param left A long value. + * @param right A long value. + * @return An addition result or an exception is thrown when overflow occurs. + */ + private static long safeAdd(long left, long right) { + if (right > 0 ? left > Long.MAX_VALUE - right + : left < Long.MIN_VALUE - right) { + throw new ArithmeticException("Long overflow"); + } + return left + right; + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/d1cc2925/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 956d4cb..2eea0e1 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 @@ -20,8 +20,11 @@ package org.apache.ignite.internal.processors.rest.handlers.redis.string; import java.nio.ByteBuffer; import java.util.Collection; import java.util.List; +import org.apache.ignite.IgniteAtomicLong; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.IgniteException; import org.apache.ignite.IgniteLogger; +import org.apache.ignite.internal.GridKernalContext; 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.GridRedisRestCommandHandler; @@ -52,14 +55,21 @@ public class GridRedisSetCommandHandler extends GridRedisRestCommandHandler { /** Value position in Redis message. */ private static final int VAL_POS = 2; + /** Grid context. */ + private final GridKernalContext ctx; + /** * Constructor. * * @param log Logger. * @param hnd Handler. + * @param ctx Context. */ - public GridRedisSetCommandHandler(IgniteLogger log, GridRestProtocolHandler hnd) { + public GridRedisSetCommandHandler(final IgniteLogger log, final GridRestProtocolHandler hnd, + GridKernalContext ctx) { super(log, hnd); + + this.ctx = ctx; } /** {@inheritDoc} */ @@ -71,6 +81,18 @@ public class GridRedisSetCommandHandler extends GridRedisRestCommandHandler { @Override public GridRestRequest asRestRequest(GridRedisMessage msg) throws IgniteCheckedException { assert msg != null; + // check if an atomic long with the key exists (related to incr/decr). + IgniteAtomicLong l = ctx.grid().atomicLong(msg.key(), 0, false); + + if (l != null) { + try { + l.close(); + } + catch (IgniteException e) { + U.warn(log, "Failed to remove atomic long for key [" + msg.key() + "]"); + } + } + GridRestCacheRequest restReq = new GridRestCacheRequest(); restReq.clientId(msg.clientId()); http://git-wip-us.apache.org/repos/asf/ignite/blob/d1cc2925/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/GridRedisNioListener.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/GridRedisNioListener.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/GridRedisNioListener.java index 45c8061..1042bdb 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/GridRedisNioListener.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/GridRedisNioListener.java @@ -67,8 +67,8 @@ public class GridRedisNioListener extends GridNioServerListenerAdapter