-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add support for GETEX in Spring Redis Cache #2643
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,7 @@ | |
* @author Christoph Strobl | ||
* @author Mark Paluch | ||
* @author André Prata | ||
* @author Shyngys Sapraliyev | ||
* @since 2.0 | ||
*/ | ||
class DefaultRedisCacheWriter implements RedisCacheWriter { | ||
|
@@ -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!"); | ||
|
@@ -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); | ||
} | ||
Comment on lines
105
to
+112
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As @mp911de alluded to above, there is technically only 1 expiration policy in Redis for a given key: TTL. Expiration (and specifically, TTL) is something that is already handled in Spring Data Redis as of Plus, what happens when TTL is less than TTI? The lesser of TTL and TTI should take precedence. (???) Also note, as of Spring Data Redis There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Technically, TTI expiration policies (e.g. timeouts) have no bearing on cache entry creates or updates (upserts). TTL expiration is only updated when another create or update occurs after the initial create. Read access (e.g. This would apply to |
||
} | ||
|
||
return "OK"; | ||
|
@@ -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))); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The lesser of TTL and TTI should take precedence. |
||
} else { | ||
result = execute(name, connection -> connection.get(key)); | ||
} | ||
|
||
statistics.incGets(name); | ||
|
||
|
@@ -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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change doesn't make sense because there can be only one TTL and instead of changing public API, we rather should apply maxIdle defaulting on the calling side. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this signature change makes any sense in any of the changed I'd prefer, if we decide to add any option to configure TTI (overriding TTL when TTI < TTL on |
||
|
||
Assert.notNull(name, "Name must not be null!"); | ||
Assert.notNull(key, "Key must not be null!"); | ||
|
@@ -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()); | ||
Comment on lines
163
to
+167
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The lesser of TTL and TTI should take precedence. |
||
} else { | ||
put = connection.setNX(key, value); | ||
} | ||
} | ||
|
||
if (put) { | ||
|
@@ -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); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change doesn't make sense because there can be only one TTL and instead of changing public API, we rather should apply maxIdle defaulting on the calling side.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additionally, "
maxIdle
" is a misnomer in this case and does not accurately reflect the behavior of "idle" data access in general and idle-timeout expiration (TTL) policies in particular. See my comment in Issue #2351.