Skip to content

Commit

Permalink
#spring-projectsGH-2351 - added maxIdle
Browse files Browse the repository at this point in the history
  • Loading branch information
Shyngys Sapraliyev committed Jul 16, 2023
1 parent 08ed1c4 commit ed43779
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
* @author Christoph Strobl
* @author Mark Paluch
* @author André Prata
* @author Shyngys Sapraliyev
* @since 2.0
*/
class DefaultRedisCacheWriter implements RedisCacheWriter {
Expand Down Expand Up @@ -93,7 +94,7 @@ class DefaultRedisCacheWriter implements RedisCacheWriter {
}

@Override
public void put(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
public void put(String name, byte[] key, byte[] value, @Nullable Duration ttl, @Nullable Duration maxIdle) {

Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
Expand All @@ -104,7 +105,11 @@ public void put(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
if (shouldExpireWithin(ttl)) {
connection.set(key, value, Expiration.from(ttl.toMillis(), TimeUnit.MILLISECONDS), SetOption.upsert());
} else {
connection.set(key, value);
if (shouldExpireMaxIdleWithin(maxIdle)) {
connection.set(key, value, Expiration.from(maxIdle), SetOption.upsert());
} else {
connection.set(key, value);
}
}

return "OK";
Expand All @@ -114,12 +119,18 @@ public void put(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
}

@Override
public byte[] get(String name, byte[] key) {
public byte[] get(String name, byte[] key, @Nullable Duration maxIdle) {

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

byte[] result = execute(name, connection -> connection.get(key));
byte[] result;

if (shouldExpireMaxIdleWithin(maxIdle)) {
result = execute(name, connection -> connection.getEx(key, Expiration.from(maxIdle)));
} else {
result = execute(name, connection -> connection.get(key));
}

statistics.incGets(name);

Expand All @@ -133,7 +144,7 @@ public byte[] get(String name, byte[] key) {
}

@Override
public byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
public byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Duration ttl, @Nullable Duration maxIdle) {

Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
Expand All @@ -152,7 +163,11 @@ public byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Durat
if (shouldExpireWithin(ttl)) {
put = connection.set(key, value, Expiration.from(ttl), SetOption.ifAbsent());
} else {
put = connection.setNX(key, value);
if (shouldExpireMaxIdleWithin(maxIdle)) {
put = connection.set(key, value, Expiration.from(maxIdle), SetOption.ifAbsent());
} else {
put = connection.setNX(key, value);
}
}

if (put) {
Expand Down Expand Up @@ -318,6 +333,10 @@ private static boolean shouldExpireWithin(@Nullable Duration ttl) {
return ttl != null && !ttl.isZero() && !ttl.isNegative();
}

private static boolean shouldExpireMaxIdleWithin(@Nullable Duration maxIdle) {
return maxIdle != null && !maxIdle.isZero() && !maxIdle.isNegative();
}

private static byte[] createCacheLockKey(String name) {
return (name + "~lock").getBytes(StandardCharsets.UTF_8);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
* @author Christoph Strobl
* @author Mark Paluch
* @author Piotr Mionskowski
* @author Shyngys Sapraliyev
* @see RedisCacheConfiguration
* @see RedisCacheWriter
* @since 2.0
Expand Down Expand Up @@ -82,7 +83,7 @@ protected RedisCache(String name, RedisCacheWriter cacheWriter, RedisCacheConfig
@Override
protected Object lookup(Object key) {

byte[] value = cacheWriter.get(name, createAndConvertCacheKey(key));
byte[] value = cacheWriter.get(name, createAndConvertCacheKey(key), cacheConfig.getMaxIdle());

if (value == null) {
return null;
Expand Down Expand Up @@ -145,7 +146,8 @@ public void put(Object key, @Nullable Object value) {
name));
}

cacheWriter.put(name, createAndConvertCacheKey(key), serializeCacheValue(cacheValue), cacheConfig.getTtl());
cacheWriter.put(name, createAndConvertCacheKey(key), serializeCacheValue(cacheValue),
cacheConfig.getTtl(), cacheConfig.getMaxIdle());
}

@Override
Expand All @@ -158,7 +160,7 @@ public ValueWrapper putIfAbsent(Object key, @Nullable Object value) {
}

byte[] result = cacheWriter.putIfAbsent(name, createAndConvertCacheKey(key), serializeCacheValue(cacheValue),
cacheConfig.getTtl());
cacheConfig.getTtl(), cacheConfig.getMaxIdle());

if (result == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,13 @@
*
* @author Christoph Strobl
* @author Mark Paluch
* @author Shyngys Sapraliyev
* @since 2.0
*/
public class RedisCacheConfiguration {

private final Duration ttl;
private final Duration maxIdle;
private final boolean cacheNullValues;
private final CacheKeyPrefix keyPrefix;
private final boolean usePrefix;
Expand All @@ -53,10 +55,11 @@ public class RedisCacheConfiguration {
private final ConversionService conversionService;

@SuppressWarnings("unchecked")
private RedisCacheConfiguration(Duration ttl, Boolean cacheNullValues, Boolean usePrefix, CacheKeyPrefix keyPrefix,
private RedisCacheConfiguration(Duration ttl, Duration maxIdle,
Boolean cacheNullValues, Boolean usePrefix, CacheKeyPrefix keyPrefix,
SerializationPair<String> keySerializationPair, SerializationPair<?> valueSerializationPair,
ConversionService conversionService) {

this.maxIdle = maxIdle;
this.ttl = ttl;
this.cacheNullValues = cacheNullValues;
this.usePrefix = usePrefix;
Expand Down Expand Up @@ -123,8 +126,8 @@ public static RedisCacheConfiguration defaultCacheConfig(@Nullable ClassLoader c

registerDefaultConverters(conversionService);

return new RedisCacheConfiguration(Duration.ZERO, true, true, CacheKeyPrefix.simple(),
SerializationPair.fromSerializer(RedisSerializer.string()),
return new RedisCacheConfiguration(Duration.ZERO, Duration.ZERO, true, true,
CacheKeyPrefix.simple(), SerializationPair.fromSerializer(RedisSerializer.string()),
SerializationPair.fromSerializer(RedisSerializer.java(classLoader)), conversionService);
}

Expand All @@ -138,8 +141,23 @@ public RedisCacheConfiguration entryTtl(Duration ttl) {

Assert.notNull(ttl, "TTL duration must not be null!");

return new RedisCacheConfiguration(ttl, cacheNullValues, usePrefix, keyPrefix, keySerializationPair,
valueSerializationPair, conversionService);
return new RedisCacheConfiguration(ttl, maxIdle, cacheNullValues, usePrefix, keyPrefix,
keySerializationPair, valueSerializationPair, conversionService);
}

/**
* Set the ttl to apply for cache entries on fetch
* Using with {@link Duration#ZERO} will not affect cache entries
*
* @param maxIdle must not be {@literal null}.
* @return new {@link RedisCacheConfiguration}.
*/
public RedisCacheConfiguration maxIdle(Duration maxIdle) {

Assert.notNull(maxIdle, "maxIdle duration must not be null!");

return new RedisCacheConfiguration(ttl, maxIdle, cacheNullValues, usePrefix, keyPrefix,
keySerializationPair, valueSerializationPair, conversionService);
}

/**
Expand Down Expand Up @@ -169,8 +187,8 @@ public RedisCacheConfiguration computePrefixWith(CacheKeyPrefix cacheKeyPrefix)

Assert.notNull(cacheKeyPrefix, "Function for computing prefix must not be null!");

return new RedisCacheConfiguration(ttl, cacheNullValues, true, cacheKeyPrefix, keySerializationPair,
valueSerializationPair, conversionService);
return new RedisCacheConfiguration(ttl, maxIdle, cacheNullValues, true, cacheKeyPrefix,
keySerializationPair, valueSerializationPair, conversionService);
}

/**
Expand All @@ -182,8 +200,8 @@ public RedisCacheConfiguration computePrefixWith(CacheKeyPrefix cacheKeyPrefix)
* @return new {@link RedisCacheConfiguration}.
*/
public RedisCacheConfiguration disableCachingNullValues() {
return new RedisCacheConfiguration(ttl, false, usePrefix, keyPrefix, keySerializationPair, valueSerializationPair,
conversionService);
return new RedisCacheConfiguration(ttl, maxIdle, false, usePrefix, keyPrefix,
keySerializationPair, valueSerializationPair, conversionService);
}

/**
Expand All @@ -195,8 +213,8 @@ public RedisCacheConfiguration disableCachingNullValues() {
*/
public RedisCacheConfiguration disableKeyPrefix() {

return new RedisCacheConfiguration(ttl, cacheNullValues, false, keyPrefix, keySerializationPair,
valueSerializationPair, conversionService);
return new RedisCacheConfiguration(ttl, maxIdle, cacheNullValues, false,
keyPrefix, keySerializationPair, valueSerializationPair, conversionService);
}

/**
Expand All @@ -209,7 +227,7 @@ public RedisCacheConfiguration withConversionService(ConversionService conversio

Assert.notNull(conversionService, "ConversionService must not be null!");

return new RedisCacheConfiguration(ttl, cacheNullValues, usePrefix, keyPrefix, keySerializationPair,
return new RedisCacheConfiguration(ttl, maxIdle, cacheNullValues, usePrefix, keyPrefix, keySerializationPair,
valueSerializationPair, conversionService);
}

Expand All @@ -223,7 +241,7 @@ public RedisCacheConfiguration serializeKeysWith(SerializationPair<String> keySe

Assert.notNull(keySerializationPair, "KeySerializationPair must not be null!");

return new RedisCacheConfiguration(ttl, cacheNullValues, usePrefix, keyPrefix, keySerializationPair,
return new RedisCacheConfiguration(ttl, maxIdle, cacheNullValues, usePrefix, keyPrefix, keySerializationPair,
valueSerializationPair, conversionService);
}

Expand All @@ -237,8 +255,8 @@ public RedisCacheConfiguration serializeValuesWith(SerializationPair<?> valueSer

Assert.notNull(valueSerializationPair, "ValueSerializationPair must not be null!");

return new RedisCacheConfiguration(ttl, cacheNullValues, usePrefix, keyPrefix, keySerializationPair,
valueSerializationPair, conversionService);
return new RedisCacheConfiguration(ttl, maxIdle, cacheNullValues, usePrefix, keyPrefix,
keySerializationPair, valueSerializationPair, conversionService);
}

/**
Expand Down Expand Up @@ -297,6 +315,13 @@ public ConversionService getConversionService() {
return conversionService;
}

/**
* @return The max idle time for cache entries. Never {@literal null}.
*/
public Duration getMaxIdle() {
return maxIdle;
}

/**
* Add a {@link Converter} for extracting the {@link String} representation of a cache key if no suitable
* {@link Object#toString()} method is present.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
*
* @author Christoph Strobl
* @author Mark Paluch
* @author Shyngys Sapraliyev
* @since 2.0
*/
public interface RedisCacheWriter extends CacheStatisticsProvider {
Expand Down Expand Up @@ -96,18 +97,20 @@ static RedisCacheWriter lockingRedisCacheWriter(RedisConnectionFactory connectio
* @param key The key for the cache entry. Must not be {@literal null}.
* @param value The value stored for the key. Must not be {@literal null}.
* @param ttl Optional expiration time. Can be {@literal null}.
* @param maxIdle Optional max idle time. Can be {@literal null}.
*/
void put(String name, byte[] key, byte[] value, @Nullable Duration ttl);
void put(String name, byte[] key, byte[] value, @Nullable Duration ttl, @Nullable Duration maxIdle);

/**
* Get the binary value representation from Redis stored for the given key.
*
* @param name must not be {@literal null}.
* @param key must not be {@literal null}.
* @param maxIdle Optional max idle time. Can be {@literal null}.
* @return {@literal null} if key does not exist.
*/
@Nullable
byte[] get(String name, byte[] key);
byte[] get(String name, byte[] key, @Nullable Duration maxIdle);

/**
* Write the given value to Redis if the key does not already exist.
Expand All @@ -116,10 +119,11 @@ static RedisCacheWriter lockingRedisCacheWriter(RedisConnectionFactory connectio
* @param key The key for the cache entry. Must not be {@literal null}.
* @param value The value stored for the key. Must not be {@literal null}.
* @param ttl Optional expiration time. Can be {@literal null}.
* @param maxIdle Optional max idle time. Can be {@literal null}.
* @return {@literal null} if the value has been written, the value stored for the key if it already exists.
*/
@Nullable
byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Duration ttl);
byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Duration ttl, @Nullable Duration maxIdle);

/**
* Remove the given key from Redis.
Expand Down
Loading

0 comments on commit ed43779

Please sign in to comment.