Skip to content

Commit 232c8a5

Browse files
denglimingchristophstrobl
authored andcommitted
DATAREDIS-1103 - Support new KEEPTTL option of the SET operation
Original Pull Request: #562
1 parent 3920890 commit 232c8a5

File tree

8 files changed

+98
-3
lines changed

8 files changed

+98
-3
lines changed

src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
* @author Ninad Divadkar
7070
* @author Tugdual Grall
7171
* @author Andrey Shlykov
72+
* @author dengliming
7273
*/
7374
public class DefaultStringRedisConnection implements StringRedisConnection, DecoratedRedisConnection {
7475

@@ -992,6 +993,15 @@ public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption op
992993
return convertAndReturn(delegate.set(key, value, expiration, option), identityConverter);
993994
}
994995

996+
/*
997+
* (non-Javadoc)
998+
* @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)
999+
*/
1000+
@Override
1001+
public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option, boolean keepTtl) {
1002+
return convertAndReturn(delegate.set(key, value, expiration, option, keepTtl), identityConverter);
1003+
}
1004+
9951005
/*
9961006
* (non-Javadoc)
9971007
* @see org.springframework.data.redis.connection.RedisStringCommands#setBit(byte[], long, boolean)

src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,13 @@ default Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption o
294294
return stringCommands().set(key, value, expiration, option);
295295
}
296296

297+
/** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */
298+
@Override
299+
@Deprecated
300+
default Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option, boolean keepTtl) {
301+
return stringCommands().set(key, value, expiration, option, keepTtl);
302+
}
303+
297304
/** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */
298305
@Override
299306
@Deprecated

src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,22 @@ enum BitOperation {
9292
@Nullable
9393
Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option);
9494

95+
/**
96+
* Set {@code value} for {@code key} applying timeouts from {@code expiration} if set and inserting/updating values
97+
* depending on {@code option}.
98+
*
99+
* @param key must not be {@literal null}.
100+
* @param value must not be {@literal null}.
101+
* @param expiration must not be {@literal null}. Use {@link Expiration#persistent()} to not set any ttl.
102+
* @param option must not be {@literal null}. Use {@link SetOption#upsert()} to add non existing.
103+
* @param keepTtl set the value and retain the existing TTL.
104+
* @return {@literal null} when used in pipeline / transaction.
105+
* @since 2.4
106+
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>
107+
*/
108+
@Nullable
109+
Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option, boolean keepTtl);
110+
95111
/**
96112
* Set {@code value} for {@code key}, only if {@code key} does not exist.
97113
*

src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStringCommands.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
* @author Christoph Strobl
4242
* @author Mark Paluch
4343
* @author Xiaohu Zhang
44+
* @author dengliming
4445
* @since 2.0
4546
*/
4647
class JedisClusterStringCommands implements RedisStringCommands {
@@ -126,11 +127,20 @@ public Boolean set(byte[] key, byte[] value) {
126127
*/
127128
@Override
128129
public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option) {
130+
return set(key, value, expiration, option, false);
131+
}
129132

133+
/*
134+
* (non-Javadoc)
135+
* @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)
136+
*/
137+
@Override
138+
public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option, boolean keepTtl) {
130139
Assert.notNull(key, "Key must not be null!");
131140
Assert.notNull(value, "Value must not be null!");
132141
Assert.notNull(expiration, "Expiration must not be null!");
133142
Assert.notNull(option, "Option must not be null!");
143+
Assert.isTrue(keepTtl, "KEEPTTL is currently not supported in jedis!");
134144

135145
SetParams setParams = JedisConverters.toSetCommandExPxArgument(expiration,
136146
JedisConverters.toSetCommandNxXxArgument(option));

src/main/java/org/springframework/data/redis/connection/jedis/JedisStringCommands.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
/**
3535
* @author Christoph Strobl
3636
* @author Mark Paluch
37+
* @author dengliming
3738
* @since 2.0
3839
*/
3940
class JedisStringCommands implements RedisStringCommands {
@@ -152,11 +153,20 @@ public Boolean set(byte[] key, byte[] value) {
152153
*/
153154
@Override
154155
public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option) {
156+
return set(key, value, expiration, option, false);
157+
}
155158

159+
/*
160+
* (non-Javadoc)
161+
* @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)
162+
*/
163+
@Override
164+
public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option, boolean keepTtl) {
156165
Assert.notNull(key, "Key must not be null!");
157166
Assert.notNull(value, "Value must not be null!");
158167
Assert.notNull(expiration, "Expiration must not be null!");
159168
Assert.notNull(option, "Option must not be null!");
169+
Assert.isTrue(keepTtl, "KEEPTTL is currently not supported in jedis!");
160170

161171
SetParams params = JedisConverters.toSetCommandExPxArgument(expiration,
162172
JedisConverters.toSetCommandNxXxArgument(option));

src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
* @author Thomas Darimont
8383
* @author Mark Paluch
8484
* @author Ninad Divadkar
85+
* @author dengliming
8586
*/
8687
abstract public class LettuceConverters extends Converters {
8788

@@ -767,6 +768,18 @@ public static RedisClusterNode toRedisClusterNode(io.lettuce.core.cluster.models
767768
* @since 1.7
768769
*/
769770
public static SetArgs toSetArgs(@Nullable Expiration expiration, @Nullable SetOption option) {
771+
return toSetArgs(expiration, option, false);
772+
}
773+
774+
/**
775+
* Converts a given {@link Expiration} and {@link SetOption} to the according {@link SetArgs}.<br />
776+
*
777+
* @param expiration can be {@literal null}.
778+
* @param option can be {@literal null}.
779+
* @param keepTtl set the value and retain the existing TTL.
780+
* @since 2.4
781+
*/
782+
public static SetArgs toSetArgs(@Nullable Expiration expiration, @Nullable SetOption option, boolean keepTtl) {
770783

771784
SetArgs args = new SetArgs();
772785
if (expiration != null && !expiration.isPersistent()) {
@@ -781,6 +794,10 @@ public static SetArgs toSetArgs(@Nullable Expiration expiration, @Nullable SetOp
781794
}
782795
}
783796

797+
if (keepTtl) {
798+
args.keepttl();
799+
}
800+
784801
if (option != null) {
785802

786803
switch (option) {

src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
/**
3737
* @author Christoph Strobl
3838
* @author Mark Paluch
39+
* @author dengliming
3940
* @since 2.0
4041
*/
4142
class LettuceStringCommands implements RedisStringCommands {
@@ -156,7 +157,15 @@ public Boolean set(byte[] key, byte[] value) {
156157
*/
157158
@Override
158159
public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option) {
160+
return set(key, value, expiration, option, false);
161+
}
159162

163+
/*
164+
* (non-Javadoc)
165+
* @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)
166+
*/
167+
@Override
168+
public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option, boolean keepTtl) {
160169
Assert.notNull(key, "Key must not be null!");
161170
Assert.notNull(value, "Value must not be null!");
162171
Assert.notNull(expiration, "Expiration must not be null!");
@@ -165,18 +174,18 @@ public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption op
165174
try {
166175
if (isPipelined()) {
167176
pipeline(connection.newLettuceResult(
168-
getAsyncConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option)),
177+
getAsyncConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option, keepTtl)),
169178
Converters.stringToBooleanConverter(), () -> false));
170179
return null;
171180
}
172181
if (isQueueing()) {
173182
transaction(connection.newLettuceResult(
174-
getAsyncConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option)),
183+
getAsyncConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option, keepTtl)),
175184
Converters.stringToBooleanConverter(), () -> false));
176185
return null;
177186
}
178187
return Converters
179-
.stringToBoolean(getConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option)));
188+
.stringToBoolean(getConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option, keepTtl)));
180189
} catch (Exception ex) {
181190
throw convertLettuceAccessException(ex);
182191
}

src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.springframework.data.redis.connection.lettuce;
1717

1818
import static org.assertj.core.api.Assertions.*;
19+
import static org.assertj.core.api.Assertions.assertThat;
1920
import static org.assertj.core.data.Offset.offset;
2021
import static org.springframework.data.redis.connection.BitFieldSubCommands.*;
2122
import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldIncrBy.Overflow.*;
@@ -2466,4 +2467,19 @@ public void bitfieldShouldWorkUsingNonZeroBasedOffset() {
24662467
.valueAt(BitFieldSubCommands.Offset.offset(1L).multipliedByTypeLength()))).containsExactly(100L,
24672468
-56L);
24682469
}
2470+
2471+
@Test // DATAREDIS-1103
2472+
public void setKeepTTL() {
2473+
2474+
long expireSeconds = 10;
2475+
assertThat(clusterConnection.setEx(KEY_1_BYTES, expireSeconds, VALUE_2_BYTES));
2476+
2477+
assertThat(clusterConnection.get(KEY_1_BYTES)).isEqualTo(VALUE_2_BYTES);
2478+
2479+
assertThat(clusterConnection.set(KEY_1_BYTES, VALUE_2_BYTES, Expiration.persistent(), SetOption.upsert(), true));
2480+
2481+
long ttl = clusterConnection.ttl(KEY_1_BYTES);
2482+
2483+
assertThat(0 < ttl && ttl <= expireSeconds);
2484+
}
24692485
}

0 commit comments

Comments
 (0)