Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit fc93414

Browse files
Align method names of RedisCacheWriter with RedisCache.
Also undo change type to record which is leaking the underlying Iterator and add more tests. Original Pull Request: #3243
1 parent 4248545 commit fc93414

File tree

6 files changed

+190
-44
lines changed

6 files changed

+190
-44
lines changed

‎src/main/java/org/springframework/data/redis/cache/BatchStrategies.java‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,16 @@ public long cleanCache(RedisConnection connection, String name, byte[] pattern)
132132
*
133133
* @param <T>
134134
*/
135-
record PartitionIterator<T>(Iterator<T> iterator, int size) implements Iterator<List<T>> {
135+
static class PartitionIterator<T> implements Iterator<List<T>> {
136+
137+
private final Iterator<T> iterator;
138+
private final int size;
139+
140+
PartitionIterator(Iterator<T> iterator, int size) {
141+
142+
this.iterator = iterator;
143+
this.size = size;
144+
}
136145

137146
@Override
138147
public boolean hasNext() {

‎src/main/java/org/springframework/data/redis/cache/DefaultRedisCacheWriter.java‎

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -416,20 +416,20 @@ public byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Durat
416416
}
417417

418418
@Override
419-
public void remove(String name, byte[] key) {
419+
public void evict(String name, byte[] key) {
420420

421421
Assert.notNull(name, "Name must not be null");
422422
Assert.notNull(key, "Key must not be null");
423423

424424
if (writeAsynchronously()) {
425425
asyncCacheWriter.remove(name, key).thenRun(() -> statistics.incDeletes(name));
426426
} else {
427-
removeIfPresent(name, key);
427+
evictIfPresent(name, key);
428428
}
429429
}
430430

431431
@Override
432-
public boolean removeIfPresent(String name, byte[] key) {
432+
public boolean evictIfPresent(String name, byte[] key) {
433433

434434
Long removals = execute(name, connection -> connection.keyCommands().del(key));
435435
statistics.incDeletes(name);
@@ -438,13 +438,13 @@ public boolean removeIfPresent(String name, byte[] key) {
438438
}
439439

440440
@Override
441-
public void clean(String name, byte[] pattern) {
441+
public void clear(String name, byte[] pattern) {
442442

443443
Assert.notNull(name, "Name must not be null");
444444
Assert.notNull(pattern, "Pattern must not be null");
445445

446446
if (writeAsynchronously()) {
447-
asyncCacheWriter.clean(name, pattern, batchStrategy)
447+
asyncCacheWriter.clear(name, pattern, batchStrategy)
448448
.thenAccept(deleteCount -> statistics.incDeletesBy(name, deleteCount.intValue()));
449449
return;
450450
}
@@ -651,8 +651,9 @@ interface AsyncCacheWriter {
651651
* @param pattern {@link String pattern} used to match Redis keys to clear.
652652
* @param batchStrategy strategy to use.
653653
* @return a future that signals completion emitting the number of removed keys.
654+
* @since 4.0
654655
*/
655-
CompletableFuture<Long> clean(String name, byte[] pattern, BatchStrategy batchStrategy);
656+
CompletableFuture<Long> clear(String name, byte[] pattern, BatchStrategy batchStrategy);
656657

657658
}
658659

@@ -686,7 +687,7 @@ public CompletableFuture<Void> remove(String name, byte[] key) {
686687
}
687688

688689
@Override
689-
public CompletableFuture<Long> clean(String name, byte[] pattern, BatchStrategy batchStrategy) {
690+
public CompletableFuture<Long> clear(String name, byte[] pattern, BatchStrategy batchStrategy) {
690691
throw new UnsupportedOperationException("async clean not supported");
691692
}
692693

@@ -701,10 +702,10 @@ public CompletableFuture<Long> clean(String name, byte[] pattern, BatchStrategy
701702
class AsynchronousCacheWriterDelegate implements AsyncCacheWriter {
702703

703704
private static final int DEFAULT_SCAN_BATCH_SIZE = 64;
704-
private final int cleanBatchSize;
705+
private final int clearBatchSize;
705706

706707
public AsynchronousCacheWriterDelegate() {
707-
this.cleanBatchSize = batchStrategy instanceof BatchStrategies.Scan scan ? scan.batchSize()
708+
this.clearBatchSize = batchStrategy instanceof BatchStrategies.Scan scan ? scan.batchSize()
708709
: DEFAULT_SCAN_BATCH_SIZE;
709710
}
710711

@@ -765,14 +766,14 @@ public CompletableFuture<Void> remove(String name, byte[] key) {
765766
}
766767

767768
@Override
768-
public CompletableFuture<Long> clean(String name, byte[] pattern, BatchStrategy batchStrategy) {
769+
public CompletableFuture<Long> clear(String name, byte[] pattern, BatchStrategy batchStrategy) {
769770

770771
return doWithConnection(connection -> {
771-
return doWithLocking(name, pattern, null, connection, () -> doClean(pattern, connection));
772+
return doWithLocking(name, pattern, null, connection, () -> doClear(pattern, connection));
772773
});
773774
}
774775

775-
private Mono<Long> doClean(byte[] pattern, ReactiveRedisConnection connection) {
776+
private Mono<Long> doClear(byte[] pattern, ReactiveRedisConnection connection) {
776777

777778
ReactiveKeyCommands commands = connection.keyCommands();
778779

@@ -781,11 +782,11 @@ private Mono<Long> doClean(byte[] pattern, ReactiveRedisConnection connection) {
781782
if (batchStrategy instanceof BatchStrategies.Keys) {
782783
keys = commands.keys(ByteBuffer.wrap(pattern)).flatMapMany(Flux::fromIterable);
783784
} else {
784-
keys = commands.scan(ScanOptions.scanOptions().count(cleanBatchSize).match(pattern).build());
785+
keys = commands.scan(ScanOptions.scanOptions().count(clearBatchSize).match(pattern).build());
785786
}
786787

787788
return keys
788-
.buffer(cleanBatchSize) //
789+
.buffer(clearBatchSize) //
789790
.flatMap(commands::mUnlink) //
790791
.collect(Collectors.summingLong(Long::longValue));
791792
}

‎src/main/java/org/springframework/data/redis/cache/RedisCache.java‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,12 +265,12 @@ public void clearStatistics() {
265265

266266
@Override
267267
public void evict(Object key) {
268-
getCacheWriter().remove(getName(), createAndConvertCacheKey(key));
268+
getCacheWriter().evict(getName(), createAndConvertCacheKey(key));
269269
}
270270

271271
@Override
272272
public boolean evictIfPresent(Object key) {
273-
return getCacheWriter().removeIfPresent(getName(), createAndConvertCacheKey(key));
273+
return getCacheWriter().evictIfPresent(getName(), createAndConvertCacheKey(key));
274274
}
275275

276276
@Override

‎src/main/java/org/springframework/data/redis/cache/RedisCacheWriter.java‎

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,24 @@ default CompletableFuture<byte[]> retrieve(String name, byte[] key) {
260260
*
261261
* @param name cache name must not be {@literal null}.
262262
* @param key key for the cache entry. Must not be {@literal null}.
263+
* @deprecated since 4.0 in favor of {@link #evict(String, byte[])}
263264
*/
264-
void remove(String name, byte[] key);
265+
@Deprecated(since = "4.0", forRemoval = true)
266+
default void remove(String name, byte[] key) {
267+
evict(name, key);
268+
}
269+
270+
/**
271+
* Remove the given key from Redis.
272+
* <p>
273+
* Actual eviction may be performed in an asynchronous or deferred fashion, with subsequent lookups possibly still
274+
* seeing the entry.
275+
*
276+
* @param name cache name must not be {@literal null}.
277+
* @param key key for the cache entry. Must not be {@literal null}.
278+
* @since 4.0
279+
*/
280+
void evict(String name, byte[] key);
265281

266282
/**
267283
* Remove the given key from Redis if it is present, expecting the key to be immediately invisible for subsequent
@@ -271,9 +287,10 @@ default CompletableFuture<byte[]> retrieve(String name, byte[] key) {
271287
* @param key key for the cache entry. Must not be {@literal null}.
272288
* @return {@code true} if the cache was known to have a mapping for this key before, {@code false} if it did not (or
273289
* if prior presence could not be determined).
290+
* @since 4.0
274291
*/
275-
default boolean removeIfPresent(String name, byte[] key) {
276-
remove(name, key);
292+
default boolean evictIfPresent(String name, byte[] key) {
293+
evict(name, key);
277294
return false;
278295
}
279296

@@ -285,8 +302,24 @@ default boolean removeIfPresent(String name, byte[] key) {
285302
*
286303
* @param name cache name must not be {@literal null}.
287304
* @param pattern pattern for the keys to remove. Must not be {@literal null}.
305+
* @deprecated since 4.0 in favor of {@link #clear(String, byte[])}
306+
*/
307+
@Deprecated(since = "4.0", forRemoval = true)
308+
default void clean(String name, byte[] pattern) {
309+
clear(name, pattern);
310+
}
311+
312+
/**
313+
* Remove all keys following the given pattern.
314+
* <p>
315+
* Actual clearing may be performed in an asynchronous or deferred fashion, with subsequent lookups possibly still
316+
* seeing the entries.
317+
*
318+
* @param name cache name must not be {@literal null}.
319+
* @param pattern pattern for the keys to remove. Must not be {@literal null}.
320+
* @since 4.0
288321
*/
289-
void clean(String name, byte[] pattern);
322+
void clear(String name, byte[] pattern);
290323

291324
/**
292325
* Remove all keys following the given pattern expecting all entries to be immediately invisible for subsequent
@@ -298,7 +331,7 @@ default boolean removeIfPresent(String name, byte[] key) {
298331
* presence of entries could not be determined).
299332
*/
300333
default boolean invalidate(String name, byte[] pattern) {
301-
clean(name, pattern);
334+
clear(name, pattern);
302335
return false;
303336
}
304337

@@ -379,7 +412,7 @@ default RedisCacheWriterConfigurer enableLocking(Consumer<CacheLockingConfigurat
379412

380413
/**
381414
* Use immediate writes (i.e. write operations such as
382-
* {@link RedisCacheWriter#put(String, byte[], byte[], Duration)} or {@link #clean(String, byte[])}) shall apply
415+
* {@link RedisCacheWriter#put(String, byte[], byte[], Duration)} or {@link #clear(String, byte[])}) shall apply
383416
* immediately.
384417
* <p>
385418
* Several {@link org.springframework.cache.Cache} operations can be performed asynchronously or deferred and this
@@ -395,7 +428,7 @@ default RedisCacheWriterConfigurer immediateWrites() {
395428

396429
/**
397430
* Configure whether to use immediate writes (i.e. write operations such as
398-
* {@link RedisCacheWriter#put(String, byte[], byte[], Duration)} or {@link #clean(String, byte[])}) shall apply
431+
* {@link RedisCacheWriter#put(String, byte[], byte[], Duration)} or {@link #clear(String, byte[])}) shall apply
399432
* immediately.
400433
* <p>
401434
* Several {@link org.springframework.cache.Cache} operations can be performed asynchronously or deferred and this

‎src/test/java/org/springframework/data/redis/cache/DefaultRedisCachWriterUnitTests.java‎

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,22 @@
1919
import static org.mockito.ArgumentMatchers.*;
2020
import static org.mockito.Mockito.*;
2121

22+
23+
import reactor.core.publisher.Mono;
24+
25+
import java.nio.ByteBuffer;
2226
import java.time.Duration;
2327

2428
import org.junit.jupiter.api.BeforeEach;
2529
import org.junit.jupiter.api.Test;
2630
import org.junit.jupiter.api.extension.ExtendWith;
2731
import org.mockito.Mock;
2832
import org.mockito.junit.jupiter.MockitoExtension;
29-
33+
importorg.mockito.quality.Strictness;
3034
import org.springframework.dao.PessimisticLockingFailureException;
35+
import org.springframework.data.redis.connection.ReactiveRedisConnection;
36+
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
37+
import org.springframework.data.redis.connection.ReactiveStringCommands;
3138
import org.springframework.data.redis.connection.RedisConnection;
3239
import org.springframework.data.redis.connection.RedisConnectionFactory;
3340
import org.springframework.data.redis.connection.RedisKeyCommands;
@@ -127,4 +134,62 @@ void mustNotUnlockWhenLockingFails() {
127134

128135
verify(mockKeyCommands, never()).del(any());
129136
}
137+
138+
@Test // GH-3236
139+
void usesAsyncPutIfPossible() {
140+
141+
byte[] key = "TestKey".getBytes();
142+
byte[] value = "TestValue".getBytes();
143+
144+
RedisConnectionFactory connectionFactory = mock(RedisConnectionFactory.class,
145+
withSettings().extraInterfaces(ReactiveRedisConnectionFactory.class));
146+
ReactiveRedisConnection mockConnection = mock(ReactiveRedisConnection.class);
147+
ReactiveStringCommands mockStringCommands = mock(ReactiveStringCommands.class);
148+
149+
doReturn(mockConnection).when((ReactiveRedisConnectionFactory) connectionFactory).getReactiveConnection();
150+
doReturn(mockStringCommands).when(mockConnection).stringCommands();
151+
doReturn(Mono.just(value)).when(mockStringCommands).set(any(), any(), any(), any());
152+
153+
RedisCacheWriter cacheWriter = RedisCacheWriter.create(connectionFactory, cfg -> {
154+
cfg.immediateWrites(false);
155+
});
156+
157+
cacheWriter.put("TestCache", key, value, null);
158+
159+
verify(mockConnection, times(1)).stringCommands();
160+
verify(mockStringCommands, times(1)).set(eq(ByteBuffer.wrap(key)), any());
161+
}
162+
163+
@Test // GH-3236
164+
void usesBlockingWritesIfConfiguredWithImmediateWritesEnabled() {
165+
166+
byte[] key = "TestKey".getBytes();
167+
byte[] value = "TestValue".getBytes();
168+
169+
RedisConnectionFactory connectionFactory = mock(RedisConnectionFactory.class,
170+
withSettings().strictness(Strictness.LENIENT).extraInterfaces(ReactiveRedisConnectionFactory.class));
171+
ReactiveRedisConnection reactiveMockConnection = mock(ReactiveRedisConnection.class,
172+
withSettings().strictness(Strictness.LENIENT));
173+
ReactiveStringCommands reactiveMockStringCommands = mock(ReactiveStringCommands.class,
174+
withSettings().strictness(Strictness.LENIENT));
175+
176+
doReturn(reactiveMockConnection).when((ReactiveRedisConnectionFactory) connectionFactory).getReactiveConnection();
177+
doReturn(reactiveMockStringCommands).when(reactiveMockConnection).stringCommands();
178+
179+
RedisStringCommands mockStringCommands = mock(RedisStringCommands.class);
180+
181+
doReturn(mockStringCommands).when(this.mockConnection).stringCommands();
182+
doReturn(this.mockConnection).when(connectionFactory).getConnection();
183+
184+
RedisCacheWriter cacheWriter = RedisCacheWriter.create(connectionFactory, cfg -> {
185+
cfg.immediateWrites(true);
186+
});
187+
188+
cacheWriter.put("TestCache", key, value, null);
189+
190+
verify(this.mockConnection, times(1)).stringCommands();
191+
verify(mockStringCommands, times(1)).set(eq(key), any());
192+
verify(reactiveMockConnection, never()).stringCommands();
193+
verify(reactiveMockStringCommands, never()).set(eq(ByteBuffer.wrap(key)), any());
194+
}
130195
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /