diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java index 963e4b4bf..dcfd5d960 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java @@ -3859,7 +3859,16 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco */ @Override public Long xTrim(String key, long count) { - return convertAndReturn(delegate.xTrim(serialize(key), count), identityConverter); + return xTrim(key, count, false); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.StringRedisConnection#xTrim(java.lang.String, long, boolean) + */ + @Override + public Long xTrim(String key, long count, boolean approximateTrimming) { + return convertAndReturn(delegate.xTrim(serialize(key), count, approximateTrimming), identityConverter); } /* @@ -4040,7 +4049,16 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco */ @Override public Long xTrim(byte[] key, long count) { - return delegate.xTrim(key, count); + return xTrim(key, count, false); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStreamCommands#xTrim(byte[], long, boolean) + */ + @Override + public Long xTrim(byte[] key, long count, boolean approximateTrimming) { + return delegate.xTrim(key, count, approximateTrimming); } /** diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java index fcd40b8d4..4b66f1fdf 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java @@ -609,7 +609,13 @@ public interface DefaultedRedisConnection extends RedisConnection { @Override @Deprecated default Long xTrim(byte[] key, long count) { - return streamCommands().xTrim(key, count); + return xTrim(key, count, false); + } + + @Override + @Deprecated + default Long xTrim(byte[] key, long count, boolean approximateTrimming) { + return streamCommands().xTrim(key, count, approximateTrimming); } // LIST COMMANDS diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveStreamCommands.java b/src/main/java/org/springframework/data/redis/connection/ReactiveStreamCommands.java index fd6869d6b..2abf8ee14 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveStreamCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveStreamCommands.java @@ -1376,11 +1376,12 @@ public interface ReactiveStreamCommands { class TrimCommand extends KeyCommand { private @Nullable Long count; + private boolean approximateTrimming; - private TrimCommand(ByteBuffer key, @Nullable Long count) { - + private TrimCommand(ByteBuffer key, @Nullable Long count, boolean approximateTrimming) { super(key); this.count = count; + this.approximateTrimming = approximateTrimming; } /** @@ -1393,7 +1394,7 @@ public interface ReactiveStreamCommands { Assert.notNull(key, "Key must not be null!"); - return new TrimCommand(key, null); + return new TrimCommand(key, null, false); } /** @@ -1401,10 +1402,11 @@ public interface ReactiveStreamCommands { * properties. * * @param count + * @param approximateTrimming * @return a new {@link TrimCommand} with {@literal count} applied. */ - public TrimCommand to(long count) { - return new TrimCommand(getKey(), count); + public TrimCommand to(long count, boolean approximateTrimming) { + return new TrimCommand(getKey(), count, approximateTrimming); } /** @@ -1414,6 +1416,10 @@ public interface ReactiveStreamCommands { public Long getCount() { return count; } + + public boolean isApproximateTrimming() { + return approximateTrimming; + } } /** @@ -1425,10 +1431,23 @@ public interface ReactiveStreamCommands { * @see Redis Documentation: XTRIM */ default Mono xTrim(ByteBuffer key, long count) { + return xTrim(key, count, false); + } + + /** + * Trims the stream to {@code count} elements. + * + * @param key the stream key. + * @param count length of the stream. + * @param approximateTrimming the trimming must be performed in a approximated way in order to maximize performances. + * @return {@link Mono} emitting the number of removed entries. + * @see Redis Documentation: XTRIM + */ + default Mono xTrim(ByteBuffer key, long count, boolean approximateTrimming) { Assert.notNull(key, "Key must not be null!"); - return xTrim(Mono.just(TrimCommand.stream(key).to(count))).next().map(NumericResponse::getOutput); + return xTrim(Mono.just(TrimCommand.stream(key).to(count, approximateTrimming))).next().map(NumericResponse::getOutput); } /** diff --git a/src/main/java/org/springframework/data/redis/connection/RedisStreamCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisStreamCommands.java index 6376c663f..f3d9270ad 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisStreamCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisStreamCommands.java @@ -873,4 +873,16 @@ public interface RedisStreamCommands { */ @Nullable Long xTrim(byte[] key, long count); + + /** + * Trims the stream to {@code count} elements. + * + * @param key the stream key. + * @param count length of the stream. + * @param approximateTrimming the trimming must be performed in a approximated way in order to maximize performances. + * @return number of removed entries. {@literal null} when used in pipeline / transaction. + * @see Redis Documentation: XTRIM + */ + @Nullable + Long xTrim(byte[] key, long count, boolean approximateTrimming); } diff --git a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java index 537804873..5fbae0dcd 100644 --- a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java @@ -2459,4 +2459,17 @@ public interface StringRedisConnection extends RedisConnection { */ @Nullable Long xTrim(String key, long count); + + /** + * Trims the stream to {@code count} elements. + * + * @param key the stream key. + * @param count length of the stream. + * @param approximateTrimming the trimming must be performed in a approximated way in order to maximize performances. + * @return number of removed entries. {@literal null} when used in pipeline / transaction. + * @since 2.2 + * @see Redis Documentation: XTRIM + */ + @Nullable + Long xTrim(String key, long count, boolean approximateTrimming); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStreamCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStreamCommands.java index cf1baeb95..b0d7f6b56 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStreamCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStreamCommands.java @@ -420,7 +420,7 @@ class LettuceReactiveStreamCommands implements ReactiveStreamCommands { Assert.notNull(command.getKey(), "Key must not be null!"); Assert.notNull(command.getCount(), "Count must not be null!"); - return cmd.xtrim(command.getKey(), command.getCount()).map(value -> new NumericResponse<>(command, value)); + return cmd.xtrim(command.getKey(), command.isApproximateTrimming(), command.getCount()).map(value -> new NumericResponse<>(command, value)); })); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStreamCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStreamCommands.java index 0afc6b6ef..62d07c010 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStreamCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStreamCommands.java @@ -662,19 +662,27 @@ class LettuceStreamCommands implements RedisStreamCommands { */ @Override public Long xTrim(byte[] key, long count) { + return xTrim(key, count, false); + } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStreamCommands#xTrim(byte[], long, boolean) + */ + @Override + public Long xTrim(byte[] key, long count, boolean approximateTrimming) { Assert.notNull(key, "Key must not be null!"); try { if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xtrim(key, count))); + pipeline(connection.newLettuceResult(getAsyncConnection().xtrim(key, approximateTrimming, count))); return null; } if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xtrim(key, count))); + transaction(connection.newLettuceResult(getAsyncConnection().xtrim(key, approximateTrimming, count))); return null; } - return getConnection().xtrim(key, count); + return getConnection().xtrim(key, approximateTrimming, count); } catch (Exception ex) { throw convertLettuceAccessException(ex); } diff --git a/src/main/java/org/springframework/data/redis/core/BoundStreamOperations.java b/src/main/java/org/springframework/data/redis/core/BoundStreamOperations.java index f311b9959..55f0d8353 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundStreamOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundStreamOperations.java @@ -208,4 +208,15 @@ public interface BoundStreamOperations { */ @Nullable Long trim(long count); + + /** + * Trims the stream to {@code count} elements. + * + * @param count length of the stream. + * @param approximateTrimming the trimming must be performed in a approximated way in order to maximize performances. + * @return number of removed entries. {@literal null} when used in pipeline / transaction. + * @see Redis Documentation: XTRIM + */ + @Nullable + Long trim(long count, boolean approximateTrimming); } diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundStreamOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundStreamOperations.java index bccb7e0ab..52724c01f 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundStreamOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultBoundStreamOperations.java @@ -170,7 +170,17 @@ class DefaultBoundStreamOperations extends DefaultBoundKeyOperations< @Nullable @Override public Long trim(long count) { - return ops.trim(getKey(), count); + return trim(count, false); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundStreamOperations#trim(long,boolean) + */ + @Nullable + @Override + public Long trim(long count, boolean approximateTrimming) { + return ops.trim(getKey(), count, approximateTrimming); } /* diff --git a/src/main/java/org/springframework/data/redis/core/DefaultReactiveStreamOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultReactiveStreamOperations.java index f628f4a6e..632c72299 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultReactiveStreamOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultReactiveStreamOperations.java @@ -341,10 +341,18 @@ class DefaultReactiveStreamOperations implements ReactiveStreamOperat */ @Override public Mono trim(K key, long count) { + return trim(key, count, false); + } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.ReactiveStreamOperations#trim(java.lang.Object, long, boolean) + */ + @Override + public Mono trim(K key, long count, boolean approximateTrimming) { Assert.notNull(key, "Key must not be null!"); - return createMono(connection -> connection.xTrim(rawKey(key), count)); + return createMono(connection -> connection.xTrim(rawKey(key), count, approximateTrimming)); } @Override diff --git a/src/main/java/org/springframework/data/redis/core/DefaultStreamOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultStreamOperations.java index 21e3a401f..e59cf85c7 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultStreamOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultStreamOperations.java @@ -336,6 +336,12 @@ class DefaultStreamOperations extends AbstractOperations i return execute(connection -> connection.xTrim(rawKey, count), true); } + @Override + public Long trim(K key, long count, boolean approximateTrimming) { + byte[] rawKey = rawKey(key); + return execute(connection -> connection.xTrim(rawKey, count, approximateTrimming), true); + } + @Override public HashMapper getHashMapper(Class targetType) { return objectMapper.getHashMapper(targetType); diff --git a/src/main/java/org/springframework/data/redis/core/ReactiveStreamOperations.java b/src/main/java/org/springframework/data/redis/core/ReactiveStreamOperations.java index 63bc4ba50..aa4280edb 100644 --- a/src/main/java/org/springframework/data/redis/core/ReactiveStreamOperations.java +++ b/src/main/java/org/springframework/data/redis/core/ReactiveStreamOperations.java @@ -544,6 +544,17 @@ public interface ReactiveStreamOperations extends HashMapperProvider< */ Mono trim(K key, long count); + /** + * Trims the stream to {@code count} elements. + * + * @param key the stream key. + * @param count length of the stream. + * @param approximateTrimming the trimming must be performed in a approximated way in order to maximize performances. + * @return number of removed entries. + * @see Redis Documentation: XTRIM + */ + Mono trim(K key, long count, boolean approximateTrimming); + /** * Get the {@link HashMapper} for a specific type. * diff --git a/src/main/java/org/springframework/data/redis/core/StreamOperations.java b/src/main/java/org/springframework/data/redis/core/StreamOperations.java index 003c5a456..9bff7be82 100644 --- a/src/main/java/org/springframework/data/redis/core/StreamOperations.java +++ b/src/main/java/org/springframework/data/redis/core/StreamOperations.java @@ -525,6 +525,18 @@ public interface StreamOperations extends HashMapperProvider @Nullable Long trim(K key, long count); + /** + * Trims the stream to {@code count} elements. + * + * @param key the stream key. + * @param count length of the stream. + * @param approximateTrimming the trimming must be performed in a approximated way in order to maximize performances. + * @return number of removed entries. {@literal null} when used in pipeline / transaction. + * @see Redis Documentation: XTRIM + */ + @Nullable + Long trim(K key, long count, boolean approximateTrimming); + /** * Get the {@link HashMapper} for a specific type. * diff --git a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTests.java b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTests.java index a395b3148..7ca20aa82 100644 --- a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTests.java +++ b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTests.java @@ -1726,6 +1726,13 @@ public class DefaultStringRedisConnectionPipelineTests extends DefaultStringRedi super.xTrimShouldDelegateAndConvertCorrectly(); } + @Test + public void xTrimApproximateShouldDelegateAndConvertCorrectly() { + + doReturn(Arrays.asList(1L)).when(nativeConnection).closePipeline(); + super.xTrimApproximateShouldDelegateAndConvertCorrectly(); + } + protected List getResults() { return connection.closePipeline(); } diff --git a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTxTests.java b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTxTests.java index 587176c91..e4c382a37 100644 --- a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTxTests.java +++ b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTxTests.java @@ -1846,6 +1846,13 @@ public class DefaultStringRedisConnectionPipelineTxTests extends DefaultStringRe super.xTrimShouldDelegateAndConvertCorrectly(); } + @Test + public void xTrimApproximateShouldDelegateAndConvertCorrectly() { + + doReturn(Arrays.asList(Arrays.asList(1L))).when(nativeConnection).closePipeline(); + super.xTrimApproximateShouldDelegateAndConvertCorrectly(); + } + @SuppressWarnings("unchecked") protected List getResults() { connection.exec(); diff --git a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTests.java b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTests.java index 344775641..4075d70d6 100644 --- a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTests.java +++ b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTests.java @@ -2169,6 +2169,15 @@ public class DefaultStringRedisConnectionTests { Assertions.assertThat(getResults()).containsExactly(1L); } + @Test + public void xTrimApproximateShouldDelegateAndConvertCorrectly() { + + doReturn(1L).when(nativeConnection).xTrim(any(), anyLong(), anyBoolean()); + + actual.add(connection.xTrim("key", 2L, true)); + Assertions.assertThat(getResults()).containsExactly(1L); + } + protected List getResults() { return actual; } diff --git a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTxTests.java b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTxTests.java index ee8121f0e..2d31ee0e7 100644 --- a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTxTests.java +++ b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTxTests.java @@ -1733,6 +1733,13 @@ public class DefaultStringRedisConnectionTxTests extends DefaultStringRedisConne super.xTrimShouldDelegateAndConvertCorrectly(); } + @Test + public void xTrimApproximateShouldDelegateAndConvertCorrectly() { + + doReturn(Arrays.asList(1L)).when(nativeConnection).exec(); + super.xTrimApproximateShouldDelegateAndConvertCorrectly(); + } + protected List getResults() { return connection.exec(); }