-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
263 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,71 +1,109 @@ | ||
package redis.clients.jedis; | ||
|
||
import java.nio.ByteBuffer; | ||
import java.util.HashMap; | ||
import java.util.Collections; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
import redis.clients.jedis.exceptions.JedisException; | ||
import java.util.Set; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
import java.util.concurrent.locks.Lock; | ||
import java.util.concurrent.locks.ReentrantReadWriteLock; | ||
import java.util.function.Function; | ||
import redis.clients.jedis.util.SafeEncoder; | ||
|
||
public class ClientSideCache { | ||
public abstract class ClientSideCache { | ||
|
||
private final Map<ByteBuffer, Object> cache; | ||
private final Map<ByteBuffer, Set<Long>> keyHashes; // TODO: clean-up | ||
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); | ||
private final Lock readLock = rwl.readLock(); | ||
private final Lock writeLock = rwl.writeLock(); | ||
|
||
public ClientSideCache() { | ||
this.cache = new HashMap<>(); | ||
protected ClientSideCache() { | ||
this.keyHashes = new ConcurrentHashMap<>(); | ||
} | ||
|
||
/** | ||
* For testing purpose only. | ||
* @param map | ||
*/ | ||
ClientSideCache(Map<ByteBuffer, Object> map) { | ||
this.cache = map; | ||
protected ClientSideCache(Map<ByteBuffer, Set<Long>> keyHashes) { | ||
this.keyHashes = keyHashes; | ||
} | ||
|
||
public final void clear() { | ||
cache.clear(); | ||
} | ||
public abstract void invalidateAll(); | ||
|
||
protected abstract void invalidateAll(Iterable<Long> hashes); | ||
|
||
protected abstract void put(long hash, Object value); | ||
|
||
public final void invalidateKeys(List list) { | ||
protected abstract Object get(long hash); | ||
|
||
final void invalidate(List list) { | ||
if (list == null) { | ||
clear(); | ||
invalidateAll(); | ||
return; | ||
} | ||
|
||
list.forEach(this::invalidateKey); | ||
Set<Long> hashes = new HashSet<>(); | ||
list.forEach(key -> hashes.addAll(getHashes(key))); | ||
invalidateAll(hashes); | ||
// TODO: clean-up keyHashes | ||
} | ||
|
||
private void invalidateKey(Object key) { | ||
if (key instanceof byte[]) { | ||
cache.remove(convertKey((byte[]) key)); | ||
} else { | ||
throw new JedisException("" + key.getClass().getSimpleName() + " is not supported. Value: " + String.valueOf(key)); | ||
private Set<Long> getHashes(Object key) { | ||
if (!(key instanceof byte[])) { | ||
throw new AssertionError("" + key.getClass().getSimpleName() + " is not supported. Value: " + String.valueOf(key)); | ||
} | ||
} | ||
|
||
protected void setKey(Object key, Object value) { | ||
cache.put(getMapKey(key), value); | ||
final ByteBuffer mapKey = makeKey((byte[]) key); | ||
readLock.lock(); | ||
try { | ||
Set<Long> hashes = keyHashes.get(mapKey); | ||
return hashes != null ? hashes : Collections.emptySet(); | ||
} finally { | ||
readLock.unlock(); | ||
} | ||
} | ||
|
||
protected <T> T getValue(Object key) { | ||
return (T) getMapValue(key); | ||
final <T> T getValue(Function<CommandObject<T>, T> loader, CommandObject<T> command, String... keys) { | ||
|
||
final long hash = getHash(command); | ||
|
||
T value = (T) get(hash); | ||
if (value != null) { | ||
return value; | ||
} | ||
|
||
value = loader.apply(command); | ||
if (value != null) { | ||
writeLock.lock(); | ||
try { | ||
put(hash, value); | ||
for (String key : keys) { | ||
ByteBuffer mapKey = makeKey(key); | ||
if (keyHashes.containsKey(mapKey)) { | ||
keyHashes.get(mapKey).add(hash); | ||
} else { | ||
Set<Long> set = new HashSet<>(); | ||
set.add(hash); | ||
keyHashes.put(mapKey, set); | ||
} | ||
} | ||
} finally { | ||
writeLock.unlock(); | ||
} | ||
} | ||
|
||
return value; | ||
} | ||
|
||
private Object getMapValue(Object key) { | ||
return cache.get(getMapKey(key)); | ||
private long getHash(CommandObject command) { | ||
// TODO: | ||
return 0; | ||
} | ||
|
||
private ByteBuffer getMapKey(Object key) { | ||
if (key instanceof byte[]) { | ||
return convertKey((byte[]) key); | ||
} else { | ||
return convertKey(SafeEncoder.encode(String.valueOf(key))); | ||
} | ||
private ByteBuffer makeKey(String key) { | ||
return makeKey(SafeEncoder.encode(key)); | ||
} | ||
|
||
private static ByteBuffer convertKey(byte[] b) { | ||
private static ByteBuffer makeKey(byte[] b) { | ||
return ByteBuffer.wrap(b); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package redis.clients.jedis.util; | ||
|
||
import com.github.benmanes.caffeine.cache.Cache; | ||
import com.github.benmanes.caffeine.cache.Caffeine; | ||
import java.util.concurrent.TimeUnit; | ||
import redis.clients.jedis.ClientSideCache; | ||
|
||
public class CaffeineCSC extends ClientSideCache { | ||
|
||
private static final int DEFAULT_MAXIMUM_SIZE = 10_000; | ||
|
||
private final Cache<Long, Object> cache; | ||
|
||
public CaffeineCSC() { | ||
this(DEFAULT_MAXIMUM_SIZE); | ||
} | ||
|
||
public CaffeineCSC(int maximumSize) { | ||
this(Caffeine.newBuilder().maximumSize(maximumSize).build()); | ||
} | ||
|
||
public CaffeineCSC(int maximumSize, int ttlSeconds) { | ||
this(Caffeine.newBuilder().maximumSize(maximumSize) | ||
.expireAfterWrite(ttlSeconds, TimeUnit.SECONDS).build()); | ||
} | ||
|
||
public CaffeineCSC(Cache<Long, Object> caffeineCache) { | ||
this.cache = caffeineCache; | ||
} | ||
|
||
@Override | ||
public final void invalidateAll() { | ||
cache.invalidateAll(); | ||
} | ||
|
||
@Override | ||
protected void invalidateAll(Iterable<Long> hashes) { | ||
cache.invalidateAll(hashes); | ||
} | ||
|
||
@Override | ||
protected void put(long hash, Object value) { | ||
cache.put(hash, value); | ||
} | ||
|
||
@Override | ||
protected Object get(long hash) { | ||
return cache.getIfPresent(hash); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package redis.clients.jedis.util; | ||
|
||
import com.google.common.cache.Cache; | ||
import com.google.common.cache.CacheBuilder; | ||
import java.util.concurrent.TimeUnit; | ||
import redis.clients.jedis.ClientSideCache; | ||
|
||
public class GuavaCSC extends ClientSideCache { | ||
|
||
private static final int DEFAULT_MAXIMUM_SIZE = 10_000; | ||
|
||
private final Cache<Long, Object> cache; | ||
|
||
public GuavaCSC() { | ||
this(DEFAULT_MAXIMUM_SIZE); | ||
} | ||
|
||
public GuavaCSC(int maximumSize) { | ||
this(CacheBuilder.newBuilder().maximumSize(maximumSize).build()); | ||
} | ||
|
||
public GuavaCSC(int maximumSize, int ttlSeconds) { | ||
this(CacheBuilder.newBuilder().maximumSize(maximumSize) | ||
.expireAfterWrite(ttlSeconds, TimeUnit.SECONDS).build()); | ||
} | ||
|
||
public GuavaCSC(Cache<Long, Object> guavaCache) { | ||
this.cache = guavaCache; | ||
} | ||
|
||
@Override | ||
public final void invalidateAll() { | ||
cache.invalidateAll(); | ||
} | ||
|
||
@Override | ||
protected void invalidateAll(Iterable<Long> hashes) { | ||
cache.invalidateAll(hashes); | ||
} | ||
|
||
@Override | ||
protected void put(long hash, Object value) { | ||
cache.put(hash, value); | ||
} | ||
|
||
@Override | ||
protected Object get(long hash) { | ||
return cache.getIfPresent(hash); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.