DATAREDIS-611 - Add overloads accepting Duration and Instant.

We revised our imperative Template API by accepting Duration and Instant types in addition to methods accepting timeout/TimeUnit respective Date.

Original Pull Request: #501
This commit is contained in:
Mark Paluch
2019-11-19 10:17:07 +01:00
committed by Christoph Strobl
parent fd85fb4eb5
commit 31d4730222
7 changed files with 259 additions and 24 deletions

View File

@@ -15,11 +15,14 @@
*/
package org.springframework.data.redis.core;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import org.springframework.data.redis.connection.DataType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Operations over a Redis key. Useful for executing common key-'bound' operations to all implementations.
@@ -57,6 +60,22 @@ public interface BoundKeyOperations<K> {
@Nullable
Long getExpire();
/**
* Sets the key time-to-live/expiration.
*
* @param timeout must not be {@literal null}.
* @return true if expiration was set, false otherwise. {@literal null} when used in pipeline / transaction.
* @since 2.3
*/
@Nullable
default Boolean expire(Duration timeout) {
Assert.notNull(timeout, "Timeout must not be null");
Assert.isTrue(!timeout.isNegative(), "Timeout must not be negative");
return expire(timeout.toMillis(), TimeUnit.MILLISECONDS);
}
/**
* Sets the key time-to-live/expiration.
*
@@ -76,6 +95,21 @@ public interface BoundKeyOperations<K> {
@Nullable
Boolean expireAt(Date date);
/**
* Sets the key time-to-live/expiration.
*
* @param time expiration time.
* @return true if expiration was set, false otherwise. {@literal null} when used in pipeline / transaction.
* @since 2.3
*/
@Nullable
default Boolean expireAt(Instant expireAt) {
Assert.notNull(expireAt, "Timestamp must not be null");
return expireAt(Date.from(expireAt));
}
/**
* Removes the expiration (if any) of the key.
*

View File

@@ -15,10 +15,12 @@
*/
package org.springframework.data.redis.core;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* List operations bound to a certain key.
@@ -188,6 +190,24 @@ public interface BoundListOperations<K, V> extends BoundKeyOperations<K> {
@Nullable
V leftPop(long timeout, TimeUnit unit);
/**
* Removes and returns first element from lists stored at the bound key . <br>
* <b>Blocks connection</b> until element available or {@code timeout} reached.
*
* @param timeout must not be {@literal null}.
* @return {@literal null} when timeout reached or used in pipeline / transaction.
* @since 2.3
* @see <a href="https://redis.io/commands/blpop">Redis Documentation: BLPOP</a>
*/
@Nullable
default V leftPop(Duration timeout) {
Assert.notNull(timeout, "Timeout must not be null");
Assert.isTrue(!timeout.isNegative(), "Timeout must not be negative");
return leftPop(TimeoutUtils.toSeconds(timeout), TimeUnit.SECONDS);
}
/**
* Removes and returns last element in list stored at the bound key.
*
@@ -209,5 +229,23 @@ public interface BoundListOperations<K, V> extends BoundKeyOperations<K> {
@Nullable
V rightPop(long timeout, TimeUnit unit);
/**
* Removes and returns last element from lists stored at the bound key. <br>
* <b>Blocks connection</b> until element available or {@code timeout} reached.
*
* @param timeout must not be {@literal null}.
* @return {@literal null} when timeout reached or used in pipeline / transaction.
* @since 2.3
* @see <a href="https://redis.io/commands/brpop">Redis Documentation: BRPOP</a>
*/
@Nullable
default V rightPop(Duration timeout) {
Assert.notNull(timeout, "Timeout must not be null");
Assert.isTrue(!timeout.isNegative(), "Timeout must not be negative");
return rightPop(TimeoutUtils.toSeconds(timeout), TimeUnit.SECONDS);
}
RedisOperations<K, V> getOperations();
}

View File

@@ -15,11 +15,13 @@
*/
package org.springframework.data.redis.core;
import java.time.Duration;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Redis list specific operations.
@@ -234,6 +236,25 @@ public interface ListOperations<K, V> {
@Nullable
V leftPop(K key, long timeout, TimeUnit unit);
/**
* Removes and returns first element from lists stored at {@code key} . <br>
* <b>Blocks connection</b> until element available or {@code timeout} reached.
*
* @param key must not be {@literal null}.
* @param timeout must not be {@literal null}.
* @return can be {@literal null}.
* @since 2.3
* @see <a href="https://redis.io/commands/blpop">Redis Documentation: BLPOP</a>
*/
@Nullable
default V leftPop(K key, Duration timeout) {
Assert.notNull(timeout, "Timeout must not be null");
Assert.isTrue(!timeout.isNegative(), "Timeout must not be negative");
return leftPop(key, TimeoutUtils.toSeconds(timeout), TimeUnit.SECONDS);
}
/**
* Removes and returns last element in list stored at {@code key}.
*
@@ -257,6 +278,25 @@ public interface ListOperations<K, V> {
@Nullable
V rightPop(K key, long timeout, TimeUnit unit);
/**
* Removes and returns last element from lists stored at {@code key}. <br>
* <b>Blocks connection</b> until element available or {@code timeout} reached.
*
* @param key must not be {@literal null}.
* @param timeout must not be {@literal null}.
* @return can be {@literal null}.
* @since 2.3
* @see <a href="https://redis.io/commands/brpop">Redis Documentation: BRPOP</a>
*/
@Nullable
default V rightPop(K key, Duration timeout) {
Assert.notNull(timeout, "Timeout must not be null");
Assert.isTrue(!timeout.isNegative(), "Timeout must not be negative");
return rightPop(key, TimeoutUtils.toSeconds(timeout), TimeUnit.SECONDS);
}
/**
* Remove the last element from list at {@code sourceKey}, append it to {@code destinationKey} and return its value.
*
@@ -282,5 +322,25 @@ public interface ListOperations<K, V> {
@Nullable
V rightPopAndLeftPush(K sourceKey, K destinationKey, long timeout, TimeUnit unit);
/**
* Remove the last element from list at {@code srcKey}, append it to {@code dstKey} and return its value.<br>
* <b>Blocks connection</b> until element available or {@code timeout} reached.
*
* @param sourceKey must not be {@literal null}.
* @param destinationKey must not be {@literal null}.
* @param timeout must not be {@literal null}.
* @return can be {@literal null}.
* @since 2.3
* @see <a href="https://redis.io/commands/brpoplpush">Redis Documentation: BRPOPLPUSH</a>
*/
@Nullable
default V rightPopAndLeftPush(K sourceKey, K destinationKey, Duration timeout) {
Assert.notNull(timeout, "Timeout must not be null");
Assert.isTrue(!timeout.isNegative(), "Timeout must not be negative");
return rightPopAndLeftPush(sourceKey, destinationKey, TimeoutUtils.toSeconds(timeout), TimeUnit.SECONDS);
}
RedisOperations<K, V> getOperations();
}

View File

@@ -16,6 +16,8 @@
package org.springframework.data.redis.core;
import java.io.Closeable;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.Date;
import java.util.List;
@@ -31,6 +33,7 @@ import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.data.redis.hash.HashMapper;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Interface that specified a basic set of Redis operations, implemented by {@link RedisTemplate}. Not often used but a
@@ -270,7 +273,7 @@ public interface RedisOperations<K, V> {
Boolean renameIfAbsent(K oldKey, K newKey);
/**
* Set time to live for given {@code key}..
* Set time to live for given {@code key}.
*
* @param key must not be {@literal null}.
* @param timeout
@@ -280,6 +283,24 @@ public interface RedisOperations<K, V> {
@Nullable
Boolean expire(K key, long timeout, TimeUnit unit);
/**
* Set time to live for given {@code key}.
*
* @param key must not be {@literal null}.
* @param timeout must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.3
*/
@Nullable
default Boolean expire(K key, Duration timeout) {
Assert.notNull(timeout, "Timeout must not be null");
Assert.isTrue(!timeout.isNegative(), "Timeout must not be negative");
return TimeoutUtils.hasMillis(timeout) ? expire(key, timeout.toMillis(), TimeUnit.MILLISECONDS)
: expire(key, timeout.getSeconds(), TimeUnit.SECONDS);
}
/**
* Set the expiration for given {@code key} as a {@literal date} timestamp.
*
@@ -290,6 +311,22 @@ public interface RedisOperations<K, V> {
@Nullable
Boolean expireAt(K key, Date date);
/**
* Set the expiration for given {@code key} as a {@literal date} timestamp.
*
* @param key must not be {@literal null}.
* @param expireAt must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.3
*/
@Nullable
default Boolean expireAt(K key, Instant expireAt) {
Assert.notNull(expireAt, "Timestamp must not be null");
return expireAt(key, Date.from(expireAt));
}
/**
* Remove the expiration from given {@code key}.
*
@@ -574,7 +611,7 @@ public interface RedisOperations<K, V> {
/**
* Returns the operations performed on hash values bound to the given key. * @param <HK> hash key (or field) type
*
*
* @param <HV> hash value type
* @param key Redis key
* @return hash operations bound to the given key.

View File

@@ -25,7 +25,7 @@ import java.util.concurrent.TimeUnit;
* @author Mark Paluch
* @author Christoph Strobl
*/
abstract public class TimeoutUtils {
public abstract class TimeoutUtils {
/**
* Check if a given Duration can be represented in {@code sec} or requires {@code msec} representation.
@@ -38,6 +38,20 @@ abstract public class TimeoutUtils {
return duration.toMillis() % 1000 != 0;
}
/**
* Converts the given timeout to seconds.
* <p>
* Since a 0 timeout blocks some Redis ops indefinitely, this method will return 1 if the original value is greater
* than 0 but is truncated to 0 on conversion.
*
* @param duration The duration to convert
* @return The converted timeout
* @since 2.3
*/
public static long toSeconds(Duration duration) {
return roundUpIfNecessary(duration.toMillis(), duration.getSeconds());
}
/**
* Converts the given timeout to seconds.
* <p>