Skip to content

Commit fb8615b

Browse files
committed
make caching configured via options, not an explicit wrapper
1 parent fc7ce99 commit fb8615b

File tree

14 files changed

+361
-176
lines changed

14 files changed

+361
-176
lines changed

src/main/asciidoc/index.adoc

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,14 +199,34 @@ To create a client with client-side caching, one would do:
199199
{@link examples.RedisExamples#clientCaching1}
200200
----
201201

202-
The default implementation will use a simple Least-Recently-Used (LFU) cache backed by a `LinkedHashMap`.
203-
You can also provide your own implementation of the cache:
202+
A specific interface, `CachingRedis`, is exposed for a caching client that allows an invalidation handler to be attached or a flush command to be issued.
203+
The invalidation handler will be invoked with all the keys being invalidated whenever a message is received on the invalidations connection.
204+
205+
To attach an invalidations handler:
204206

205207
[source,$lang]
206208
----
207209
{@link examples.RedisExamples#clientCaching2}
208210
----
209211

212+
To manually flush the client's cache store:
213+
214+
[source,$lang]
215+
----
216+
{@link examples.RedisExamples#clientCaching3}
217+
----
218+
219+
The client comes with a default cache store out of the box, but you can write your own if you prefer.
220+
221+
The implementations are expected to follow the `ServiceLoader` conventions and all stores that are available at runtime from the classpath will be exposed.
222+
When more than 1 implementation is available the first one that can be instantiated and configured with success becomes the default.
223+
If none is available, then the default is a simple Least-Recently-Used (LRU) cache backed by a `LinkedHashMap`.
224+
225+
[source,$lang]
226+
----
227+
{@link examples.RedisExamples#clientCaching4}
228+
----
229+
210230
NOTE: The cache is not a write-through cache. A value will not be stored in the client-side cache until the value is fetched from Redis for the first time.
211231
To avoid write-then-read race conditions within the same batch, read commands that are part of a batch will not check the cache first.
212232
Additionally, the current implementation does not support the `OPTIN` or `NOLOOP` options.

src/main/java/examples/RedisExamples.java

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
package examples;
22

3+
import io.vertx.codegen.annotations.Nullable;
34
import io.vertx.core.AbstractVerticle;
45
import io.vertx.core.Future;
56
import io.vertx.core.Promise;
67
import io.vertx.core.Vertx;
78
import io.vertx.core.tracing.TracingPolicy;
89
import io.vertx.redis.client.*;
910

11+
import io.vertx.redis.client.impl.CachingRedis;
12+
import io.vertx.redis.client.impl.CachingRedisClient;
13+
import io.vertx.redis.client.impl.RedisClient;
14+
import io.vertx.redis.client.impl.cache.CacheKey;
15+
import io.vertx.redis.client.spi.RedisClientCache;
16+
import java.util.HashMap;
17+
import java.util.Map;
1018
import java.util.concurrent.atomic.AtomicBoolean;
1119

1220
/**
@@ -248,8 +256,12 @@ public void tracing1(RedisOptions options) {
248256
}
249257

250258
public void clientCaching1(Vertx vertx) {
251-
CachingRedis
252-
.create(vertx)
259+
Redis.createClient(
260+
vertx,
261+
new RedisOptions()
262+
.setCacheEnabled(true)
263+
.setCacheMaxSize(256)
264+
.setCacheMaxAge(60_000))
253265
.connect()
254266
.onSuccess(conn -> {
255267
// get the value for a key, returning from a local in-memory cache if
@@ -259,9 +271,59 @@ public void clientCaching1(Vertx vertx) {
259271
});
260272
}
261273

262-
public void clientCaching2(Vertx vertx, RedisClientCache customCache) {
263-
CachingRedis
264-
.create(vertx, customCache)
274+
public void clientCaching2(Redis redis) {
275+
CachingRedis cachingClient = (CachingRedis) redis;
276+
277+
cachingClient.invalidationHandler(keys -> {
278+
// something...
279+
});
280+
}
281+
282+
public void clientCaching3(Redis redis) {
283+
CachingRedis cachingClient = (CachingRedis) redis;
284+
285+
cachingClient.flush().onSuccess(ignored -> {
286+
// Success!
287+
});
288+
}
289+
290+
public void clientCaching4(Vertx vertx, RedisClientCache customCache) {
291+
292+
// Register this class in META-INF/services/io.vertx.redis.client.spi.RedisClientCache
293+
class CustomCache implements RedisClientCache {
294+
295+
private final Map<CacheKey, Response> store = new HashMap<>();
296+
297+
@Override
298+
public @Nullable Response get(CacheKey key) {
299+
return store.get(key);
300+
}
301+
302+
@Override
303+
public void put(CacheKey key, Response value) {
304+
store.put(key, value);
305+
}
306+
307+
@Override
308+
public void delete(CacheKey key) {
309+
store.remove(key);
310+
}
311+
312+
@Override
313+
public void flush() {
314+
store.clear();
315+
}
316+
317+
@Override
318+
public void close() {
319+
// Nothing to do here
320+
}
321+
}
322+
323+
Redis.createClient(
324+
vertx,
325+
new RedisOptions()
326+
.setCacheEnabled(true))
265327
.connect()
266328
.onSuccess(conn -> {
267329
// get the value for a key, returning from the custom cache if

src/main/java/io/vertx/redis/client/CachingRedis.java

Lines changed: 0 additions & 123 deletions
This file was deleted.

src/main/java/io/vertx/redis/client/CachingRedisOptions.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import io.vertx.core.json.JsonObject;
2020

2121
import java.util.ArrayList;
22+
import java.util.Collection;
2223
import java.util.List;
2324
import java.util.concurrent.TimeUnit;
2425

@@ -36,6 +37,7 @@ public class CachingRedisOptions {
3637
public static final long DEFAULT_MAX_AGE = 3_600_000; // 1 hour in milliseconds
3738
public static final TimeUnit DEFAULT_MAX_AGE_UNIT = TimeUnit.MILLISECONDS;
3839

40+
private boolean enabled;
3941
private int maxCacheSize;
4042
private long maxAge;
4143
private TimeUnit maxAgeUnit;
@@ -46,6 +48,7 @@ public class CachingRedisOptions {
4648
* Creates a default configuration.
4749
*/
4850
public CachingRedisOptions() {
51+
this.enabled = false;
4952
this.maxCacheSize = DEFAULT_MAX_SIZE;
5053
this.maxAge = DEFAULT_MAX_AGE;
5154
this.maxAgeUnit = DEFAULT_MAX_AGE_UNIT;
@@ -59,6 +62,7 @@ public CachingRedisOptions() {
5962
* @param other the options to clone
6063
*/
6164
public CachingRedisOptions(CachingRedisOptions other) {
65+
this.enabled = other.enabled;
6266
this.maxCacheSize = other.maxCacheSize;
6367
this.maxAge = other.maxAge;
6468
this.maxAgeUnit = other.maxAgeUnit;
@@ -76,6 +80,24 @@ public CachingRedisOptions(JsonObject json) {
7680
CachingRedisOptionsConverter.fromJson(json, this);
7781
}
7882

83+
/**
84+
* @return true if caching is enabled
85+
*/
86+
public boolean getEnabled() {
87+
return enabled;
88+
}
89+
90+
/**
91+
* Set if caching is enabled.
92+
*
93+
* @param enabled if caching is enabled
94+
* @return fluent self
95+
*/
96+
public CachingRedisOptions setEnabled(boolean enabled) {
97+
this.enabled = enabled;
98+
return this;
99+
}
100+
79101
/**
80102
* Get the max cache size.
81103
*
@@ -174,7 +196,7 @@ public List<String> getPrefixes() {
174196
* @param prefixes the prefix list
175197
* @return fluent self
176198
*/
177-
public CachingRedisOptions setPrefixes(List<String> prefixes) {
199+
public CachingRedisOptions setPrefixes(Collection<String> prefixes) {
178200
this.prefixes.clear();
179201
this.prefixes.addAll(prefixes);
180202
return this;
@@ -193,7 +215,7 @@ public CachingRedisOptions setPrefix(String prefix) {
193215
}
194216

195217
/**
196-
* Add a prefix teh server should send invalidation messages for.
218+
* Add a prefix the server should send invalidation messages for.
197219
*
198220
* @param prefix the prefix to add
199221
* @return fluent self

src/main/java/io/vertx/redis/client/Redis.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import io.vertx.codegen.annotations.VertxGen;
2020
import io.vertx.core.Future;
2121
import io.vertx.core.Vertx;
22+
import io.vertx.redis.client.impl.CachingRedisClient;
2223
import io.vertx.redis.client.impl.RedisClient;
2324
import io.vertx.redis.client.impl.RedisClusterClient;
2425
import io.vertx.redis.client.impl.RedisReplicationClient;
@@ -62,18 +63,30 @@ static Redis createClient(Vertx vertx, String connectionString) {
6263
* @return the client
6364
*/
6465
static Redis createClient(Vertx vertx, RedisOptions options) {
66+
final Redis clientImpl;
67+
6568
switch (options.getType()) {
6669
case STANDALONE:
67-
return new RedisClient(vertx, options.getNetClientOptions(), options.getPoolOptions(), new RedisStandaloneConnectOptions(options), options.getTracingPolicy());
70+
clientImpl = new RedisClient(vertx, options.getNetClientOptions(), options.getPoolOptions(), new RedisStandaloneConnectOptions(options), options.getTracingPolicy());
71+
break;
6872
case SENTINEL:
69-
return new RedisSentinelClient(vertx, options.getNetClientOptions(), options.getPoolOptions(), new RedisSentinelConnectOptions(options), options.getTracingPolicy());
73+
clientImpl = new RedisSentinelClient(vertx, options.getNetClientOptions(), options.getPoolOptions(), new RedisSentinelConnectOptions(options), options.getTracingPolicy());
74+
break;
7075
case CLUSTER:
71-
return new RedisClusterClient(vertx, options.getNetClientOptions(), options.getPoolOptions(), new RedisClusterConnectOptions(options), options.getTracingPolicy());
76+
clientImpl = new RedisClusterClient(vertx, options.getNetClientOptions(), options.getPoolOptions(), new RedisClusterConnectOptions(options), options.getTracingPolicy());
77+
break;
7278
case REPLICATION:
73-
return new RedisReplicationClient(vertx, options.getNetClientOptions(), options.getPoolOptions(), new RedisClusterConnectOptions(options), options.getTracingPolicy());
79+
clientImpl = new RedisReplicationClient(vertx, options.getNetClientOptions(), options.getPoolOptions(), new RedisClusterConnectOptions(options), options.getTracingPolicy());
80+
break;
7481
default:
7582
throw new IllegalStateException("Unknown Redis Client type: " + options.getType());
7683
}
84+
85+
if (options.getCacheEnabled()) {
86+
return new CachingRedisClient(vertx, clientImpl, options.getCachingOptions());
87+
}
88+
89+
return clientImpl;
7790
}
7891

7992
/**

0 commit comments

Comments
 (0)