Skip to content

Commit

Permalink
DATAREDIS-611 - Add overloads accepting Duration and Instant.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mp911de authored and christophstrobl committed Jan 27, 2020
1 parent fd85fb4 commit 31d4730
Show file tree
Hide file tree
Showing 7 changed files with 257 additions and 22 deletions.
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
*
Expand All @@ -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.
*
Expand Down
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
*
Expand All @@ -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();
}
Expand Up @@ -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.
Expand Down Expand Up @@ -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}.
*
Expand All @@ -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.
*
Expand All @@ -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();
}
Expand Up @@ -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;
Expand All @@ -31,6 +33,7 @@
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
Expand Down Expand Up @@ -270,7 +273,7 @@ <T> T execute(RedisScript<T> script, RedisSerializer<?> argsSerializer, RedisSer
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
Expand All @@ -280,6 +283,24 @@ <T> T execute(RedisScript<T> script, RedisSerializer<?> argsSerializer, RedisSer
@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.
*
Expand All @@ -290,6 +311,22 @@ <T> T execute(RedisScript<T> script, RedisSerializer<?> argsSerializer, RedisSer
@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}.
*
Expand Down Expand Up @@ -574,7 +611,7 @@ default void restore(K key, byte[] value, long timeToLive, TimeUnit unit) {

/**
* 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.
Expand Down
Expand Up @@ -25,7 +25,7 @@
* @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.
Expand All @@ -38,6 +38,20 @@ public static boolean hasMillis(Duration duration) {
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>
Expand Down

0 comments on commit 31d4730

Please sign in to comment.