From 8fc04158d8d1ca0d3c4b426dc1b2955ef6b8a1ad Mon Sep 17 00:00:00 2001 From: Nikita Koksharov Date: Wed, 27 Nov 2024 15:45:19 +0300 Subject: [PATCH] Added getLocalCachedMapCache method --- .../src/main/java/org/redisson/Redisson.java | 10 + .../api/LocalCachedMapCacheOptions.java | 431 ++++++++++++++++++ .../redisson/api/RLocalCachedMapCache.java | 38 ++ .../java/org/redisson/api/RedissonClient.java | 27 +- 4 files changed, 505 insertions(+), 1 deletion(-) create mode 100644 redisson/src/main/java/org/redisson/api/LocalCachedMapCacheOptions.java create mode 100644 redisson/src/main/java/org/redisson/api/RLocalCachedMapCache.java diff --git a/redisson/src/main/java/org/redisson/Redisson.java b/redisson/src/main/java/org/redisson/Redisson.java index 65e981212..a87b3cb6b 100755 --- a/redisson/src/main/java/org/redisson/Redisson.java +++ b/redisson/src/main/java/org/redisson/Redisson.java @@ -343,6 +343,16 @@ public final class Redisson implements RedissonClient { return new RedissonListMultimap<>(params.getCodec(), commandExecutor.copy(params), params.getName()); } + @Override + public RLocalCachedMapCache getLocalCachedMapCache(String name, LocalCachedMapCacheOptions options) { + throw new UnsupportedOperationException("This feature is implemented in the Redisson PRO version -> https://redisson.pro"); + } + + @Override + public RLocalCachedMapCache getLocalCachedMapCache(String name, Codec codec, LocalCachedMapCacheOptions options) { + throw new UnsupportedOperationException("This feature is implemented in the Redisson PRO version -> https://redisson.pro"); + } + @Override public RLocalCachedMap getLocalCachedMap(String name, LocalCachedMapOptions options) { return getLocalCachedMap(name, null, options); diff --git a/redisson/src/main/java/org/redisson/api/LocalCachedMapCacheOptions.java b/redisson/src/main/java/org/redisson/api/LocalCachedMapCacheOptions.java new file mode 100644 index 000000000..6c20b6caf --- /dev/null +++ b/redisson/src/main/java/org/redisson/api/LocalCachedMapCacheOptions.java @@ -0,0 +1,431 @@ +/** + * Copyright (c) 2013-2024 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.redisson.api; + +import org.redisson.api.map.MapLoader; +import org.redisson.api.map.MapLoaderAsync; +import org.redisson.api.map.MapWriter; +import org.redisson.api.map.MapWriterAsync; + +import java.util.concurrent.TimeUnit; + +/** + * Configuration for LocalCachedMapCache object. + * + * @author Nikita Koksharov + * + * @param key type + * @param value type + */ +public class LocalCachedMapCacheOptions extends MapCacheOptions { + + /** + * Various strategies to avoid stale objects in local cache. + * Handle cases when map instance has been disconnected for a while. + * + */ + public enum ReconnectionStrategy { + + /** + * No reconnect handling. + */ + NONE, + + /** + * Clear local cache if map instance disconnected. + */ + CLEAR, + + /** + * Store invalidated entry hash in invalidation log for 10 minutes. + * Cache keys for stored invalidated entry hashes will be removed + * if LocalCachedMap instance has been disconnected less than 10 minutes + * or whole local cache will be cleaned otherwise. + */ + LOAD + + } + + public enum SyncStrategy { + + /** + * No synchronizations on map changes. + */ + NONE, + + /** + * Invalidate local cache entry across all LocalCachedMap instances on map entry change. Broadcasts map entry hash (16 bytes) to all instances. + */ + INVALIDATE, + + /** + * Update local cache entry across all LocalCachedMap instances on map entry change. Broadcasts full map entry state (Key and Value objects) to all instances. + */ + UPDATE + + } + + public enum EvictionPolicy { + + /** + * Local cache without eviction. + */ + NONE, + + /** + * Least Recently Used local cache eviction policy. + */ + LRU, + + /** + * Least Frequently Used local cache eviction policy. + */ + LFU, + + /** + * Local cache eviction policy with Soft Reference used for values. + * All references will be collected by GC + */ + SOFT, + + /** + * Local cache eviction policy with Weak Reference used for values. + * All references will be collected by GC + */ + WEAK + }; + + public enum CacheProvider { + + REDISSON, + + CAFFEINE + + } + + public enum StoreMode { + + /** + * Store data only in local cache. + */ + LOCALCACHE, + + /** + * Store data only in both Redis and local cache. + */ + LOCALCACHE_REDIS + + } + + private ReconnectionStrategy reconnectionStrategy; + private SyncStrategy syncStrategy; + private EvictionPolicy evictionPolicy; + private int cacheSize; + private long timeToLiveInMillis; + private long maxIdleInMillis; + private CacheProvider cacheProvider; + private StoreMode storeMode; + private boolean storeCacheMiss; + private boolean useKeyEventsPattern; + + protected LocalCachedMapCacheOptions() { + } + + protected LocalCachedMapCacheOptions(LocalCachedMapCacheOptions copy) { + this.reconnectionStrategy = copy.reconnectionStrategy; + this.syncStrategy = copy.syncStrategy; + this.evictionPolicy = copy.evictionPolicy; + this.cacheSize = copy.cacheSize; + this.timeToLiveInMillis = copy.timeToLiveInMillis; + this.maxIdleInMillis = copy.maxIdleInMillis; + this.cacheProvider = copy.cacheProvider; + this.storeMode = copy.storeMode; + this.storeCacheMiss = copy.storeCacheMiss; + } + + /** + * Creates a new instance of LocalCachedMapOptions with default options. + *

+ * This is equivalent to: + *

+     *     new LocalCachedMapOptions()
+     *      .cacheSize(0).timeToLive(0).maxIdle(0)
+     *      .evictionPolicy(EvictionPolicy.NONE)
+     *      .reconnectionStrategy(ReconnectionStrategy.NONE)
+     *      .cacheProvider(CacheProvider.REDISSON)
+     *      .syncStrategy(SyncStrategy.INVALIDATE)
+     *      .storeCacheMiss(false);
+     * 
+ * + * @param key type + * @param value type + * + * @return LocalCachedMapOptions instance + * + */ + public static LocalCachedMapCacheOptions defaults() { + return new LocalCachedMapCacheOptions() + .cacheSize(0).timeToLive(0).maxIdle(0) + .evictionPolicy(EvictionPolicy.NONE) + .reconnectionStrategy(ReconnectionStrategy.NONE) + .cacheProvider(CacheProvider.REDISSON) + .storeMode(StoreMode.LOCALCACHE_REDIS) + .syncStrategy(SyncStrategy.INVALIDATE) + .storeCacheMiss(false) + .useKeyEventsPattern(true); + } + + public CacheProvider getCacheProvider() { + return cacheProvider; + } + + public EvictionPolicy getEvictionPolicy() { + return evictionPolicy; + } + + public int getCacheSize() { + return cacheSize; + } + + public long getTimeToLiveInMillis() { + return timeToLiveInMillis; + } + + public long getMaxIdleInMillis() { + return maxIdleInMillis; + } + + /** + * Defines local cache size. + *

+ * If size is 0 then local cache is unbounded. + *

+ * If size is -1 then local cache is always empty and doesn't store data. + * + * @param cacheSize size of cache + * @return LocalCachedMapOptions instance + */ + public LocalCachedMapCacheOptions cacheSize(int cacheSize) { + this.cacheSize = cacheSize; + return this; + } + + public ReconnectionStrategy getReconnectionStrategy() { + return reconnectionStrategy; + } + + public SyncStrategy getSyncStrategy() { + return syncStrategy; + } + + /** + * Defines strategy for load missed local cache updates after Redis connection failure. + * + * @param reconnectionStrategy + *

CLEAR - clear local cache if map instance has been disconnected for a while. + *

LOAD - store invalidated entry hash in invalidation log for 10 minutes. Cache keys for stored invalidated entry hashes will be removed if LocalCachedMap instance has been disconnected less than 10 minutes or whole cache will be cleaned otherwise + *

NONE - Default. No reconnection handling + * @return LocalCachedMapOptions instance + */ + public LocalCachedMapCacheOptions reconnectionStrategy(ReconnectionStrategy reconnectionStrategy) { + if (reconnectionStrategy == null) { + throw new NullPointerException("reconnectionStrategy can't be null"); + } + + this.reconnectionStrategy = reconnectionStrategy; + return this; + } + + /** + * Defines local cache synchronization strategy. + * + * @param syncStrategy + *

INVALIDATE - Default. Invalidate cache entry across all LocalCachedMap instances on map entry change + *

UPDATE - Insert/update cache entry across all LocalCachedMap instances on map entry change + *

NONE - No synchronizations on map changes + * @return LocalCachedMapOptions instance + */ + public LocalCachedMapCacheOptions syncStrategy(SyncStrategy syncStrategy) { + if (syncStrategy == null) { + throw new NullPointerException("syncStrategy can't be null"); + } + + this.syncStrategy = syncStrategy; + return this; + } + + /** + * Defines local cache eviction policy. + * + * @param evictionPolicy + *

LRU - uses local cache with LRU (least recently used) eviction policy. + *

LFU - uses local cache with LFU (least frequently used) eviction policy. + *

SOFT - uses local cache with soft references. The garbage collector will evict items from the local cache when the JVM is running out of memory. + *

WEAK - uses local cache with weak references. The garbage collector will evict items from the local cache when it became weakly reachable. + *

NONE - doesn't use eviction policy, but timeToLive and maxIdleTime params are still working. + * @return LocalCachedMapOptions instance + */ + public LocalCachedMapCacheOptions evictionPolicy(EvictionPolicy evictionPolicy) { + if (evictionPolicy == null) { + throw new NullPointerException("evictionPolicy can't be null"); + } + this.evictionPolicy = evictionPolicy; + return this; + } + + /** + * Defines time to live in milliseconds of each map entry in local cache. + * If value equals to 0 then timeout is not applied + * + * @param timeToLiveInMillis - time to live in milliseconds + * @return LocalCachedMapOptions instance + */ + public LocalCachedMapCacheOptions timeToLive(long timeToLiveInMillis) { + this.timeToLiveInMillis = timeToLiveInMillis; + return this; + } + + /** + * Defines time to live of each map entry in local cache. + * If value equals to 0 then timeout is not applied + * + * @param timeToLive - time to live + * @param timeUnit - time unit + * @return LocalCachedMapOptions instance + */ + public LocalCachedMapCacheOptions timeToLive(long timeToLive, TimeUnit timeUnit) { + return timeToLive(timeUnit.toMillis(timeToLive)); + } + + /** + * Defines max idle time in milliseconds of each map entry in local cache. + * If value equals to 0 then timeout is not applied + * + * @param maxIdleInMillis - time to live in milliseconds + * @return LocalCachedMapOptions instance + */ + public LocalCachedMapCacheOptions maxIdle(long maxIdleInMillis) { + this.maxIdleInMillis = maxIdleInMillis; + return this; + } + + /** + * Defines max idle time of each map entry in local cache. + * If value equals to 0 then timeout is not applied + * + * @param maxIdle - max idle time + * @param timeUnit - time unit + * @return LocalCachedMapOptions instance + */ + public LocalCachedMapCacheOptions maxIdle(long maxIdle, TimeUnit timeUnit) { + return maxIdle(timeUnit.toMillis(maxIdle)); + } + + public StoreMode getStoreMode() { + return storeMode; + } + + /** + * Defines store mode of cache data. + * + * @param storeMode + *

LOCALCACHE - store data in local cache only. + *

LOCALCACHE_REDIS - store data in both Redis and local cache. + * @return LocalCachedMapOptions instance + */ + public LocalCachedMapCacheOptions storeMode(StoreMode storeMode) { + this.storeMode = storeMode; + return this; + } + + /** + * Defines Cache provider used as local cache store. + * + * @param cacheProvider + *

REDISSON - uses Redisson own implementation. + *

CAFFEINE - uses Caffeine implementation. + * @return LocalCachedMapOptions instance + */ + public LocalCachedMapCacheOptions cacheProvider(CacheProvider cacheProvider) { + this.cacheProvider = cacheProvider; + return this; + } + + public boolean isStoreCacheMiss() { + return this.storeCacheMiss; + } + + /** + * Defines whether to store a cache miss into the local cache. + * + * @param storeCacheMiss - whether to store a cache miss into the local cache + * @return LocalCachedMapOptions instance + */ + public LocalCachedMapCacheOptions storeCacheMiss(boolean storeCacheMiss) { + this.storeCacheMiss = storeCacheMiss; + return this; + } + + public boolean isUseKeyEventsPattern() { + return useKeyEventsPattern; + } + + /** + * Defines whether to use __keyevent pattern topic to listen for expired events. + * + * @param useKeyEventsPattern - whether to use __keyevent pattern topic + * @return LocalCachedMapOptions instance + */ + public LocalCachedMapCacheOptions useKeyEventsPattern(boolean useKeyEventsPattern) { + this.useKeyEventsPattern = useKeyEventsPattern; + return this; + } + + @Override + public LocalCachedMapCacheOptions writeBehindBatchSize(int writeBehindBatchSize) { + return (LocalCachedMapCacheOptions) super.writeBehindBatchSize(writeBehindBatchSize); + } + + @Override + public LocalCachedMapCacheOptions writeBehindDelay(int writeBehindDelay) { + return (LocalCachedMapCacheOptions) super.writeBehindDelay(writeBehindDelay); + } + + @Override + public LocalCachedMapCacheOptions writer(MapWriter writer) { + return (LocalCachedMapCacheOptions) super.writer(writer); + } + + @Override + public LocalCachedMapCacheOptions writerAsync(MapWriterAsync writer) { + return (LocalCachedMapCacheOptions) super.writerAsync(writer); + } + + @Override + public LocalCachedMapCacheOptions writeMode(WriteMode writeMode) { + return (LocalCachedMapCacheOptions) super.writeMode(writeMode); + } + + @Override + public LocalCachedMapCacheOptions loader(MapLoader loader) { + return (LocalCachedMapCacheOptions) super.loader(loader); + } + + @Override + public LocalCachedMapCacheOptions loaderAsync(MapLoaderAsync loaderAsync) { + return (LocalCachedMapCacheOptions) super.loaderAsync(loaderAsync); + } +} diff --git a/redisson/src/main/java/org/redisson/api/RLocalCachedMapCache.java b/redisson/src/main/java/org/redisson/api/RLocalCachedMapCache.java new file mode 100644 index 000000000..684d80cf3 --- /dev/null +++ b/redisson/src/main/java/org/redisson/api/RLocalCachedMapCache.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2013-2024 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.redisson.api; + +/** + * Map object with entry expiration and local cache support. + *

+ * Each instance maintains local cache to achieve fast read operations. + * Suitable for maps which used mostly for read operations and network roundtrip delays are undesirable. + * + * @author Nikita Koksharov + * + * @param map key + * @param map value + */ +public interface RLocalCachedMapCache extends RMapCache, RLocalCachedMap { + + /** + * Pre-warm the cached values. Not guaranteed to load ALL values, but statistically + * will preload approximately all (all if no concurrent mutating activity) + * Intended for use with no-eviction caches where entire maps are locally cached + */ + void preloadCache(); + +} diff --git a/redisson/src/main/java/org/redisson/api/RedissonClient.java b/redisson/src/main/java/org/redisson/api/RedissonClient.java index e18653065..7427ef112 100755 --- a/redisson/src/main/java/org/redisson/api/RedissonClient.java +++ b/redisson/src/main/java/org/redisson/api/RedissonClient.java @@ -512,7 +512,32 @@ public interface RedissonClient { * @return ListMultimapCache object */ RListMultimapCache getListMultimapCache(PlainOptions options); - + + /** + * Returns local cached map cache instance by name. + * Configured by parameters of options-object. + * + * @param type of key + * @param type of value + * @param name - name of object + * @param options - local map options + * @return LocalCachedMapCache object + */ + RLocalCachedMapCache getLocalCachedMapCache(String name, LocalCachedMapCacheOptions options); + + /** + * Returns local cached map cache instance by name using provided codec. + * Configured by parameters of options-object. + * + * @param type of key + * @param type of value + * @param name - name of object + * @param codec - codec for keys and values + * @param options - local map options + * @return LocalCachedMap object + */ + RLocalCachedMapCache getLocalCachedMapCache(String name, Codec codec, LocalCachedMapCacheOptions options); + /** * Returns List based Multimap instance by name. * Supports key-entry eviction with a given TTL value.