DATAREDIS-1103 - Polishing.

Move keepTTL to Expiration and remove superfluous methods from interfaces. Add tests for reactive variant and work around an open issue in Jedis to support KEEPTTL though the API does not offer that option directly.

Original Pull Request: #562
This commit is contained in:
Christoph Strobl
2020-10-08 08:30:02 +02:00
parent 232c8a5dd4
commit 0f54fcf796
14 changed files with 117 additions and 98 deletions

View File

@@ -993,15 +993,6 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
return convertAndReturn(delegate.set(key, value, expiration, option), identityConverter);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[], org.springframework.data.redis.core.types.Expiration, org.springframework.data.redis.connection.RedisStringCommands.SetOptions, boolean)
*/
@Override
public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option, boolean keepTtl) {
return convertAndReturn(delegate.set(key, value, expiration, option, keepTtl), identityConverter);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisStringCommands#setBit(byte[], long, boolean)

View File

@@ -294,13 +294,6 @@ public interface DefaultedRedisConnection extends RedisConnection {
return stringCommands().set(key, value, expiration, option);
}
/** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */
@Override
@Deprecated
default Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option, boolean keepTtl) {
return stringCommands().set(key, value, expiration, option, keepTtl);
}
/** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */
@Override
@Deprecated

View File

@@ -169,7 +169,8 @@ public interface ReactiveStringCommands {
*
* @param key must not be {@literal null}.
* @param value must not be {@literal null}.
* @param expiration must not be {@literal null}.
* @param expiration must not be {@literal null}. Use {@link Expiration#persistent()} for no expiration time or
* {@link Expiration#keepTtl()} to keep the existing.
* @param option must not be {@literal null}.
* @return
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>

View File

@@ -83,7 +83,8 @@ public interface RedisStringCommands {
*
* @param key must not be {@literal null}.
* @param value must not be {@literal null}.
* @param expiration must not be {@literal null}. Use {@link Expiration#persistent()} to not set any ttl.
* @param expiration must not be {@literal null}. Use {@link Expiration#persistent()} to not set any ttl or
* {@link Expiration#keepTtl()} to keep the existing expiration.
* @param option must not be {@literal null}. Use {@link SetOption#upsert()} to add non existing.
* @return {@literal null} when used in pipeline / transaction.
* @since 1.7
@@ -92,22 +93,6 @@ public interface RedisStringCommands {
@Nullable
Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option);
/**
* Set {@code value} for {@code key} applying timeouts from {@code expiration} if set and inserting/updating values
* depending on {@code option}.
*
* @param key must not be {@literal null}.
* @param value must not be {@literal null}.
* @param expiration must not be {@literal null}. Use {@link Expiration#persistent()} to not set any ttl.
* @param option must not be {@literal null}. Use {@link SetOption#upsert()} to add non existing.
* @param keepTtl set the value and retain the existing TTL.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.4
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>
*/
@Nullable
Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option, boolean keepTtl);
/**
* Set {@code value} for {@code key}, only if {@code key} does not exist.
*

View File

@@ -420,7 +420,8 @@ public interface StringRedisConnection extends RedisConnection {
*
* @param key must not be {@literal null}.
* @param value must not be {@literal null}.
* @param expiration can be {@literal null}. Defaulted to {@link Expiration#persistent()}.
* @param expiration can be {@literal null}. Defaulted to {@link Expiration#persistent()}. Use
* {@link Expiration#keepTtl()} to keep the existing expiration.
* @param option can be {@literal null}. Defaulted to {@link SetOption#UPSERT}.
* @since 1.7
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>

View File

@@ -127,20 +127,11 @@ class JedisClusterStringCommands implements RedisStringCommands {
*/
@Override
public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option) {
return set(key, value, expiration, option, false);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[], org.springframework.data.redis.core.types.Expiration, org.springframework.data.redis.connection.RedisStringCommands.SetOptions, boolean)
*/
@Override
public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option, boolean keepTtl) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(value, "Value must not be null!");
Assert.notNull(expiration, "Expiration must not be null!");
Assert.notNull(option, "Option must not be null!");
Assert.isTrue(keepTtl, "KEEPTTL is currently not supported in jedis!");
SetParams setParams = JedisConverters.toSetCommandExPxArgument(expiration,
JedisConverters.toSetCommandNxXxArgument(option));

View File

@@ -533,6 +533,24 @@ abstract public class JedisConverters extends Converters {
SetParams paramsToUse = params == null ? SetParams.setParams() : params;
if (expiration.isKeepTtl()) {
// TODO: remove once jedis supports KEEPTTL (https://github.com/xetorthio/jedis/issues/2248)
return new SetParams() {
@Override
public byte[][] getByteParams(byte[]... args) {
ArrayList<byte[]> byteParams = new ArrayList<>();
for (byte[] arg : paramsToUse.getByteParams(args)) {
byteParams.add(arg);
}
byteParams.add(SafeEncoder.encode("keepttl"));
return byteParams.toArray(new byte[byteParams.size()][]);
}
};
}
if (!expiration.isPersistent()) {
if (expiration.getTimeUnit() == TimeUnit.MILLISECONDS) {
return paramsToUse.px(expiration.getExpirationTime());

View File

@@ -153,20 +153,11 @@ class JedisStringCommands implements RedisStringCommands {
*/
@Override
public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option) {
return set(key, value, expiration, option, false);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[], org.springframework.data.redis.core.types.Expiration, org.springframework.data.redis.connection.RedisStringCommands.SetOption, boolean)
*/
@Override
public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option, boolean keepTtl) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(value, "Value must not be null!");
Assert.notNull(expiration, "Expiration must not be null!");
Assert.notNull(option, "Option must not be null!");
Assert.isTrue(keepTtl, "KEEPTTL is currently not supported in jedis!");
SetParams params = JedisConverters.toSetCommandExPxArgument(expiration,
JedisConverters.toSetCommandNxXxArgument(option));

View File

@@ -768,36 +768,26 @@ abstract public class LettuceConverters extends Converters {
* @since 1.7
*/
public static SetArgs toSetArgs(@Nullable Expiration expiration, @Nullable SetOption option) {
return toSetArgs(expiration, option, false);
}
/**
* Converts a given {@link Expiration} and {@link SetOption} to the according {@link SetArgs}.<br />
*
* @param expiration can be {@literal null}.
* @param option can be {@literal null}.
* @param keepTtl set the value and retain the existing TTL.
* @since 2.4
*/
public static SetArgs toSetArgs(@Nullable Expiration expiration, @Nullable SetOption option, boolean keepTtl) {
SetArgs args = new SetArgs();
if (expiration != null && !expiration.isPersistent()) {
switch (expiration.getTimeUnit()) {
case SECONDS:
args.ex(expiration.getExpirationTime());
break;
default:
args.px(expiration.getConverted(TimeUnit.MILLISECONDS));
break;
if (expiration != null) {
if (expiration.isKeepTtl()) {
args.keepttl();
} else if (!expiration.isPersistent()) {
switch (expiration.getTimeUnit()) {
case SECONDS:
args.ex(expiration.getExpirationTime());
break;
default:
args.px(expiration.getConverted(TimeUnit.MILLISECONDS));
break;
}
}
}
if (keepTtl) {
args.keepttl();
}
if (option != null) {
switch (option) {

View File

@@ -157,15 +157,7 @@ class LettuceStringCommands implements RedisStringCommands {
*/
@Override
public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option) {
return set(key, value, expiration, option, false);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[], org.springframework.data.redis.core.types.Expiration, org.springframework.data.redis.connection.RedisStringCommands.SetOption, boolean)
*/
@Override
public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option, boolean keepTtl) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(value, "Value must not be null!");
Assert.notNull(expiration, "Expiration must not be null!");
@@ -174,18 +166,18 @@ class LettuceStringCommands implements RedisStringCommands {
try {
if (isPipelined()) {
pipeline(connection.newLettuceResult(
getAsyncConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option, keepTtl)),
getAsyncConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option)),
Converters.stringToBooleanConverter(), () -> false));
return null;
}
if (isQueueing()) {
transaction(connection.newLettuceResult(
getAsyncConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option, keepTtl)),
getAsyncConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option)),
Converters.stringToBooleanConverter(), () -> false));
return null;
}
return Converters
.stringToBoolean(getConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option, keepTtl)));
.stringToBoolean(getConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option)));
} catch (Exception ex) {
throw convertLettuceAccessException(ex);
}

View File

@@ -115,6 +115,19 @@ public class Expiration {
return new Expiration(expirationTime, TimeUnit.MILLISECONDS);
}
/**
* Obtain an {@link Expiration} that indicates to keep the existing one. Eg. when sending a {@code SET} command.
* <p />
* <strong>NOTE: </strong>Please follow the documentation of the individual commands to see if {@link #keepTtl()} is
* applicable.
*
* @return never {@literal null}.
* @since 2.4
*/
public static Expiration keepTtl() {
return KeepTtl.INSTANCE;
}
/**
* Creates new {@link Expiration} with the provided {@link TimeUnit}. Greater units than {@link TimeUnit#SECONDS} are
* converted to {@link TimeUnit#SECONDS}. Units smaller than {@link TimeUnit#MILLISECONDS} are converted to
@@ -175,4 +188,30 @@ public class Expiration {
public boolean isPersistent() {
return expirationTime == -1;
}
/**
* @return {@literal true} if {@link Expiration} of existing key should not be modified.
* @since 2.4
*/
public boolean isKeepTtl() {
return false;
}
/**
* @author Christoph Strobl
* @since 2.4
*/
private static class KeepTtl extends Expiration {
static KeepTtl INSTANCE = new KeepTtl();
private KeepTtl() {
super(-2, null);
}
@Override
public boolean isKeepTtl() {
return true;
}
}
}