Feature - support of Caffeine as alternative local cache implementation #2612

pull/2122/merge
Nikita Koksharov 5 years ago
parent b7b780ba20
commit 0dbe2d5db4

@ -237,7 +237,13 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.8.1</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-ion</artifactId>

@ -15,37 +15,14 @@
*/
package org.redisson;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import io.netty.buffer.ByteBuf;
import org.redisson.api.LocalCachedMapOptions;
import org.redisson.api.LocalCachedMapOptions.ReconnectionStrategy;
import org.redisson.api.LocalCachedMapOptions.SyncStrategy;
import org.redisson.api.RFuture;
import org.redisson.api.RLocalCachedMap;
import org.redisson.api.RedissonClient;
import org.redisson.cache.Cache;
import org.redisson.cache.CacheKey;
import org.redisson.cache.CacheValue;
import org.redisson.cache.LocalCacheListener;
import org.redisson.cache.LocalCacheView;
import org.redisson.cache.LocalCachedMapClear;
import org.redisson.cache.LocalCachedMapInvalidate;
import org.redisson.cache.LocalCachedMapUpdate;
import org.redisson.cache.LocalCachedMessageCodec;
import org.redisson.cache.*;
import org.redisson.client.codec.Codec;
import org.redisson.client.codec.LongCodec;
import org.redisson.client.codec.StringCodec;
@ -62,7 +39,11 @@ import org.redisson.misc.Hash;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonPromise;
import io.netty.buffer.ByteBuf;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
@SuppressWarnings("serial")
public class RedissonLocalCachedMap<K, V> extends RedissonMap<K, V> implements RLocalCachedMap<K, V> {
@ -76,7 +57,7 @@ public class RedissonLocalCachedMap<K, V> extends RedissonMap<K, V> implements R
private long cacheUpdateLogTime = TimeUnit.MINUTES.toMillis(10);
private byte[] instanceId;
private Cache<CacheKey, CacheValue> cache;
private Map<CacheKey, CacheValue> cache;
private int invalidateEntryOnChange;
private SyncStrategy syncStrategy;

@ -105,13 +105,22 @@ public class LocalCachedMapOptions<K, V> extends MapOptions<K, V> {
*/
WEAK
};
public enum CacheProvider {
REDISSON,
CAFFEINE
}
private ReconnectionStrategy reconnectionStrategy;
private SyncStrategy syncStrategy;
private EvictionPolicy evictionPolicy;
private int cacheSize;
private long timeToLiveInMillis;
private long maxIdleInMillis;
private CacheProvider cacheProvider;
protected LocalCachedMapOptions() {
}
@ -123,6 +132,7 @@ public class LocalCachedMapOptions<K, V> extends MapOptions<K, V> {
this.cacheSize = copy.cacheSize;
this.timeToLiveInMillis = copy.timeToLiveInMillis;
this.maxIdleInMillis = copy.maxIdleInMillis;
this.cacheProvider = copy.cacheProvider;
}
/**
@ -133,7 +143,9 @@ public class LocalCachedMapOptions<K, V> extends MapOptions<K, V> {
* new LocalCachedMapOptions()
* .cacheSize(0).timeToLive(0).maxIdle(0)
* .evictionPolicy(EvictionPolicy.NONE)
* .invalidateEntryOnChange(true);
* .reconnectionStrategy(ReconnectionStrategy.NONE)
* .cacheProvider(CacheProvider.REDISSON)
* .syncStrategy(SyncStrategy.INVALIDATE);
* </pre>
*
* @param <K> key type
@ -147,9 +159,14 @@ public class LocalCachedMapOptions<K, V> extends MapOptions<K, V> {
.cacheSize(0).timeToLive(0).maxIdle(0)
.evictionPolicy(EvictionPolicy.NONE)
.reconnectionStrategy(ReconnectionStrategy.NONE)
.cacheProvider(CacheProvider.REDISSON)
.syncStrategy(SyncStrategy.INVALIDATE);
}
public CacheProvider getCacheProvider() {
return cacheProvider;
}
public EvictionPolicy getEvictionPolicy() {
return evictionPolicy;
}
@ -167,7 +184,7 @@ public class LocalCachedMapOptions<K, V> extends MapOptions<K, V> {
}
/**
* Sets local cache size. If size is <code>0</code> then local cache is unbounded.
* Defines local cache size. If size is <code>0</code> then local cache is unbounded.
*
* @param cacheSize - size of cache
* @return LocalCachedMapOptions instance
@ -204,12 +221,13 @@ public class LocalCachedMapOptions<K, V> extends MapOptions<K, V> {
}
/**
* Sets eviction policy.
* Defines eviction policy.
*
* @param evictionPolicy
* <p><code>LRU</code> - uses local cache with LRU (least recently used) eviction policy.
* <p><code>LFU</code> - uses local cache with LFU (least frequently used) eviction policy.
* <p><code>SOFT</code> - uses local cache with soft references. The garbage collector will evict items from the local cache when the JVM is running out of memory.
* <p><code>WEAK</code> - uses local cache with weak references. The garbage collector will evict items from the local cache when it became weakly reachable.
* <p><code>NONE</code> - doesn't use eviction policy, but timeToLive and maxIdleTime params are still working.
* @return LocalCachedMapOptions instance
*/
@ -222,7 +240,7 @@ public class LocalCachedMapOptions<K, V> extends MapOptions<K, V> {
}
/**
* Sets time to live in milliseconds for each map entry in local cache.
* Defines time to live in milliseconds of each map entry in local cache.
* If value equals to <code>0</code> then timeout is not applied
*
* @param timeToLiveInMillis - time to live in milliseconds
@ -234,7 +252,7 @@ public class LocalCachedMapOptions<K, V> extends MapOptions<K, V> {
}
/**
* Sets time to live for each map entry in local cache.
* Defines time to live of each map entry in local cache.
* If value equals to <code>0</code> then timeout is not applied
*
* @param timeToLive - time to live
@ -246,7 +264,7 @@ public class LocalCachedMapOptions<K, V> extends MapOptions<K, V> {
}
/**
* Sets max idle time in milliseconds for each map entry in local cache.
* Defines max idle time in milliseconds of each map entry in local cache.
* If value equals to <code>0</code> then timeout is not applied
*
* @param maxIdleInMillis - time to live in milliseconds
@ -258,7 +276,7 @@ public class LocalCachedMapOptions<K, V> extends MapOptions<K, V> {
}
/**
* Sets max idle time for each map entry in local cache.
* Defines max idle time of each map entry in local cache.
* If value equals to <code>0</code> then timeout is not applied
*
* @param maxIdle - max idle time
@ -268,7 +286,20 @@ public class LocalCachedMapOptions<K, V> extends MapOptions<K, V> {
public LocalCachedMapOptions<K, V> maxIdle(long maxIdle, TimeUnit timeUnit) {
return maxIdle(timeUnit.toMillis(maxIdle));
}
/**
* Defines Cache provider used as local cache store.
*
* @param cacheProvider
* <p><code>REDISSON</code> - uses Redisson own implementation.
* <p><code>CAFFEINE</code> - uses Caffeine implementation.
* @return
*/
public LocalCachedMapOptions<K, V> cacheProvider(CacheProvider cacheProvider) {
this.cacheProvider = cacheProvider;
return this;
}
@Override
public LocalCachedMapOptions<K, V> writeBehindBatchSize(int writeBehindBatchSize) {
return (LocalCachedMapOptions<K, V>) super.writeBehindBatchSize(writeBehindBatchSize);

@ -15,32 +15,15 @@
*/
package org.redisson.cache;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import org.redisson.RedissonListMultimapCache;
import org.redisson.RedissonObject;
import org.redisson.RedissonScoredSortedSet;
import org.redisson.RedissonSemaphore;
import org.redisson.RedissonTopic;
import org.redisson.api.LocalCachedMapOptions;
import com.github.benmanes.caffeine.cache.Caffeine;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import org.redisson.*;
import org.redisson.api.*;
import org.redisson.api.LocalCachedMapOptions.EvictionPolicy;
import org.redisson.api.LocalCachedMapOptions.ReconnectionStrategy;
import org.redisson.api.LocalCachedMapOptions.SyncStrategy;
import org.redisson.api.RFuture;
import org.redisson.api.RListMultimapCache;
import org.redisson.api.RObject;
import org.redisson.api.RScoredSortedSet;
import org.redisson.api.RSemaphore;
import org.redisson.api.RTopic;
import org.redisson.api.listener.BaseStatusListener;
import org.redisson.api.listener.MessageListener;
import org.redisson.client.codec.ByteArrayCodec;
@ -51,9 +34,12 @@ import org.redisson.misc.RedissonPromise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
/**
*
@ -72,7 +58,7 @@ public abstract class LocalCacheListener {
private String name;
private CommandAsyncExecutor commandExecutor;
private Cache<?, ?> cache;
private Map<?, ?> cache;
private RObject object;
private byte[] instanceId = new byte[16];
private Codec codec;
@ -107,7 +93,27 @@ public abstract class LocalCacheListener {
return instanceId;
}
public Cache<CacheKey, CacheValue> createCache(LocalCachedMapOptions<?, ?> options) {
public Map<CacheKey, CacheValue> createCache(LocalCachedMapOptions<?, ?> options) {
if (options.getCacheProvider() == LocalCachedMapOptions.CacheProvider.CAFFEINE) {
Caffeine<Object, Object> caffeineBuilder = Caffeine.newBuilder();
if (options.getTimeToLiveInMillis() > 0) {
caffeineBuilder.expireAfterWrite(options.getTimeToLiveInMillis(), TimeUnit.MILLISECONDS);
}
if (options.getMaxIdleInMillis() > 0) {
caffeineBuilder.expireAfterAccess(options.getMaxIdleInMillis(), TimeUnit.MILLISECONDS);
}
if (options.getCacheSize() > 0) {
caffeineBuilder.maximumSize(options.getCacheSize());
}
if (options.getEvictionPolicy() == LocalCachedMapOptions.EvictionPolicy.SOFT) {
caffeineBuilder.softValues();
}
if (options.getEvictionPolicy() == LocalCachedMapOptions.EvictionPolicy.WEAK) {
caffeineBuilder.weakValues();
}
return caffeineBuilder.<CacheKey, CacheValue>build().asMap();
}
if (options.getEvictionPolicy() == EvictionPolicy.NONE) {
return new NoneCacheMap<CacheKey, CacheValue>(options.getTimeToLiveInMillis(), options.getMaxIdleInMillis());
}
@ -130,7 +136,7 @@ public abstract class LocalCacheListener {
return disabledKeys.containsKey(key);
}
public void add(Cache<?, ?> cache) {
public void add(Map<?, ?> cache) {
this.cache = cache;
invalidationTopic = new RedissonTopic(LocalCachedMessageCodec.INSTANCE, commandExecutor, getInvalidationTopicName());

@ -39,9 +39,9 @@ import io.netty.buffer.ByteBuf;
public class LocalCacheView<K, V> {
private final RedissonObject object;
private final Cache<CacheKey, CacheValue> cache;
private final Map<CacheKey, CacheValue> cache;
public LocalCacheView(Cache<CacheKey, CacheValue> cache, RedissonObject object) {
public LocalCacheView(Map<CacheKey, CacheValue> cache, RedissonObject object) {
this.cache = cache;
this.object = object;
}

Loading…
Cancel
Save