diff --git a/redisson/src/main/java/org/redisson/RedissonBucket.java b/redisson/src/main/java/org/redisson/RedissonBucket.java index 5712c204f..f10c84db3 100644 --- a/redisson/src/main/java/org/redisson/RedissonBucket.java +++ b/redisson/src/main/java/org/redisson/RedissonBucket.java @@ -175,7 +175,7 @@ public class RedissonBucket extends RedissonExpirable implements RBucket { if (value == null) { throw new IllegalArgumentException("Value can't be null"); } - return commandExecutor.writeAsync(getName(), codec, RedisCommands.SETPXNX, getName(), encode(value), "PX", timeUnit.toMillis(timeToLive), "NX"); + return commandExecutor.writeAsync(getName(), codec, RedisCommands.SET_BOOLEAN, getName(), encode(value), "PX", timeUnit.toMillis(timeToLive), "NX"); } @Override @@ -188,6 +188,41 @@ public class RedissonBucket extends RedissonExpirable implements RBucket { return get(trySetAsync(value)); } + @Override + public boolean setIfExists(V value) { + return get(setIfExistsAsync(value)); + } + + @Override + public RFuture setIfExistsAsync(V value) { + if (value == null) { + return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_BOOLEAN, + "local currValue = redis.call('get', KEYS[1]); " + + "if currValue ~= false then " + + "redis.call('del', KEYS[1]); " + + "return 1;" + + "end;" + + "return 0; ", + Collections.singletonList(getName())); + } + + return commandExecutor.writeAsync(getName(), codec, RedisCommands.SET_BOOLEAN, getName(), encode(value), "XX"); + } + + @Override + public boolean setIfExists(V value, long timeToLive, TimeUnit timeUnit) { + return get(setIfExistsAsync(value, timeToLive, timeUnit)); + } + + @Override + public RFuture setIfExistsAsync(V value, long timeToLive, TimeUnit timeUnit) { + if (value == null) { + throw new IllegalArgumentException("Value can't be null"); + } + + return commandExecutor.writeAsync(getName(), codec, RedisCommands.SET_BOOLEAN, getName(), encode(value), "PX", timeUnit.toMillis(timeToLive), "XX"); + } + @Override public RFuture getAndSetAsync(V value, long timeToLive, TimeUnit timeUnit) { return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_OBJECT, diff --git a/redisson/src/main/java/org/redisson/api/RBucket.java b/redisson/src/main/java/org/redisson/api/RBucket.java index ff930c94f..9db4eedcf 100644 --- a/redisson/src/main/java/org/redisson/api/RBucket.java +++ b/redisson/src/main/java/org/redisson/api/RBucket.java @@ -67,6 +67,26 @@ public interface RBucket extends RExpirable, RBucketAsync { */ boolean trySet(V value, long timeToLive, TimeUnit timeUnit); + /** + * Sets value only if it's already exists. + * + * @param value - value to set + * @return {@code true} if successful, or {@code false} if + * element wasn't set + */ + boolean setIfExists(V value); + + /** + * Sets value only if it's already exists. + * + * @param value - value to set + * @param timeToLive - time to live interval + * @param timeUnit - unit of time to live interval + * @return {@code true} if successful, or {@code false} if + * element wasn't set + */ + boolean setIfExists(V value, long timeToLive, TimeUnit timeUnit); + /** * Atomically sets the value to the given updated value * only if serialized state of the current value equals diff --git a/redisson/src/main/java/org/redisson/api/RBucketAsync.java b/redisson/src/main/java/org/redisson/api/RBucketAsync.java index c2927ddee..1cfb3c396 100644 --- a/redisson/src/main/java/org/redisson/api/RBucketAsync.java +++ b/redisson/src/main/java/org/redisson/api/RBucketAsync.java @@ -67,6 +67,26 @@ public interface RBucketAsync extends RExpirableAsync { */ RFuture trySetAsync(V value, long timeToLive, TimeUnit timeUnit); + /** + * Sets value only if it's already exists. + * + * @param value - value to set + * @return {@code true} if successful, or {@code false} if + * element wasn't set + */ + RFuture setIfExistsAsync(V value); + + /** + * Sets value only if it's already exists. + * + * @param value - value to set + * @param timeToLive - time to live interval + * @param timeUnit - unit of time to live interval + * @return {@code true} if successful, or {@code false} if + * element wasn't set + */ + RFuture setIfExistsAsync(V value, long timeToLive, TimeUnit timeUnit); + /** * Atomically sets the value to the given updated value * only if serialized state of the current value equals diff --git a/redisson/src/main/java/org/redisson/api/RBucketReactive.java b/redisson/src/main/java/org/redisson/api/RBucketReactive.java index fc6454958..fe90d9986 100644 --- a/redisson/src/main/java/org/redisson/api/RBucketReactive.java +++ b/redisson/src/main/java/org/redisson/api/RBucketReactive.java @@ -15,10 +15,10 @@ */ package org.redisson.api; -import java.util.concurrent.TimeUnit; - import reactor.core.publisher.Mono; +import java.util.concurrent.TimeUnit; + /** * Reactive implementation of object holder. Max size of object is 512MB @@ -56,6 +56,26 @@ public interface RBucketReactive extends RExpirableReactive { */ Mono trySet(V value, long timeToLive, TimeUnit timeUnit); + /** + * Sets value only if it's already exists. + * + * @param value - value to set + * @return {@code true} if successful, or {@code false} if + * element wasn't set + */ + Mono setIfExists(V value); + + /** + * Sets value only if it's already exists. + * + * @param value - value to set + * @param timeToLive - time to live interval + * @param timeUnit - unit of time to live interval + * @return {@code true} if successful, or {@code false} if + * element wasn't set + */ + Mono setIfExists(V value, long timeToLive, TimeUnit timeUnit); + /** * Atomically sets the value to the given updated value * only if serialized state of the current value equals diff --git a/redisson/src/main/java/org/redisson/api/RBucketRx.java b/redisson/src/main/java/org/redisson/api/RBucketRx.java index 2be2db6d2..cf53bad41 100644 --- a/redisson/src/main/java/org/redisson/api/RBucketRx.java +++ b/redisson/src/main/java/org/redisson/api/RBucketRx.java @@ -15,12 +15,12 @@ */ package org.redisson.api; -import java.util.concurrent.TimeUnit; - import io.reactivex.Completable; import io.reactivex.Maybe; import io.reactivex.Single; +import java.util.concurrent.TimeUnit; + /** * Reactive implementation of object holder. Max size of object is 512MB @@ -58,6 +58,26 @@ public interface RBucketRx extends RExpirableRx { */ Single trySet(V value, long timeToLive, TimeUnit timeUnit); + /** + * Sets value only if it's already exists. + * + * @param value - value to set + * @return {@code true} if successful, or {@code false} if + * element wasn't set + */ + Single setIfExists(V value); + + /** + * Sets value only if it's already exists. + * + * @param value - value to set + * @param timeToLive - time to live interval + * @param timeUnit - unit of time to live interval + * @return {@code true} if successful, or {@code false} if + * element wasn't set + */ + Single setIfExists(V value, long timeToLive, TimeUnit timeUnit); + /** * Atomically sets the value to the given updated value * only if serialized state of the current value equals 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 b35d71a0d..b949c665c 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java +++ b/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java @@ -299,7 +299,7 @@ public interface RedisCommands { RedisCommand GETSET = new RedisCommand("GETSET"); RedisCommand SET = new RedisCommand("SET", new VoidReplayConvertor()); RedisCommand APPEND = new RedisCommand("APPEND", new VoidReplayConvertor()); - RedisCommand SETPXNX = new RedisCommand("SET", new BooleanNotNullReplayConvertor()); + RedisCommand SET_BOOLEAN = new RedisCommand("SET", new BooleanNotNullReplayConvertor()); RedisCommand SETNX = new RedisCommand("SETNX", new BooleanReplayConvertor()); RedisCommand PSETEX = new RedisCommand("PSETEX", new VoidReplayConvertor()); diff --git a/redisson/src/test/java/org/redisson/RedissonBucketTest.java b/redisson/src/test/java/org/redisson/RedissonBucketTest.java index 8902d6fad..06468b8a5 100755 --- a/redisson/src/test/java/org/redisson/RedissonBucketTest.java +++ b/redisson/src/test/java/org/redisson/RedissonBucketTest.java @@ -216,6 +216,23 @@ public class RedissonBucketTest extends BaseTest { assertThat(r1.isExists()).isFalse(); } + @Test + public void testSetIfExists() throws InterruptedException { + RBucket r1 = redisson.getBucket("test1"); + assertThat(r1.setIfExists("0")).isFalse(); + assertThat(r1.isExists()).isFalse(); + r1.set("1"); + assertThat(r1.setIfExists("2")).isTrue(); + assertThat(r1.get()).isEqualTo("2"); + + RBucket r2 = redisson.getBucket("test2"); + r2.set("1"); + assertThat(r2.setIfExists("2", 1, TimeUnit.SECONDS)).isTrue(); + assertThat(r2.get()).isEqualTo("2"); + Thread.sleep(1000); + assertThat(r2.isExists()).isFalse(); + } + @Test public void testTrySet() { RBucket r1 = redisson.getBucket("testTrySet");