Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support KEEPTTL via ValueOperations. #2770

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -77,6 +77,15 @@ public Mono<Boolean> set(K key, V value, Duration timeout) {
stringCommands.set(rawKey(key), rawValue(value), Expiration.from(timeout), SetOption.UPSERT));
}

@Override
public Mono<Boolean> set(K key, V value, boolean keepTtl) {

Assert.notNull(key, "Key must not be null");

Expiration expiration = keepTtl ? Expiration.keepTtl() : Expiration.persistent();
return createMono(stringCommands -> stringCommands.set(rawKey(key), rawValue(value), expiration, SetOption.UPSERT));
}

@Override
public Mono<Boolean> setIfAbsent(K key, V value) {

@@ -115,6 +124,16 @@ public Mono<Boolean> setIfPresent(K key, V value, Duration timeout) {
stringCommands.set(rawKey(key), rawValue(value), Expiration.from(timeout), SetOption.SET_IF_PRESENT));
}

@Override
public Mono<Boolean> setIfPresent(K key, V value, boolean keepTtl) {

Assert.notNull(key, "Key must not be null");

Expiration expiration = keepTtl ? Expiration.keepTtl() : Expiration.persistent();
return createMono(
stringCommands -> stringCommands.set(rawKey(key), rawValue(value), expiration, SetOption.SET_IF_PRESENT));
}

@Override
public Mono<Boolean> multiSet(Map<? extends K, ? extends V> map) {

Original file line number Diff line number Diff line change
@@ -281,6 +281,16 @@ private boolean failsafeInvokePsetEx(RedisConnection connection) {
});
}

@Override
public void set(K key, V value, boolean keepTtl) {

byte[] rawKey = rawKey(key);
byte[] rawValue = rawValue(value);

Expiration expiration = keepTtl ? Expiration.keepTtl() : Expiration.persistent();
execute(connection -> connection.set(rawKey, rawValue, expiration, SetOption.upsert()));
}

@Override
public Boolean setIfAbsent(K key, V value) {

@@ -320,6 +330,16 @@ public Boolean setIfPresent(K key, V value, long timeout, TimeUnit unit) {
return execute(connection -> connection.set(rawKey, rawValue, expiration, SetOption.ifPresent()));
}

@Override
public Boolean setIfPresent(K key, V value, boolean keepTtl) {

byte[] rawKey = rawKey(key);
byte[] rawValue = rawValue(value);

Expiration expiration = keepTtl ? Expiration.keepTtl() : Expiration.persistent();
return execute(connection -> connection.set(rawKey, rawValue, expiration, SetOption.ifPresent()));
}

@Override
public void set(K key, V value, long offset) {

Original file line number Diff line number Diff line change
@@ -58,6 +58,16 @@ public interface ReactiveValueOperations<K, V> {
*/
Mono<Boolean> set(K key, V value, Duration timeout);

/**
* Set {@code value} for {@code key}.
*
* @param key must not be {@literal null}.
* @param value
* @param keepTtl whether to retain TTL associated with the key.
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>
*/
Mono<Boolean> set(K key, V value, boolean keepTtl);

/**
* Set {@code key} to hold the string {@code value} if {@code key} is absent.
*
@@ -98,6 +108,16 @@ public interface ReactiveValueOperations<K, V> {
*/
Mono<Boolean> setIfPresent(K key, V value, Duration timeout);

/**
* Set {@code key} to hold the string {@code value} if {@code key} is present.
*
* @param key must not be {@literal null}.
* @param value
* @param keepTtl whether to retain TTL associated with the key.
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>
*/
Mono<Boolean> setIfPresent(K key, V value, boolean keepTtl);

/**
* Set multiple keys to multiple values using key-value pairs provided in {@code tuple}.
*
Original file line number Diff line number Diff line change
@@ -76,6 +76,16 @@ default void set(K key, V value, Duration timeout) {
}
}

/**
* Set {@code value} for {@code key}.
*
* @param key must not be {@literal null}.
* @param value must not be {@literal null}.
* @param keepTtl whether to retain TTL associated with the key.
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>
*/
void set(K key, V value, boolean keepTtl);

/**
* Set {@code key} to hold the string {@code value} if {@code key} is absent.
*
@@ -175,6 +185,19 @@ default Boolean setIfPresent(K key, V value, Duration timeout) {
return setIfPresent(key, value, timeout.getSeconds(), TimeUnit.SECONDS);
}

/**
* Set {@code key} to hold the string {@code value} if {@code key} is present.
*
* @param key must not be {@literal null}.
* @param value must not be {@literal null}.
* @param keepTtl whether to retain TTL associated with the key.
* @return command result indicating if the key has been set.
* @throws IllegalArgumentException if either {@code key} or {@code value} is not present.
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>
*/
@Nullable
Boolean setIfPresent(K key, V value, boolean keepTtl);

/**
* Set multiple keys to multiple values using key-value pairs provided in {@code tuple}.
*
Original file line number Diff line number Diff line change
@@ -98,6 +98,50 @@ void set() {
valueOperations.get(key).as(StepVerifier::create).expectNext(value).verifyComplete();
}

@ParameterizedRedisTest // GH-2084
void setWithKeepTtl() {

K key = keyFactory.instance();
V value1 = valueFactory.instance();
V value2 = valueFactory.instance();

valueOperations.set(key, value1, Duration.ofMillis(5500)).as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();
valueOperations.set(key, value2, true).as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();

valueOperations.get(key).as(StepVerifier::create) //
.expectNext(value2) //
.verifyComplete();
redisTemplate.getExpire(key).as(StepVerifier::create) //
.assertNext(actual -> assertThat(actual).isBetween(Duration.ofMillis(1), Duration.ofSeconds(6))) //
.verifyComplete();
}

@ParameterizedRedisTest // GH-2084
void setWithoutKeepTtl() {

K key = keyFactory.instance();
V value1 = valueFactory.instance();
V value2 = valueFactory.instance();

valueOperations.set(key, value1, Duration.ofMillis(5500)).as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();
valueOperations.set(key, value2, false).as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();

valueOperations.get(key).as(StepVerifier::create) //
.expectNext(value2) //
.verifyComplete();
redisTemplate.getExpire(key).as(StepVerifier::create) //
.assertNext(actual -> assertThat(actual).isZero()) //
.verifyComplete();
}

@ParameterizedRedisTest // DATAREDIS-602
void setWithExpiry() {

@@ -186,6 +230,58 @@ void setIfPresentWithExpiry() {
}).verifyComplete();
}

@ParameterizedRedisTest // GH-2084
void setIfPresentWithKeepTtl() {

K key = keyFactory.instance();
V value1 = valueFactory.instance();
V value2 = valueFactory.instance();

valueOperations.setIfPresent(key, value1, true).as(StepVerifier::create) //
.expectNext(false) //
.verifyComplete();
valueOperations.set(key, value1, Duration.ofMillis(5500)).as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();

valueOperations.setIfPresent(key, value2, true).as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();

valueOperations.get(key).as(StepVerifier::create) //
.expectNext(value2) //
.verifyComplete();
redisTemplate.getExpire(key).as(StepVerifier::create) //
.assertNext(actual -> assertThat(actual).isBetween(Duration.ofMillis(1), Duration.ofSeconds(6))) //
.verifyComplete();
}

@ParameterizedRedisTest // GH-2084
void setIfPresentWithoutKeepTtl() {

K key = keyFactory.instance();
V value1 = valueFactory.instance();
V value2 = valueFactory.instance();

valueOperations.setIfPresent(key, value1, false).as(StepVerifier::create) //
.expectNext(false) //
.verifyComplete();
valueOperations.set(key, value1, Duration.ofMillis(5500)).as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();

valueOperations.setIfPresent(key, value2, false).as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();

valueOperations.get(key).as(StepVerifier::create) //
.expectNext(value2) //
.verifyComplete();
redisTemplate.getExpire(key).as(StepVerifier::create) //
.assertNext(actual -> assertThat(actual).isZero()) //
.verifyComplete();
}

@ParameterizedRedisTest // DATAREDIS-602
void multiSet() {

Original file line number Diff line number Diff line change
@@ -316,6 +316,37 @@ void testSetWithExpirationWithTimeUnitMilliseconds() {
await().atMost(Duration.ofMillis(500L)).until(() -> !redisTemplate.hasKey(key));
}

@ParameterizedRedisTest // GH-2084
void testSetWithKeepTtl() {

K key = keyFactory.instance();
V value1 = valueFactory.instance();
V value2 = valueFactory.instance();

valueOps.set(key, value1, Duration.ofMillis(5500));
valueOps.set(key, value2, true);

Long expire = redisTemplate.getExpire(key, TimeUnit.MILLISECONDS);

assertThat(valueOps.get(key)).isEqualTo(value2);
assertThat(expire).isLessThan(TimeUnit.SECONDS.toMillis(6));
assertThat(expire).isGreaterThan(TimeUnit.MILLISECONDS.toMillis(1));
}

@ParameterizedRedisTest // GH-2084
void testSetWithoutKeepTtl() {

K key = keyFactory.instance();
V value1 = valueFactory.instance();
V value2 = valueFactory.instance();

valueOps.set(key, value1, Duration.ofMillis(5500));
valueOps.set(key, value2, false);

assertThat(valueOps.get(key)).isEqualTo(value2);
assertThat(redisTemplate.getExpire(key)).isEqualTo(-1);
}

@ParameterizedRedisTest
void testAppend() {

@@ -483,6 +514,39 @@ void testSetIfPresentWithExpirationPX() {
assertThat(valueOps.get(key)).isEqualTo(value2);
}

@ParameterizedRedisTest // GH-2084
void testSetIfPresentWithKeepTtl() {

K key = keyFactory.instance();
V value1 = valueFactory.instance();
V value2 = valueFactory.instance();

assertThat(valueOps.setIfPresent(key, value1, true)).isFalse();
valueOps.set(key, value1, Duration.ofMillis(5500));

Long expire = redisTemplate.getExpire(key, TimeUnit.MILLISECONDS);

assertThat(valueOps.setIfPresent(key, value2, true)).isTrue();
assertThat(valueOps.get(key)).isEqualTo(value2);
assertThat(expire).isLessThan(TimeUnit.SECONDS.toMillis(6));
assertThat(expire).isGreaterThan(TimeUnit.MILLISECONDS.toMillis(1));
}

@ParameterizedRedisTest // GH-2084
void testSetIfPresentWithoutKeepTtl() {

K key = keyFactory.instance();
V value1 = valueFactory.instance();
V value2 = valueFactory.instance();

assertThat(valueOps.setIfPresent(key, value1, false)).isFalse();
valueOps.set(key, value1, Duration.ofMillis(5500));

assertThat(valueOps.setIfPresent(key, value2, false)).isTrue();
assertThat(valueOps.get(key)).isEqualTo(value2);
assertThat(redisTemplate.getExpire(key)).isEqualTo(-1);
}

@ParameterizedRedisTest
void testSize() {