diff --git a/redisson/src/main/java/org/redisson/RedissonAtomicDouble.java b/redisson/src/main/java/org/redisson/RedissonAtomicDouble.java index 61ceba620..e23d67c23 100644 --- a/redisson/src/main/java/org/redisson/RedissonAtomicDouble.java +++ b/redisson/src/main/java/org/redisson/RedissonAtomicDouble.java @@ -60,7 +60,8 @@ public class RedissonAtomicDouble extends RedissonExpirable implements RAtomicDo @Override public RFuture<Boolean> compareAndSetAsync(double expect, double update) { return commandExecutor.evalWriteAsync(getName(), StringCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, - "if tonumber(redis.call('get', KEYS[1])) == tonumber(ARGV[1]) then " + "local value = redis.call('get', KEYS[1]);" + + "if (value == false and tonumber(ARGV[1]) == 0) or (tonumber(value) == tonumber(ARGV[1])) then " + "redis.call('set', KEYS[1], ARGV[2]); " + "return 1 " + "else " @@ -80,12 +81,26 @@ public class RedissonAtomicDouble extends RedissonExpirable implements RAtomicDo @Override public double get() { - return addAndGet(0); + return get(getAsync()); } + @Override + public double getAndDelete() { + return get(getAndDeleteAsync()); + } + + @Override + public RFuture<Double> getAndDeleteAsync() { + return commandExecutor.evalWriteAsync(getName(), StringCodec.INSTANCE, RedisCommands.EVAL_DOUBLE, + "local currValue = redis.call('get', KEYS[1]); " + + "redis.call('del', KEYS[1]); " + + "return currValue; ", + Collections.<Object>singletonList(getName())); + } + @Override public RFuture<Double> getAsync() { - return addAndGetAsync(0); + return commandExecutor.writeAsync(getName(), StringCodec.INSTANCE, RedisCommands.GET_DOUBLE, getName()); } @Override diff --git a/redisson/src/main/java/org/redisson/RedissonAtomicLong.java b/redisson/src/main/java/org/redisson/RedissonAtomicLong.java index 69b8bb647..22d65d1f2 100644 --- a/redisson/src/main/java/org/redisson/RedissonAtomicLong.java +++ b/redisson/src/main/java/org/redisson/RedissonAtomicLong.java @@ -66,6 +66,20 @@ public class RedissonAtomicLong extends RedissonExpirable implements RAtomicLong + "end", Collections.<Object>singletonList(getName()), expect, update); } + + @Override + public long getAndDelete() { + return get(getAndDeleteAsync()); + } + + @Override + public RFuture<Long> getAndDeleteAsync() { + return commandExecutor.evalWriteAsync(getName(), StringCodec.INSTANCE, RedisCommands.EVAL_LONG_SAFE, + "local currValue = redis.call('get', KEYS[1]); " + + "redis.call('del', KEYS[1]); " + + "return currValue; ", + Collections.<Object>singletonList(getName())); + } @Override public long decrementAndGet() { @@ -79,12 +93,12 @@ public class RedissonAtomicLong extends RedissonExpirable implements RAtomicLong @Override public long get() { - return addAndGet(0); + return get(getAsync()); } @Override public RFuture<Long> getAsync() { - return addAndGetAsync(0); + return commandExecutor.writeAsync(getName(), StringCodec.INSTANCE, RedisCommands.GET_LONG, getName()); } @Override diff --git a/redisson/src/main/java/org/redisson/api/RAtomicDouble.java b/redisson/src/main/java/org/redisson/api/RAtomicDouble.java index e52b395dc..7ec2abcb5 100644 --- a/redisson/src/main/java/org/redisson/api/RAtomicDouble.java +++ b/redisson/src/main/java/org/redisson/api/RAtomicDouble.java @@ -62,6 +62,13 @@ public interface RAtomicDouble extends RExpirable, RAtomicDoubleAsync { * @return the current value */ double get(); + + /** + * Gets and deletes object + * + * @return the current value + */ + double getAndDelete(); /** * Atomically adds the given value to the current value. diff --git a/redisson/src/main/java/org/redisson/api/RAtomicDoubleAsync.java b/redisson/src/main/java/org/redisson/api/RAtomicDoubleAsync.java index d83dbf883..9889655ab 100644 --- a/redisson/src/main/java/org/redisson/api/RAtomicDoubleAsync.java +++ b/redisson/src/main/java/org/redisson/api/RAtomicDoubleAsync.java @@ -15,6 +15,11 @@ */ package org.redisson.api; +/** + * + * @author Nikita Koksharov + * + */ public interface RAtomicDoubleAsync extends RExpirableAsync { RFuture<Boolean> compareAndSetAsync(double expect, double update); @@ -25,6 +30,13 @@ public interface RAtomicDoubleAsync extends RExpirableAsync { RFuture<Double> getAsync(); + /** + * Gets and deletes object + * + * @return the current value + */ + RFuture<Double> getAndDeleteAsync(); + RFuture<Double> getAndAddAsync(double delta); RFuture<Double> getAndSetAsync(double newValue); diff --git a/redisson/src/main/java/org/redisson/api/RAtomicLong.java b/redisson/src/main/java/org/redisson/api/RAtomicLong.java index 714f56fcb..c2d8da378 100644 --- a/redisson/src/main/java/org/redisson/api/RAtomicLong.java +++ b/redisson/src/main/java/org/redisson/api/RAtomicLong.java @@ -63,6 +63,13 @@ public interface RAtomicLong extends RExpirable, RAtomicLongAsync { */ long get(); + /** + * Gets and deletes object + * + * @return the current value + */ + long getAndDelete(); + /** * Atomically adds the given value to the current value. * diff --git a/redisson/src/main/java/org/redisson/api/RAtomicLongAsync.java b/redisson/src/main/java/org/redisson/api/RAtomicLongAsync.java index 02bffedbd..c4cf387d1 100644 --- a/redisson/src/main/java/org/redisson/api/RAtomicLongAsync.java +++ b/redisson/src/main/java/org/redisson/api/RAtomicLongAsync.java @@ -15,6 +15,11 @@ */ package org.redisson.api; +/** + * + * @author Nikita Koksharov + * + */ public interface RAtomicLongAsync extends RExpirableAsync { RFuture<Boolean> compareAndSetAsync(long expect, long update); @@ -24,6 +29,13 @@ public interface RAtomicLongAsync extends RExpirableAsync { RFuture<Long> decrementAndGetAsync(); RFuture<Long> getAsync(); + + /** + * Gets and deletes object + * + * @return the current value + */ + RFuture<Long> getAndDeleteAsync(); RFuture<Long> getAndAddAsync(long delta); diff --git a/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java b/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java index 48299979a..c3eac37eb 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java +++ b/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java @@ -32,6 +32,7 @@ import org.redisson.client.protocol.convertor.BooleanNullReplayConvertor; import org.redisson.client.protocol.convertor.BooleanNullSafeReplayConvertor; import org.redisson.client.protocol.convertor.BooleanNumberReplayConvertor; import org.redisson.client.protocol.convertor.BooleanReplayConvertor; +import org.redisson.client.protocol.convertor.DoubleNullSafeReplayConvertor; import org.redisson.client.protocol.convertor.DoubleReplayConvertor; import org.redisson.client.protocol.convertor.IntegerReplayConvertor; import org.redisson.client.protocol.convertor.KeyValueConvertor; @@ -133,7 +134,7 @@ public interface RedisCommands { RedisCommand<List<ScoredEntry<Object>>> ZRANGE_ENTRY = new RedisCommand<List<ScoredEntry<Object>>>("ZRANGE", new ScoredSortedSetReplayDecoder<Object>()); RedisCommand<List<ScoredEntry<Object>>> ZRANGEBYSCORE_ENTRY = new RedisCommand<List<ScoredEntry<Object>>>("ZRANGEBYSCORE", new ScoredSortedSetReplayDecoder<Object>()); RedisCommand<ListScanResult<Object>> ZSCAN = new RedisCommand<ListScanResult<Object>>("ZSCAN", new ListMultiDecoder(new LongMultiDecoder(), new ScoredSortedSetScanDecoder<Object>(), new ScoredSortedSetScanReplayDecoder())); - RedisStrictCommand<Double> ZINCRBY = new RedisStrictCommand<Double>("ZINCRBY", new DoubleReplayConvertor()); + RedisStrictCommand<Double> ZINCRBY = new RedisStrictCommand<Double>("ZINCRBY", new DoubleNullSafeReplayConvertor()); RedisCommand<ListScanResult<String>> SCAN = new RedisCommand<ListScanResult<String>>("SCAN", new ListMultiDecoder(new LongMultiDecoder(), new ObjectListReplayDecoder<String>(), new ListScanResultReplayDecoder())); RedisStrictCommand<String> RANDOM_KEY = new RedisStrictCommand<String>("RANDOMKEY", new StringDataDecoder()); @@ -221,7 +222,9 @@ public interface RedisCommands { RedisStrictCommand<String> EVAL_STRING = new RedisStrictCommand<String>("EVAL", new StringReplayDecoder()); RedisStrictCommand<String> EVAL_STRING_DATA = new RedisStrictCommand<String>("EVAL", new StringDataDecoder()); RedisStrictCommand<Integer> EVAL_INTEGER = new RedisStrictCommand<Integer>("EVAL", new IntegerReplayConvertor()); + RedisStrictCommand<Double> EVAL_DOUBLE = new RedisStrictCommand<Double>("EVAL", new DoubleNullSafeReplayConvertor()); RedisStrictCommand<Long> EVAL_LONG = new RedisStrictCommand<Long>("EVAL"); + RedisStrictCommand<Long> EVAL_LONG_SAFE = new RedisStrictCommand<Long>("EVAL", new LongReplayConvertor()); RedisStrictCommand<Void> EVAL_VOID = new RedisStrictCommand<Void>("EVAL", new VoidReplayConvertor()); RedisCommand<List<Object>> EVAL_LIST = new RedisCommand<List<Object>>("EVAL", new ObjectListReplayDecoder<Object>()); RedisCommand<Set<Object>> EVAL_SET = new RedisCommand<Set<Object>>("EVAL", new ObjectSetReplayDecoder<Object>()); @@ -235,7 +238,7 @@ public interface RedisCommands { RedisStrictCommand<Long> INCR = new RedisStrictCommand<Long>("INCR"); RedisStrictCommand<Long> INCRBY = new RedisStrictCommand<Long>("INCRBY"); - RedisStrictCommand<Double> INCRBYFLOAT = new RedisStrictCommand<Double>("INCRBYFLOAT", new DoubleReplayConvertor()); + RedisStrictCommand<Double> INCRBYFLOAT = new RedisStrictCommand<Double>("INCRBYFLOAT", new DoubleNullSafeReplayConvertor()); RedisStrictCommand<Long> DECR = new RedisStrictCommand<Long>("DECR"); RedisStrictCommand<Void> AUTH = new RedisStrictCommand<Void>("AUTH", new VoidReplayConvertor()); @@ -281,6 +284,7 @@ public interface RedisCommands { RedisCommand<Object> GET = new RedisCommand<Object>("GET"); RedisStrictCommand<Long> GET_LONG = new RedisStrictCommand<Long>("GET", new LongReplayConvertor()); RedisStrictCommand<Integer> GET_INTEGER = new RedisStrictCommand<Integer>("GET", new IntegerReplayConvertor()); + RedisStrictCommand<Double> GET_DOUBLE = new RedisStrictCommand<Double>("GET", new DoubleNullSafeReplayConvertor()); RedisCommand<Object> GETSET = new RedisCommand<Object>("GETSET"); RedisCommand<Object> GETRANGE = new RedisCommand<Object>("GETRANGE"); RedisCommand<Object> APPEND = new RedisCommand<Object>("APPEND"); diff --git a/redisson/src/main/java/org/redisson/client/protocol/convertor/DoubleNullSafeReplayConvertor.java b/redisson/src/main/java/org/redisson/client/protocol/convertor/DoubleNullSafeReplayConvertor.java new file mode 100644 index 000000000..c1c0b1c5c --- /dev/null +++ b/redisson/src/main/java/org/redisson/client/protocol/convertor/DoubleNullSafeReplayConvertor.java @@ -0,0 +1,19 @@ +package org.redisson.client.protocol.convertor; + +/** + * + * @author Nikita Koksharov + * + */ +public class DoubleNullSafeReplayConvertor extends DoubleReplayConvertor { + + @Override + public Double convert(Object obj) { + Double r = super.convert(obj); + if (r == null) { + return 0.0; + } + return r; + } + +} diff --git a/redisson/src/test/java/org/redisson/RedissonAtomicDoubleTest.java b/redisson/src/test/java/org/redisson/RedissonAtomicDoubleTest.java index 3a4850ca0..0d69e2186 100644 --- a/redisson/src/test/java/org/redisson/RedissonAtomicDoubleTest.java +++ b/redisson/src/test/java/org/redisson/RedissonAtomicDoubleTest.java @@ -9,6 +9,23 @@ import org.redisson.api.RAtomicDouble; public class RedissonAtomicDoubleTest extends BaseTest { + @Test + public void testGetZero() { + RAtomicDouble ad2 = redisson.getAtomicDouble("test"); + assertThat(ad2.get()).isZero(); + } + + @Test + public void testGetAndDelete() { + RAtomicDouble al = redisson.getAtomicDouble("test"); + al.set(10.34); + assertThat(al.getAndDelete()).isEqualTo(10.34); + assertThat(al.isExists()).isFalse(); + + RAtomicDouble ad2 = redisson.getAtomicDouble("test2"); + assertThat(ad2.getAndDelete()).isZero(); + } + @Test public void testCompareAndSet() { RAtomicDouble al = redisson.getAtomicDouble("test"); diff --git a/redisson/src/test/java/org/redisson/RedissonAtomicLongTest.java b/redisson/src/test/java/org/redisson/RedissonAtomicLongTest.java index a35ff024f..170368e51 100644 --- a/redisson/src/test/java/org/redisson/RedissonAtomicLongTest.java +++ b/redisson/src/test/java/org/redisson/RedissonAtomicLongTest.java @@ -1,11 +1,30 @@ package org.redisson; +import static org.assertj.core.api.Assertions.assertThat; + import org.junit.Assert; import org.junit.Test; import org.redisson.api.RAtomicLong; public class RedissonAtomicLongTest extends BaseTest { + @Test + public void testGetZero() { + RAtomicLong ad2 = redisson.getAtomicLong("test"); + assertThat(ad2.get()).isZero(); + } + + @Test + public void testGetAndDelete() { + RAtomicLong al = redisson.getAtomicLong("test"); + al.set(10); + assertThat(al.getAndDelete()).isEqualTo(10); + assertThat(al.isExists()).isFalse(); + + RAtomicLong ad2 = redisson.getAtomicLong("test2"); + assertThat(ad2.getAndDelete()).isZero(); + } + @Test public void testCompareAndSetZero() { RAtomicLong al = redisson.getAtomicLong("test");