diff --git a/src/main/java/redis/clients/jedis/CommandArguments.java b/src/main/java/redis/clients/jedis/CommandArguments.java index c630ae76de..b0ebd7fd13 100644 --- a/src/main/java/redis/clients/jedis/CommandArguments.java +++ b/src/main/java/redis/clients/jedis/CommandArguments.java @@ -14,16 +14,14 @@ public class CommandArguments implements Iterable { private final ArrayList args; + private final ArrayList keys; private boolean blocking; - private CommandArguments() { - throw new InstantiationError(); - } - public CommandArguments(ProtocolCommand command) { args = new ArrayList<>(); args.add(command); + keys = new ArrayList<>(); } public ProtocolCommand getCommand() { @@ -115,6 +113,7 @@ public CommandArguments key(Object key) { } else { throw new IllegalArgumentException("\"" + key.toString() + "\" is not a valid argument."); } + keys.add(key); return this; } @@ -134,7 +133,6 @@ public final CommandArguments addParams(IParams params) { } protected CommandArguments processKey(byte[] key) { - // do nothing return this; } @@ -146,7 +144,6 @@ protected final CommandArguments processKeys(byte[]... keys) { } protected CommandArguments processKey(String key) { - // do nothing return this; } @@ -166,6 +163,10 @@ public Iterator iterator() { return args.iterator(); } + public Object[] getKeys() { + return keys.toArray(); + } + public boolean isBlocking() { return blocking; } diff --git a/src/main/java/redis/clients/jedis/Connection.java b/src/main/java/redis/clients/jedis/Connection.java index c7c5f439d4..e0cb9e7ad6 100644 --- a/src/main/java/redis/clients/jedis/Connection.java +++ b/src/main/java/redis/clients/jedis/Connection.java @@ -16,7 +16,6 @@ import redis.clients.jedis.Protocol.Command; import redis.clients.jedis.Protocol.Keyword; import redis.clients.jedis.annots.Experimental; -import redis.clients.jedis.annots.Internal; import redis.clients.jedis.args.ClientAttributeOption; import redis.clients.jedis.args.Rawable; import redis.clients.jedis.commands.ProtocolCommand; @@ -342,24 +341,20 @@ protected void flush() { } @Experimental - @Internal protected Object protocolRead(RedisInputStream is) { return Protocol.read(is); } @Experimental - @Internal protected void protocolReadPushes(RedisInputStream is) { } - // TODO: final protected Object readProtocolWithCheckingBroken() { if (broken) { throw new JedisConnectionException("Attempting to read from a broken connection."); } try { - protocolReadPushes(inputStream); return protocolRead(inputStream); } catch (JedisConnectionException exc) { broken = true; @@ -367,6 +362,24 @@ protected Object readProtocolWithCheckingBroken() { } } + protected void readPushesWithCheckingBroken() { + if (broken) { + throw new JedisConnectionException("Attempting to read from a broken connection."); + } + + try { + if (inputStream.available() > 0) { + protocolReadPushes(inputStream); + } + } catch (IOException e) { + broken = true; + throw new JedisConnectionException("Failed to check buffer on connection.", e); + } catch (JedisConnectionException exc) { + broken = true; + throw exc; + } + } + public List getMany(final int count) { flush(); final List responses = new ArrayList<>(count); @@ -382,6 +395,7 @@ public List getMany(final int count) { /** * Check if the client name libname, libver, characters are legal + * * @param info the name * @return Returns true if legal, false throws exception * @throws JedisException if characters illegal @@ -397,7 +411,7 @@ private static boolean validateClientInfo(String info) { return true; } - private void initializeFromClientConfig(final JedisClientConfig config) { + protected void initializeFromClientConfig(final JedisClientConfig config) { try { connect(); @@ -425,7 +439,8 @@ private void initializeFromClientConfig(final JedisClientConfig config) { } ClientSetInfoConfig setInfoConfig = config.getClientSetInfoConfig(); - if (setInfoConfig == null) setInfoConfig = ClientSetInfoConfig.DEFAULT; + if (setInfoConfig == null) + setInfoConfig = ClientSetInfoConfig.DEFAULT; if (!setInfoConfig.isDisabled()) { String libName = JedisMetaInfo.getArtifactId(); diff --git a/src/main/java/redis/clients/jedis/ConnectionFactory.java b/src/main/java/redis/clients/jedis/ConnectionFactory.java index 722c3e32c8..cc53df56f0 100644 --- a/src/main/java/redis/clients/jedis/ConnectionFactory.java +++ b/src/main/java/redis/clients/jedis/ConnectionFactory.java @@ -7,8 +7,8 @@ import org.slf4j.LoggerFactory; import redis.clients.jedis.annots.Experimental; +import redis.clients.jedis.csc.Cache; import redis.clients.jedis.csc.CacheConnection; -import redis.clients.jedis.csc.ClientSideCache; import redis.clients.jedis.exceptions.JedisException; /** @@ -20,7 +20,7 @@ public class ConnectionFactory implements PooledObjectFactory { private final JedisSocketFactory jedisSocketFactory; private final JedisClientConfig clientConfig; - private ClientSideCache clientSideCache = null; + private Cache clientSideCache = null; public ConnectionFactory(final HostAndPort hostAndPort) { this.clientConfig = DefaultJedisClientConfig.builder().build(); @@ -33,7 +33,7 @@ public ConnectionFactory(final HostAndPort hostAndPort, final JedisClientConfig } @Experimental - public ConnectionFactory(final HostAndPort hostAndPort, final JedisClientConfig clientConfig, ClientSideCache csCache) { + public ConnectionFactory(final HostAndPort hostAndPort, final JedisClientConfig clientConfig, Cache csCache) { this.clientConfig = clientConfig; this.jedisSocketFactory = new DefaultJedisSocketFactory(hostAndPort, this.clientConfig); this.clientSideCache = csCache; diff --git a/src/main/java/redis/clients/jedis/ConnectionPool.java b/src/main/java/redis/clients/jedis/ConnectionPool.java index 49b0fe803d..40d4861f98 100644 --- a/src/main/java/redis/clients/jedis/ConnectionPool.java +++ b/src/main/java/redis/clients/jedis/ConnectionPool.java @@ -3,7 +3,7 @@ import org.apache.commons.pool2.PooledObjectFactory; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import redis.clients.jedis.annots.Experimental; -import redis.clients.jedis.csc.ClientSideCache; +import redis.clients.jedis.csc.Cache; import redis.clients.jedis.util.Pool; public class ConnectionPool extends Pool { @@ -13,7 +13,7 @@ public ConnectionPool(HostAndPort hostAndPort, JedisClientConfig clientConfig) { } @Experimental - public ConnectionPool(HostAndPort hostAndPort, JedisClientConfig clientConfig, ClientSideCache clientSideCache) { + public ConnectionPool(HostAndPort hostAndPort, JedisClientConfig clientConfig, Cache clientSideCache) { this(new ConnectionFactory(hostAndPort, clientConfig, clientSideCache)); } @@ -27,7 +27,7 @@ public ConnectionPool(HostAndPort hostAndPort, JedisClientConfig clientConfig, } @Experimental - public ConnectionPool(HostAndPort hostAndPort, JedisClientConfig clientConfig, ClientSideCache clientSideCache, + public ConnectionPool(HostAndPort hostAndPort, JedisClientConfig clientConfig, Cache clientSideCache, GenericObjectPoolConfig poolConfig) { this(new ConnectionFactory(hostAndPort, clientConfig, clientSideCache), poolConfig); } diff --git a/src/main/java/redis/clients/jedis/DefaultJedisSocketFactory.java b/src/main/java/redis/clients/jedis/DefaultJedisSocketFactory.java index c9ef6646ba..0d41693d0f 100644 --- a/src/main/java/redis/clients/jedis/DefaultJedisSocketFactory.java +++ b/src/main/java/redis/clients/jedis/DefaultJedisSocketFactory.java @@ -94,11 +94,13 @@ public Socket createSocket() throws JedisConnectionException { if (null == _sslSocketFactory) { _sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); } + Socket plainSocket = socket; socket = _sslSocketFactory.createSocket(socket, _hostAndPort.getHost(), _hostAndPort.getPort(), true); if (null != sslParameters) { ((SSLSocket) socket).setSSLParameters(sslParameters); } + socket = new SSLSocketWrapper((SSLSocket) socket, plainSocket); if (null != hostnameVerifier && !hostnameVerifier.verify(_hostAndPort.getHost(), ((SSLSocket) socket).getSession())) { diff --git a/src/main/java/redis/clients/jedis/JedisCluster.java b/src/main/java/redis/clients/jedis/JedisCluster.java index 6646409a24..94e3f561e0 100644 --- a/src/main/java/redis/clients/jedis/JedisCluster.java +++ b/src/main/java/redis/clients/jedis/JedisCluster.java @@ -8,7 +8,7 @@ import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import redis.clients.jedis.annots.Experimental; import redis.clients.jedis.providers.ClusterConnectionProvider; -import redis.clients.jedis.csc.ClientSideCache; +import redis.clients.jedis.csc.Cache; import redis.clients.jedis.util.JedisClusterCRC16; public class JedisCluster extends UnifiedJedis { @@ -218,27 +218,27 @@ private JedisCluster(ClusterConnectionProvider provider, int maxAttempts, Durati } @Experimental - public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, ClientSideCache clientSideCache) { + public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, Cache clientSideCache) { this(clusterNodes, clientConfig, clientSideCache, DEFAULT_MAX_ATTEMPTS, Duration.ofMillis(DEFAULT_MAX_ATTEMPTS * clientConfig.getSocketTimeoutMillis())); } @Experimental - public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, ClientSideCache clientSideCache, + public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, Cache clientSideCache, int maxAttempts, Duration maxTotalRetriesDuration) { this(new ClusterConnectionProvider(clusterNodes, clientConfig, clientSideCache), maxAttempts, maxTotalRetriesDuration, clientConfig.getRedisProtocol(), clientSideCache); } @Experimental - public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, ClientSideCache clientSideCache, + public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, Cache clientSideCache, int maxAttempts, Duration maxTotalRetriesDuration, GenericObjectPoolConfig poolConfig) { this(new ClusterConnectionProvider(clusterNodes, clientConfig, clientSideCache, poolConfig), maxAttempts, maxTotalRetriesDuration, clientConfig.getRedisProtocol(), clientSideCache); } @Experimental - public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, ClientSideCache clientSideCache, + public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, Cache clientSideCache, GenericObjectPoolConfig poolConfig) { this(new ClusterConnectionProvider(clusterNodes, clientConfig, clientSideCache, poolConfig), DEFAULT_MAX_ATTEMPTS, Duration.ofMillis(DEFAULT_MAX_ATTEMPTS * clientConfig.getSocketTimeoutMillis()), @@ -246,7 +246,7 @@ public JedisCluster(Set clusterNodes, JedisClientConfig clientConfi } @Experimental - public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, ClientSideCache clientSideCache, + public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, Cache clientSideCache, GenericObjectPoolConfig poolConfig, Duration topologyRefreshPeriod, int maxAttempts, Duration maxTotalRetriesDuration) { this(new ClusterConnectionProvider(clusterNodes, clientConfig, clientSideCache, poolConfig, topologyRefreshPeriod), @@ -255,7 +255,7 @@ public JedisCluster(Set clusterNodes, JedisClientConfig clientConfi @Experimental private JedisCluster(ClusterConnectionProvider provider, int maxAttempts, Duration maxTotalRetriesDuration, - RedisProtocol protocol, ClientSideCache clientSideCache) { + RedisProtocol protocol, Cache clientSideCache) { super(provider, maxAttempts, maxTotalRetriesDuration, protocol, clientSideCache); } diff --git a/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java b/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java index bc150dbcb0..700f49e272 100644 --- a/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java +++ b/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java @@ -25,7 +25,7 @@ import redis.clients.jedis.annots.Experimental; import redis.clients.jedis.annots.Internal; -import redis.clients.jedis.csc.ClientSideCache; +import redis.clients.jedis.csc.Cache; import redis.clients.jedis.exceptions.JedisClusterOperationException; import redis.clients.jedis.exceptions.JedisException; import redis.clients.jedis.util.SafeEncoder; @@ -48,7 +48,7 @@ public class JedisClusterInfoCache { private final GenericObjectPoolConfig poolConfig; private final JedisClientConfig clientConfig; - private final ClientSideCache clientSideCache; + private final Cache clientSideCache; private final Set startNodes; private static final int MASTER_NODE_INDEX = 2; @@ -72,7 +72,7 @@ public JedisClusterInfoCache(final JedisClientConfig clientConfig, final Set startNodes) { this(clientConfig, clientSideCache, null, startNodes); } @@ -83,7 +83,7 @@ public JedisClusterInfoCache(final JedisClientConfig clientConfig, } @Experimental - public JedisClusterInfoCache(final JedisClientConfig clientConfig, ClientSideCache clientSideCache, + public JedisClusterInfoCache(final JedisClientConfig clientConfig, Cache clientSideCache, final GenericObjectPoolConfig poolConfig, final Set startNodes) { this(clientConfig, clientSideCache, poolConfig, startNodes, null); } @@ -95,7 +95,7 @@ public JedisClusterInfoCache(final JedisClientConfig clientConfig, } @Experimental - public JedisClusterInfoCache(final JedisClientConfig clientConfig, ClientSideCache clientSideCache, + public JedisClusterInfoCache(final JedisClientConfig clientConfig, Cache clientSideCache, final GenericObjectPoolConfig poolConfig, final Set startNodes, final Duration topologyRefreshPeriod) { this.poolConfig = poolConfig; diff --git a/src/main/java/redis/clients/jedis/JedisPooled.java b/src/main/java/redis/clients/jedis/JedisPooled.java index 504141404f..498bcb02c8 100644 --- a/src/main/java/redis/clients/jedis/JedisPooled.java +++ b/src/main/java/redis/clients/jedis/JedisPooled.java @@ -8,7 +8,7 @@ import org.apache.commons.pool2.PooledObjectFactory; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import redis.clients.jedis.annots.Experimental; -import redis.clients.jedis.csc.ClientSideCache; +import redis.clients.jedis.csc.Cache; import redis.clients.jedis.providers.PooledConnectionProvider; import redis.clients.jedis.util.JedisURIHelper; import redis.clients.jedis.util.Pool; @@ -78,7 +78,7 @@ public JedisPooled(final HostAndPort hostAndPort, final JedisClientConfig client } @Experimental - public JedisPooled(final HostAndPort hostAndPort, final JedisClientConfig clientConfig, ClientSideCache clientSideCache) { + public JedisPooled(final HostAndPort hostAndPort, final JedisClientConfig clientConfig, Cache clientSideCache) { super(hostAndPort, clientConfig, clientSideCache); } @@ -383,7 +383,7 @@ public JedisPooled(final HostAndPort hostAndPort, final JedisClientConfig client } @Experimental - public JedisPooled(final HostAndPort hostAndPort, final JedisClientConfig clientConfig, ClientSideCache clientSideCache, + public JedisPooled(final HostAndPort hostAndPort, final JedisClientConfig clientConfig, Cache clientSideCache, final GenericObjectPoolConfig poolConfig) { super(new PooledConnectionProvider(hostAndPort, clientConfig, clientSideCache, poolConfig), clientConfig.getRedisProtocol(), clientSideCache); diff --git a/src/main/java/redis/clients/jedis/JedisSentineled.java b/src/main/java/redis/clients/jedis/JedisSentineled.java index f89764d22c..35585f713f 100644 --- a/src/main/java/redis/clients/jedis/JedisSentineled.java +++ b/src/main/java/redis/clients/jedis/JedisSentineled.java @@ -3,7 +3,7 @@ import java.util.Set; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import redis.clients.jedis.annots.Experimental; -import redis.clients.jedis.csc.ClientSideCache; +import redis.clients.jedis.csc.Cache; import redis.clients.jedis.providers.SentineledConnectionProvider; public class JedisSentineled extends UnifiedJedis { @@ -15,7 +15,7 @@ public JedisSentineled(String masterName, final JedisClientConfig masterClientCo } @Experimental - public JedisSentineled(String masterName, final JedisClientConfig masterClientConfig, ClientSideCache clientSideCache, + public JedisSentineled(String masterName, final JedisClientConfig masterClientConfig, Cache clientSideCache, Set sentinels, final JedisClientConfig sentinelClientConfig) { super(new SentineledConnectionProvider(masterName, masterClientConfig, clientSideCache, sentinels, sentinelClientConfig), masterClientConfig.getRedisProtocol(), clientSideCache); @@ -29,7 +29,7 @@ public JedisSentineled(String masterName, final JedisClientConfig masterClientCo } @Experimental - public JedisSentineled(String masterName, final JedisClientConfig masterClientConfig, ClientSideCache clientSideCache, + public JedisSentineled(String masterName, final JedisClientConfig masterClientConfig, Cache clientSideCache, final GenericObjectPoolConfig poolConfig, Set sentinels, final JedisClientConfig sentinelClientConfig) { super(new SentineledConnectionProvider(masterName, masterClientConfig, clientSideCache, poolConfig, diff --git a/src/main/java/redis/clients/jedis/Protocol.java b/src/main/java/redis/clients/jedis/Protocol.java index c025e37a4a..174fdd142b 100644 --- a/src/main/java/redis/clients/jedis/Protocol.java +++ b/src/main/java/redis/clients/jedis/Protocol.java @@ -12,7 +12,7 @@ import redis.clients.jedis.exceptions.*; import redis.clients.jedis.args.Rawable; import redis.clients.jedis.commands.ProtocolCommand; -import redis.clients.jedis.csc.ClientSideCache; +import redis.clients.jedis.csc.Cache; import redis.clients.jedis.util.KeyValue; import redis.clients.jedis.util.RedisInputStream; import redis.clients.jedis.util.RedisOutputStream; @@ -126,7 +126,7 @@ private static String[] parseTargetHostAndSlot(String clusterRedirectResponse) { private static Object process(final RedisInputStream is) { final byte b = is.readByte(); - //System.out.println("BYTE: " + (char) b); + // System.out.println("BYTE: " + (char) b); switch (b) { case PLUS_BYTE: return is.readLineBytes(); @@ -185,7 +185,8 @@ private static byte[] processBulkReply(final RedisInputStream is) { private static List processMultiBulkReply(final RedisInputStream is) { final int num = is.readIntCrLf(); - if (num == -1) return null; + if (num == -1) + return null; final List ret = new ArrayList<>(num); for (int i = 0; i < num; i++) { try { @@ -199,7 +200,8 @@ private static List processMultiBulkReply(final RedisInputStream is) { private static List processMapKeyValueReply(final RedisInputStream is) { final int num = is.readIntCrLf(); - if (num == -1) return null; + if (num == -1) + return null; final List ret = new ArrayList<>(num); for (int i = 0; i < num; i++) { ret.add(new KeyValue(process(is), process(is))); @@ -212,18 +214,37 @@ public static Object read(final RedisInputStream is) { } @Experimental - public static void readPushes(final RedisInputStream is, final ClientSideCache cache) { - while (is.peek(GREATER_THAN_BYTE)) { - is.readByte(); - processPush(is, cache); + public static Object read(final RedisInputStream is, final Cache cache) { + readPushes(is, cache, false); + return process(is); + } + + @Experimental + public static void readPushes(final RedisInputStream is, final Cache cache, boolean onlyPendingBuffer) { + if (onlyPendingBuffer) { + try { + while (is.available() > 0 && is.peek(GREATER_THAN_BYTE)) { + is.readByte(); + processPush(is, cache); + } + } catch (JedisConnectionException e) { + // TODO handle it properly + } catch (IOException e) { + // TODO handle it properly + } + } else { + while (is.peek(GREATER_THAN_BYTE)) { + is.readByte(); + processPush(is, cache); + } } } - private static void processPush(final RedisInputStream is, ClientSideCache cache) { + private static void processPush(final RedisInputStream is, Cache cache) { List list = processMultiBulkReply(is); if (list.size() == 2 && list.get(0) instanceof byte[] && Arrays.equals(INVALIDATE_BYTES, (byte[]) list.get(0))) { - cache.invalidate((List) list.get(1)); + cache.deleteByRedisKeys((List) list.get(1)); } } diff --git a/src/main/java/redis/clients/jedis/SSLSocketWrapper.java b/src/main/java/redis/clients/jedis/SSLSocketWrapper.java new file mode 100644 index 0000000000..a2b9e5b74c --- /dev/null +++ b/src/main/java/redis/clients/jedis/SSLSocketWrapper.java @@ -0,0 +1,408 @@ +package redis.clients.jedis; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.util.function.BiFunction; +import java.util.List; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; + +public class SSLSocketWrapper extends SSLSocket { + + SSLSocket actual; + Socket underlying; + InputStream wrapper; + + private class InputStreamWrapper extends InputStream { + private InputStream actual; + private InputStream underlying; + + public InputStreamWrapper(InputStream actual, InputStream underlying) { + this.actual = actual; + this.underlying = underlying; + } + + @Override + public int read() throws IOException { + return actual.read(); + } + + @Override + public int read(byte[] b) throws IOException { + return actual.read(b); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + return actual.read(b, off, len); + } + + @Override + public long skip(long n) throws IOException { + return actual.skip(n); + } + + @Override + public int available() throws IOException { + return underlying.available(); + } + + @Override + public void close() throws IOException { + actual.close(); + } + + @Override + public synchronized void mark(int readlimit) { + actual.mark(readlimit); + } + + @Override + public synchronized void reset() throws IOException { + actual.reset(); + } + + @Override + public boolean markSupported() { + return actual.markSupported(); + } + } + + public SSLSocketWrapper(SSLSocket actual, Socket underlying) throws IOException { + this.actual = actual; + this.underlying = underlying; + this.wrapper = new InputStreamWrapper(actual.getInputStream(), underlying.getInputStream()); + } + + @Override + public void connect(SocketAddress endpoint) throws IOException { + actual.connect(endpoint); + } + + @Override + public void connect(SocketAddress endpoint, int timeout) throws IOException { + actual.connect(endpoint, timeout); + } + + @Override + public void bind(SocketAddress bindpoint) throws IOException { + actual.bind(bindpoint); + } + + @Override + public InetAddress getInetAddress() { + return actual.getInetAddress(); + } + + @Override + public InetAddress getLocalAddress() { + return actual.getLocalAddress(); + } + + @Override + public int getPort() { + return actual.getPort(); + } + + @Override + public int getLocalPort() { + return actual.getLocalPort(); + } + + @Override + public SocketAddress getRemoteSocketAddress() { + return actual.getRemoteSocketAddress(); + } + + @Override + public SocketAddress getLocalSocketAddress() { + return actual.getLocalSocketAddress(); + } + + @Override + public void setTcpNoDelay(boolean on) throws SocketException { + actual.setTcpNoDelay(on); + } + + @Override + public boolean getTcpNoDelay() throws SocketException { + return actual.getTcpNoDelay(); + } + + @Override + public void setSoLinger(boolean on, int linger) throws SocketException { + actual.setSoLinger(on, linger); + } + + @Override + public int getSoLinger() throws SocketException { + return actual.getSoLinger(); + } + + @Override + public void sendUrgentData(int data) throws IOException { + actual.sendUrgentData(data); + } + + @Override + public void setOOBInline(boolean on) throws SocketException { + actual.setOOBInline(on); + } + + @Override + public boolean getOOBInline() throws SocketException { + return actual.getOOBInline(); + } + + @Override + public synchronized void setSoTimeout(int timeout) throws SocketException { + actual.setSoTimeout(timeout); + } + + @Override + public synchronized int getSoTimeout() throws SocketException { + return actual.getSoTimeout(); + } + + @Override + public synchronized void setSendBufferSize(int size) throws SocketException { + actual.setSendBufferSize(size); + } + + @Override + public synchronized int getSendBufferSize() throws SocketException { + return actual.getSendBufferSize(); + } + + @Override + public synchronized void setReceiveBufferSize(int size) throws SocketException { + actual.setReceiveBufferSize(size); + } + + @Override + public synchronized int getReceiveBufferSize() throws SocketException { + return actual.getReceiveBufferSize(); + } + + @Override + public void setKeepAlive(boolean on) throws SocketException { + actual.setKeepAlive(on); + } + + @Override + public boolean getKeepAlive() throws SocketException { + return actual.getKeepAlive(); + } + + @Override + public void setTrafficClass(int tc) throws SocketException { + actual.setTrafficClass(tc); + } + + @Override + public int getTrafficClass() throws SocketException { + return actual.getTrafficClass(); + } + + @Override + public void setReuseAddress(boolean on) throws SocketException { + actual.setReuseAddress(on); + } + + @Override + public boolean getReuseAddress() throws SocketException { + return actual.getReuseAddress(); + } + + @Override + public synchronized void close() throws IOException { + actual.close(); + } + + @Override + public void shutdownInput() throws IOException { + actual.shutdownInput(); + } + + @Override + public void shutdownOutput() throws IOException { + actual.shutdownOutput(); + } + + @Override + public String toString() { + return actual.toString(); + } + + @Override + public boolean isConnected() { + return actual.isConnected(); + } + + @Override + public boolean isBound() { + return actual.isBound(); + } + + @Override + public boolean isClosed() { + return actual.isClosed(); + } + + @Override + public boolean isInputShutdown() { + return actual.isInputShutdown(); + } + + @Override + public boolean isOutputShutdown() { + return actual.isOutputShutdown(); + } + + @Override + public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { + actual.setPerformancePreferences(connectionTime, latency, bandwidth); + } + + @Override + public InputStream getInputStream() throws IOException { + return wrapper; + } + + @Override + public OutputStream getOutputStream() throws IOException { + return actual.getOutputStream(); + } + + @Override + public String[] getSupportedCipherSuites() { + return actual.getSupportedCipherSuites(); + } + + @Override + public String[] getEnabledCipherSuites() { + return actual.getEnabledCipherSuites(); + } + + @Override + public void setEnabledCipherSuites(String[] var1) { + actual.setEnabledCipherSuites(var1); + } + + @Override + public String[] getSupportedProtocols() { + return actual.getSupportedProtocols(); + } + + @Override + public String[] getEnabledProtocols() { + return actual.getEnabledProtocols(); + } + + @Override + public void setEnabledProtocols(String[] var1) { + actual.setEnabledProtocols(var1); + } + + @Override + public SSLSession getSession() { + return actual.getSession(); + } + + @Override + public SSLSession getHandshakeSession() { + return actual.getHandshakeSession(); + } + + @Override + public void addHandshakeCompletedListener(HandshakeCompletedListener var1) { + actual.addHandshakeCompletedListener(var1); + } + + @Override + public void removeHandshakeCompletedListener(HandshakeCompletedListener var1) { + actual.removeHandshakeCompletedListener(var1); + } + + @Override + public void startHandshake() throws IOException { + actual.startHandshake(); + } + + @Override + public void setUseClientMode(boolean var1) { + actual.setUseClientMode(var1); + } + + @Override + public boolean getUseClientMode() { + return actual.getUseClientMode(); + } + + @Override + public void setNeedClientAuth(boolean var1) { + actual.setNeedClientAuth(var1); + } + + @Override + public boolean getNeedClientAuth() { + return actual.getNeedClientAuth(); + } + + @Override + public void setWantClientAuth(boolean var1) { + actual.setWantClientAuth(var1); + } + + @Override + public boolean getWantClientAuth() { + return actual.getWantClientAuth(); + } + + @Override + public void setEnableSessionCreation(boolean var1) { + actual.setEnableSessionCreation(var1); + } + + @Override + public boolean getEnableSessionCreation() { + return actual.getEnableSessionCreation(); + } + + @Override + public SSLParameters getSSLParameters() { + return actual.getSSLParameters(); + } + + @Override + public void setSSLParameters(SSLParameters var1) { + actual.setSSLParameters(var1); + } + + @Override + public String getApplicationProtocol() { + return actual.getApplicationProtocol(); + } + + @Override + public String getHandshakeApplicationProtocol() { + return actual.getHandshakeApplicationProtocol(); + } + + @Override + public void setHandshakeApplicationProtocolSelector(BiFunction, String> var1) { + actual.setHandshakeApplicationProtocolSelector(var1); + } + + @Override + public BiFunction, String> getHandshakeApplicationProtocolSelector() { + return actual.getHandshakeApplicationProtocolSelector(); + } +} diff --git a/src/main/java/redis/clients/jedis/UnifiedJedis.java b/src/main/java/redis/clients/jedis/UnifiedJedis.java index 3a2dd9ab3e..405220b83e 100644 --- a/src/main/java/redis/clients/jedis/UnifiedJedis.java +++ b/src/main/java/redis/clients/jedis/UnifiedJedis.java @@ -19,7 +19,7 @@ import redis.clients.jedis.commands.SampleBinaryKeyedCommands; import redis.clients.jedis.commands.SampleKeyedCommands; import redis.clients.jedis.commands.RedisModuleCommands; -import redis.clients.jedis.csc.ClientSideCache; +import redis.clients.jedis.csc.Cache; import redis.clients.jedis.exceptions.JedisException; import redis.clients.jedis.executors.*; import redis.clients.jedis.gears.TFunctionListParams; @@ -51,8 +51,8 @@ public class UnifiedJedis implements JedisCommands, JedisBinaryCommands, SampleKeyedCommands, SampleBinaryKeyedCommands, RedisModuleCommands, AutoCloseable { - @Deprecated protected RedisProtocol protocol = null; - private final ClientSideCache clientSideCache; + @Deprecated + protected RedisProtocol protocol = null; protected final ConnectionProvider provider; protected final CommandExecutor executor; protected final CommandObjects commandObjects; @@ -95,8 +95,9 @@ public UnifiedJedis(HostAndPort hostAndPort, JedisClientConfig clientConfig) { } @Experimental - public UnifiedJedis(HostAndPort hostAndPort, JedisClientConfig clientConfig, ClientSideCache clientSideCache) { - this(new PooledConnectionProvider(hostAndPort, clientConfig, clientSideCache), clientConfig.getRedisProtocol(), clientSideCache); + public UnifiedJedis(HostAndPort hostAndPort, JedisClientConfig clientConfig, Cache clientSideCache) { + this(new PooledConnectionProvider(hostAndPort, clientConfig, clientSideCache), clientConfig.getRedisProtocol(), + clientSideCache); } public UnifiedJedis(ConnectionProvider provider) { @@ -108,7 +109,7 @@ protected UnifiedJedis(ConnectionProvider provider, RedisProtocol protocol) { } @Experimental - protected UnifiedJedis(ConnectionProvider provider, RedisProtocol protocol, ClientSideCache clientSideCache) { + protected UnifiedJedis(ConnectionProvider provider, RedisProtocol protocol, Cache clientSideCache) { this(new DefaultCommandExecutor(provider), provider, new CommandObjects(), protocol, clientSideCache); } @@ -143,14 +144,15 @@ public UnifiedJedis(Connection connection) { this.executor = new SimpleCommandExecutor(connection); this.commandObjects = new CommandObjects(); RedisProtocol proto = connection.getRedisProtocol(); - if (proto != null) this.commandObjects.setProtocol(proto); + if (proto != null) + this.commandObjects.setProtocol(proto); this.graphCommandObjects = new GraphCommandObjects(this); - this.clientSideCache = null; // TODO: } @Deprecated public UnifiedJedis(Set jedisClusterNodes, JedisClientConfig clientConfig, int maxAttempts) { - this(jedisClusterNodes, clientConfig, maxAttempts, Duration.ofMillis(maxAttempts * clientConfig.getSocketTimeoutMillis())); + this(jedisClusterNodes, clientConfig, maxAttempts, + Duration.ofMillis(maxAttempts * clientConfig.getSocketTimeoutMillis())); } @Deprecated @@ -181,7 +183,7 @@ protected UnifiedJedis(ClusterConnectionProvider provider, int maxAttempts, Dura @Experimental protected UnifiedJedis(ClusterConnectionProvider provider, int maxAttempts, Duration maxTotalRetriesDuration, - RedisProtocol protocol, ClientSideCache clientSideCache) { + RedisProtocol protocol, Cache clientSideCache) { this(new ClusterCommandExecutor(provider, maxAttempts, maxTotalRetriesDuration), provider, new ClusterCommandObjects(), protocol, clientSideCache); } @@ -199,7 +201,8 @@ public UnifiedJedis(ShardedConnectionProvider provider) { */ @Deprecated public UnifiedJedis(ShardedConnectionProvider provider, Pattern tagPattern) { - this(new DefaultCommandExecutor(provider), provider, new ShardedCommandObjects(provider.getHashingAlgo(), tagPattern)); + this(new DefaultCommandExecutor(provider), provider, + new ShardedCommandObjects(provider.getHashingAlgo(), tagPattern)); } public UnifiedJedis(ConnectionProvider provider, int maxAttempts, Duration maxTotalRetriesDuration) { @@ -240,21 +243,23 @@ public UnifiedJedis(CommandExecutor executor, ConnectionProvider provider, Comma try (Connection conn = this.provider.getConnection()) { if (conn != null) { RedisProtocol proto = conn.getRedisProtocol(); - if (proto != null) this.commandObjects.setProtocol(proto); + if (proto != null) + this.commandObjects.setProtocol(proto); } - } catch (JedisException je) { } + } catch (JedisException je) { + } } } @Experimental private UnifiedJedis(CommandExecutor executor, ConnectionProvider provider, CommandObjects commandObjects, RedisProtocol protocol) { - this(executor, provider, commandObjects, protocol, (ClientSideCache) null); + this(executor, provider, commandObjects, protocol, (Cache) null); } @Experimental private UnifiedJedis(CommandExecutor executor, ConnectionProvider provider, CommandObjects commandObjects, - RedisProtocol protocol, ClientSideCache clientSideCache) { + RedisProtocol protocol, Cache clientSideCache) { if (clientSideCache != null && protocol != RedisProtocol.RESP3) { throw new IllegalArgumentException("Client-side caching is only supported with RESP3."); @@ -264,12 +269,12 @@ private UnifiedJedis(CommandExecutor executor, ConnectionProvider provider, Comm this.executor = executor; this.commandObjects = commandObjects; - if (protocol != null) this.commandObjects.setProtocol(protocol); + if (protocol != null) + this.commandObjects.setProtocol(protocol); this.graphCommandObjects = new GraphCommandObjects(this); this.graphCommandObjects.setBaseCommandArgumentsCreator((comm) -> this.commandObjects.commandArguments(comm)); - this.clientSideCache = clientSideCache; } @Override @@ -296,7 +301,8 @@ private T checkAndBroadcastCommand(CommandObject commandObject) { if (broadcastAndRoundRobinConfig == null) { } else if (commandObject.getArguments().getCommand() instanceof SearchProtocol.SearchCommand - && broadcastAndRoundRobinConfig.getRediSearchModeInCluster() == JedisBroadcastAndRoundRobinConfig.RediSearchMode.LIGHT) { + && broadcastAndRoundRobinConfig + .getRediSearchModeInCluster() == JedisBroadcastAndRoundRobinConfig.RediSearchMode.LIGHT) { broadcast = false; } @@ -308,14 +314,6 @@ public void setBroadcastAndRoundRobinConfig(JedisBroadcastAndRoundRobinConfig co this.commandObjects.setBroadcastAndRoundRobinConfig(this.broadcastAndRoundRobinConfig); } - private T checkAndClientSideCacheCommand(CommandObject command, Object... keys) { - if (clientSideCache != null) { - return clientSideCache.get((cmd) -> executeCommand(cmd), command, keys); - } - - return executeCommand(command); - } - public String ping() { return checkAndBroadcastCommand(commandObjects.ping()); } @@ -335,12 +333,12 @@ public String configSet(String parameter, String value) { // Key commands @Override public boolean exists(String key) { - return checkAndClientSideCacheCommand(commandObjects.exists(key), key); + return executeCommand(commandObjects.exists(key)); } @Override public long exists(String... keys) { - return checkAndClientSideCacheCommand(commandObjects.exists(keys), (Object[]) keys); + return executeCommand(commandObjects.exists(keys)); } @Override @@ -350,17 +348,17 @@ public long persist(String key) { @Override public String type(String key) { - return checkAndClientSideCacheCommand(commandObjects.type(key), key); + return executeCommand(commandObjects.type(key)); } @Override public boolean exists(byte[] key) { - return checkAndClientSideCacheCommand(commandObjects.exists(key), key); + return executeCommand(commandObjects.exists(key)); } @Override public long exists(byte[]... keys) { - return checkAndClientSideCacheCommand(commandObjects.exists(keys), (Object[]) keys); + return executeCommand(commandObjects.exists(keys)); } @Override @@ -370,7 +368,7 @@ public long persist(byte[] key) { @Override public String type(byte[] key) { - return checkAndClientSideCacheCommand(commandObjects.type(key), key); + return executeCommand(commandObjects.type(key)); } @Override @@ -770,7 +768,7 @@ public String set(String key, String value, SetParams params) { @Override public String get(String key) { - return checkAndClientSideCacheCommand(commandObjects.get(key), key); + return executeCommand(commandObjects.get(key)); } @Override @@ -805,7 +803,7 @@ public String set(byte[] key, byte[] value, SetParams params) { @Override public byte[] get(byte[] key) { - return checkAndClientSideCacheCommand(commandObjects.get(key), key); + return executeCommand(commandObjects.get(key)); } @Override @@ -835,7 +833,7 @@ public boolean setbit(String key, long offset, boolean value) { @Override public boolean getbit(String key, long offset) { - return checkAndClientSideCacheCommand(commandObjects.getbit(key, offset), key); + return executeCommand(commandObjects.getbit(key, offset)); } @Override @@ -845,7 +843,7 @@ public long setrange(String key, long offset, String value) { @Override public String getrange(String key, long startOffset, long endOffset) { - return checkAndClientSideCacheCommand(commandObjects.getrange(key, startOffset, endOffset), key); + return executeCommand(commandObjects.getrange(key, startOffset, endOffset)); } @Override @@ -855,7 +853,7 @@ public boolean setbit(byte[] key, long offset, boolean value) { @Override public boolean getbit(byte[] key, long offset) { - return checkAndClientSideCacheCommand(commandObjects.getbit(key, offset), key); + return executeCommand(commandObjects.getbit(key, offset)); } @Override @@ -865,7 +863,7 @@ public long setrange(byte[] key, long offset, byte[] value) { @Override public byte[] getrange(byte[] key, long startOffset, long endOffset) { - return checkAndClientSideCacheCommand(commandObjects.getrange(key, startOffset, endOffset), key); + return executeCommand(commandObjects.getrange(key, startOffset, endOffset)); } /** @@ -968,7 +966,7 @@ public long decrBy(byte[] key, long decrement) { @Override public List mget(String... keys) { - return checkAndClientSideCacheCommand(commandObjects.mget(keys), (Object[]) keys); + return executeCommand(commandObjects.mget(keys)); } @Override @@ -983,7 +981,7 @@ public long msetnx(String... keysvalues) { @Override public List mget(byte[]... keys) { - return checkAndClientSideCacheCommand(commandObjects.mget(keys), (Object[]) keys); + return executeCommand(commandObjects.mget(keys)); } @Override @@ -1003,12 +1001,12 @@ public long append(String key, String value) { @Override public String substr(String key, int start, int end) { - return checkAndClientSideCacheCommand(commandObjects.substr(key, start, end), key); + return executeCommand(commandObjects.substr(key, start, end)); } @Override public long strlen(String key) { - return checkAndClientSideCacheCommand(commandObjects.strlen(key), key); + return executeCommand(commandObjects.strlen(key)); } @Override @@ -1018,62 +1016,62 @@ public long append(byte[] key, byte[] value) { @Override public byte[] substr(byte[] key, int start, int end) { - return checkAndClientSideCacheCommand(commandObjects.substr(key, start, end), key); + return executeCommand(commandObjects.substr(key, start, end)); } @Override public long strlen(byte[] key) { - return checkAndClientSideCacheCommand(commandObjects.strlen(key), key); + return executeCommand(commandObjects.strlen(key)); } @Override public long bitcount(String key) { - return checkAndClientSideCacheCommand(commandObjects.bitcount(key), key); + return executeCommand(commandObjects.bitcount(key)); } @Override public long bitcount(String key, long start, long end) { - return checkAndClientSideCacheCommand(commandObjects.bitcount(key, start, end), key); + return executeCommand(commandObjects.bitcount(key, start, end)); } @Override public long bitcount(String key, long start, long end, BitCountOption option) { - return checkAndClientSideCacheCommand(commandObjects.bitcount(key, start, end, option), key); + return executeCommand(commandObjects.bitcount(key, start, end, option)); } @Override public long bitpos(String key, boolean value) { - return checkAndClientSideCacheCommand(commandObjects.bitpos(key, value), key); + return executeCommand(commandObjects.bitpos(key, value)); } @Override public long bitpos(String key, boolean value, BitPosParams params) { - return checkAndClientSideCacheCommand(commandObjects.bitpos(key, value, params), key); + return executeCommand(commandObjects.bitpos(key, value, params)); } @Override public long bitcount(byte[] key) { - return checkAndClientSideCacheCommand(commandObjects.bitcount(key), key); + return executeCommand(commandObjects.bitcount(key)); } @Override public long bitcount(byte[] key, long start, long end) { - return checkAndClientSideCacheCommand(commandObjects.bitcount(key, start, end), key); + return executeCommand(commandObjects.bitcount(key, start, end)); } @Override public long bitcount(byte[] key, long start, long end, BitCountOption option) { - return checkAndClientSideCacheCommand(commandObjects.bitcount(key, start, end, option), key); + return executeCommand(commandObjects.bitcount(key, start, end, option)); } @Override public long bitpos(byte[] key, boolean value) { - return checkAndClientSideCacheCommand(commandObjects.bitpos(key, value), key); + return executeCommand(commandObjects.bitpos(key, value)); } @Override public long bitpos(byte[] key, boolean value, BitPosParams params) { - return checkAndClientSideCacheCommand(commandObjects.bitpos(key, value, params), key); + return executeCommand(commandObjects.bitpos(key, value, params)); } @Override @@ -1083,7 +1081,7 @@ public List bitfield(String key, String... arguments) { @Override public List bitfieldReadonly(String key, String... arguments) { - return checkAndClientSideCacheCommand(commandObjects.bitfieldReadonly(key, arguments), key); + return executeCommand(commandObjects.bitfieldReadonly(key, arguments)); } @Override @@ -1093,7 +1091,7 @@ public List bitfield(byte[] key, byte[]... arguments) { @Override public List bitfieldReadonly(byte[] key, byte[]... arguments) { - return checkAndClientSideCacheCommand(commandObjects.bitfieldReadonly(key, arguments), key); + return executeCommand(commandObjects.bitfieldReadonly(key, arguments)); } @Override @@ -1108,12 +1106,12 @@ public long bitop(BitOP op, byte[] destKey, byte[]... srcKeys) { @Override public LCSMatchResult lcs(String keyA, String keyB, LCSParams params) { - return checkAndClientSideCacheCommand(commandObjects.lcs(keyA, keyB, params), keyA, keyB); + return executeCommand(commandObjects.lcs(keyA, keyB, params)); } @Override public LCSMatchResult lcs(byte[] keyA, byte[] keyB, LCSParams params) { - return checkAndClientSideCacheCommand(commandObjects.lcs(keyA, keyB, params), keyA, keyB); + return executeCommand(commandObjects.lcs(keyA, keyB, params)); } // String commands @@ -1130,12 +1128,12 @@ public long lpush(String key, String... string) { @Override public long llen(String key) { - return checkAndClientSideCacheCommand(commandObjects.llen(key), key); + return executeCommand(commandObjects.llen(key)); } @Override public List lrange(String key, long start, long stop) { - return checkAndClientSideCacheCommand(commandObjects.lrange(key, start, stop), key); + return executeCommand(commandObjects.lrange(key, start, stop)); } @Override @@ -1145,7 +1143,7 @@ public String ltrim(String key, long start, long stop) { @Override public String lindex(String key, long index) { - return checkAndClientSideCacheCommand(commandObjects.lindex(key, index), key); + return executeCommand(commandObjects.lindex(key, index)); } @Override @@ -1160,12 +1158,12 @@ public long lpush(byte[] key, byte[]... args) { @Override public long llen(byte[] key) { - return checkAndClientSideCacheCommand(commandObjects.llen(key), key); + return executeCommand(commandObjects.llen(key)); } @Override public List lrange(byte[] key, long start, long stop) { - return checkAndClientSideCacheCommand(commandObjects.lrange(key, start, stop), key); + return executeCommand(commandObjects.lrange(key, start, stop)); } @Override @@ -1175,7 +1173,7 @@ public String ltrim(byte[] key, long start, long stop) { @Override public byte[] lindex(byte[] key, long index) { - return checkAndClientSideCacheCommand(commandObjects.lindex(key, index), key); + return executeCommand(commandObjects.lindex(key, index)); } @Override @@ -1220,32 +1218,32 @@ public List lpop(byte[] key, int count) { @Override public Long lpos(String key, String element) { - return checkAndClientSideCacheCommand(commandObjects.lpos(key, element), key); + return executeCommand(commandObjects.lpos(key, element)); } @Override public Long lpos(String key, String element, LPosParams params) { - return checkAndClientSideCacheCommand(commandObjects.lpos(key, element, params), key); + return executeCommand(commandObjects.lpos(key, element, params)); } @Override public List lpos(String key, String element, LPosParams params, long count) { - return checkAndClientSideCacheCommand(commandObjects.lpos(key, element, params, count), key); + return executeCommand(commandObjects.lpos(key, element, params, count)); } @Override public Long lpos(byte[] key, byte[] element) { - return checkAndClientSideCacheCommand(commandObjects.lpos(key, element), key); + return executeCommand(commandObjects.lpos(key, element)); } @Override public Long lpos(byte[] key, byte[] element, LPosParams params) { - return checkAndClientSideCacheCommand(commandObjects.lpos(key, element, params), key); + return executeCommand(commandObjects.lpos(key, element, params)); } @Override public List lpos(byte[] key, byte[] element, LPosParams params, long count) { - return checkAndClientSideCacheCommand(commandObjects.lpos(key, element, params, count), key); + return executeCommand(commandObjects.lpos(key, element, params, count)); } @Override @@ -1452,7 +1450,7 @@ public long hset(String key, Map hash) { @Override public String hget(String key, String field) { - return checkAndClientSideCacheCommand(commandObjects.hget(key, field), key); + return executeCommand(commandObjects.hget(key, field)); } @Override @@ -1467,7 +1465,7 @@ public String hmset(String key, Map hash) { @Override public List hmget(String key, String... fields) { - return checkAndClientSideCacheCommand(commandObjects.hmget(key, fields), key); + return executeCommand(commandObjects.hmget(key, fields)); } @Override @@ -1482,7 +1480,7 @@ public long hset(byte[] key, Map hash) { @Override public byte[] hget(byte[] key, byte[] field) { - return checkAndClientSideCacheCommand(commandObjects.hget(key, field), key); + return executeCommand(commandObjects.hget(key, field)); } @Override @@ -1497,7 +1495,7 @@ public String hmset(byte[] key, Map hash) { @Override public List hmget(byte[] key, byte[]... fields) { - return checkAndClientSideCacheCommand(commandObjects.hmget(key, fields), key); + return executeCommand(commandObjects.hmget(key, fields)); } @Override @@ -1512,7 +1510,7 @@ public double hincrByFloat(String key, String field, double value) { @Override public boolean hexists(String key, String field) { - return checkAndClientSideCacheCommand(commandObjects.hexists(key, field), key); + return executeCommand(commandObjects.hexists(key, field)); } @Override @@ -1522,7 +1520,7 @@ public long hdel(String key, String... field) { @Override public long hlen(String key) { - return checkAndClientSideCacheCommand(commandObjects.hlen(key), key); + return executeCommand(commandObjects.hlen(key)); } @Override @@ -1537,7 +1535,7 @@ public double hincrByFloat(byte[] key, byte[] field, double value) { @Override public boolean hexists(byte[] key, byte[] field) { - return checkAndClientSideCacheCommand(commandObjects.hexists(key, field), key); + return executeCommand(commandObjects.hexists(key, field)); } @Override @@ -1547,37 +1545,37 @@ public long hdel(byte[] key, byte[]... field) { @Override public long hlen(byte[] key) { - return checkAndClientSideCacheCommand(commandObjects.hlen(key), key); + return executeCommand(commandObjects.hlen(key)); } @Override public Set hkeys(String key) { - return checkAndClientSideCacheCommand(commandObjects.hkeys(key), key); + return executeCommand(commandObjects.hkeys(key)); } @Override public List hvals(String key) { - return checkAndClientSideCacheCommand(commandObjects.hvals(key), key); + return executeCommand(commandObjects.hvals(key)); } @Override public Map hgetAll(String key) { - return checkAndClientSideCacheCommand(commandObjects.hgetAll(key), key); + return executeCommand(commandObjects.hgetAll(key)); } @Override public Set hkeys(byte[] key) { - return checkAndClientSideCacheCommand(commandObjects.hkeys(key), key); + return executeCommand(commandObjects.hkeys(key)); } @Override public List hvals(byte[] key) { - return checkAndClientSideCacheCommand(commandObjects.hvals(key), key); + return executeCommand(commandObjects.hvals(key)); } @Override public Map hgetAll(byte[] key) { - return checkAndClientSideCacheCommand(commandObjects.hgetAll(key), key); + return executeCommand(commandObjects.hgetAll(key)); } @Override @@ -1607,7 +1605,7 @@ public ScanResult hscanNoValues(String key, String cursor, ScanParams pa @Override public long hstrlen(String key, String field) { - return checkAndClientSideCacheCommand(commandObjects.hstrlen(key, field), key); + return executeCommand(commandObjects.hstrlen(key, field)); } @Override @@ -1637,7 +1635,7 @@ public ScanResult hscanNoValues(byte[] key, byte[] cursor, ScanParams pa @Override public long hstrlen(byte[] key, byte[] field) { - return checkAndClientSideCacheCommand(commandObjects.hstrlen(key, field), key); + return executeCommand(commandObjects.hstrlen(key, field)); } @Override @@ -1779,7 +1777,7 @@ public long sadd(String key, String... members) { @Override public Set smembers(String key) { - return checkAndClientSideCacheCommand(commandObjects.smembers(key), key); + return executeCommand(commandObjects.smembers(key)); } @Override @@ -1799,17 +1797,17 @@ public Set spop(String key, long count) { @Override public long scard(String key) { - return checkAndClientSideCacheCommand(commandObjects.scard(key), key); + return executeCommand(commandObjects.scard(key)); } @Override public boolean sismember(String key, String member) { - return checkAndClientSideCacheCommand(commandObjects.sismember(key, member), key); + return executeCommand(commandObjects.sismember(key, member)); } @Override public List smismember(String key, String... members) { - return checkAndClientSideCacheCommand(commandObjects.smismember(key, members), key); + return executeCommand(commandObjects.smismember(key, members)); } @Override @@ -1819,7 +1817,7 @@ public long sadd(byte[] key, byte[]... members) { @Override public Set smembers(byte[] key) { - return checkAndClientSideCacheCommand(commandObjects.smembers(key), key); + return executeCommand(commandObjects.smembers(key)); } @Override @@ -1839,17 +1837,17 @@ public Set spop(byte[] key, long count) { @Override public long scard(byte[] key) { - return checkAndClientSideCacheCommand(commandObjects.scard(key), key); + return executeCommand(commandObjects.scard(key)); } @Override public boolean sismember(byte[] key, byte[] member) { - return checkAndClientSideCacheCommand(commandObjects.sismember(key, member), key); + return executeCommand(commandObjects.sismember(key, member)); } @Override public List smismember(byte[] key, byte[]... members) { - return checkAndClientSideCacheCommand(commandObjects.smismember(key, members), key); + return executeCommand(commandObjects.smismember(key, members)); } @Override @@ -1884,7 +1882,7 @@ public ScanResult sscan(byte[] key, byte[] cursor, ScanParams params) { @Override public Set sdiff(String... keys) { - return checkAndClientSideCacheCommand(commandObjects.sdiff(keys), (Object[]) keys); + return executeCommand(commandObjects.sdiff(keys)); } @Override @@ -1894,7 +1892,7 @@ public long sdiffstore(String dstkey, String... keys) { @Override public Set sinter(String... keys) { - return checkAndClientSideCacheCommand(commandObjects.sinter(keys), (Object[]) keys); + return executeCommand(commandObjects.sinter(keys)); } @Override @@ -1914,7 +1912,7 @@ public long sintercard(int limit, String... keys) { @Override public Set sunion(String... keys) { - return checkAndClientSideCacheCommand(commandObjects.sunion(keys), (Object[]) keys); + return executeCommand(commandObjects.sunion(keys)); } @Override @@ -1929,7 +1927,7 @@ public long smove(String srckey, String dstkey, String member) { @Override public Set sdiff(byte[]... keys) { - return checkAndClientSideCacheCommand(commandObjects.sdiff(keys), (Object[]) keys); + return executeCommand(commandObjects.sdiff(keys)); } @Override @@ -1939,7 +1937,7 @@ public long sdiffstore(byte[] dstkey, byte[]... keys) { @Override public Set sinter(byte[]... keys) { - return checkAndClientSideCacheCommand(commandObjects.sinter(keys), (Object[]) keys); + return executeCommand(commandObjects.sinter(keys)); } @Override @@ -1959,7 +1957,7 @@ public long sintercard(int limit, byte[]... keys) { @Override public Set sunion(byte[]... keys) { - return checkAndClientSideCacheCommand(commandObjects.sunion(keys), (Object[]) keys); + return executeCommand(commandObjects.sunion(keys)); } @Override @@ -2041,22 +2039,22 @@ public Double zincrby(String key, double increment, String member, ZIncrByParams @Override public Long zrank(String key, String member) { - return checkAndClientSideCacheCommand(commandObjects.zrank(key, member), key); + return executeCommand(commandObjects.zrank(key, member)); } @Override public Long zrevrank(String key, String member) { - return checkAndClientSideCacheCommand(commandObjects.zrevrank(key, member), key); + return executeCommand(commandObjects.zrevrank(key, member)); } @Override public KeyValue zrankWithScore(String key, String member) { - return checkAndClientSideCacheCommand(commandObjects.zrankWithScore(key, member), key); + return executeCommand(commandObjects.zrankWithScore(key, member)); } @Override public KeyValue zrevrankWithScore(String key, String member) { - return checkAndClientSideCacheCommand(commandObjects.zrevrankWithScore(key, member), key); + return executeCommand(commandObjects.zrevrankWithScore(key, member)); } @Override @@ -2076,22 +2074,22 @@ public Double zincrby(byte[] key, double increment, byte[] member, ZIncrByParams @Override public Long zrank(byte[] key, byte[] member) { - return checkAndClientSideCacheCommand(commandObjects.zrank(key, member), key); + return executeCommand(commandObjects.zrank(key, member)); } @Override public Long zrevrank(byte[] key, byte[] member) { - return checkAndClientSideCacheCommand(commandObjects.zrevrank(key, member), key); + return executeCommand(commandObjects.zrevrank(key, member)); } @Override public KeyValue zrankWithScore(byte[] key, byte[] member) { - return checkAndClientSideCacheCommand(commandObjects.zrankWithScore(key, member), key); + return executeCommand(commandObjects.zrankWithScore(key, member)); } @Override public KeyValue zrevrankWithScore(byte[] key, byte[] member) { - return checkAndClientSideCacheCommand(commandObjects.zrevrankWithScore(key, member), key); + return executeCommand(commandObjects.zrevrankWithScore(key, member)); } @Override @@ -2111,17 +2109,17 @@ public List zrandmemberWithScores(String key, long count) { @Override public long zcard(String key) { - return checkAndClientSideCacheCommand(commandObjects.zcard(key), key); + return executeCommand(commandObjects.zcard(key)); } @Override public Double zscore(String key, String member) { - return checkAndClientSideCacheCommand(commandObjects.zscore(key, member), key); + return executeCommand(commandObjects.zscore(key, member)); } @Override public List zmscore(String key, String... members) { - return checkAndClientSideCacheCommand(commandObjects.zmscore(key, members), key); + return executeCommand(commandObjects.zmscore(key, members)); } @Override @@ -2141,17 +2139,17 @@ public List zrandmemberWithScores(byte[] key, long count) { @Override public long zcard(byte[] key) { - return checkAndClientSideCacheCommand(commandObjects.zcard(key), key); + return executeCommand(commandObjects.zcard(key)); } @Override public Double zscore(byte[] key, byte[] member) { - return checkAndClientSideCacheCommand(commandObjects.zscore(key, member), key); + return executeCommand(commandObjects.zscore(key, member)); } @Override public List zmscore(byte[] key, byte[]... members) { - return checkAndClientSideCacheCommand(commandObjects.zmscore(key, members), key); + return executeCommand(commandObjects.zmscore(key, members)); } @Override @@ -2176,12 +2174,12 @@ public List zpopmin(String key, int count) { @Override public long zcount(String key, double min, double max) { - return checkAndClientSideCacheCommand(commandObjects.zcount(key, min, max), key); + return executeCommand(commandObjects.zcount(key, min, max)); } @Override public long zcount(String key, String min, String max) { - return checkAndClientSideCacheCommand(commandObjects.zcount(key, min, max), key); + return executeCommand(commandObjects.zcount(key, min, max)); } @Override @@ -2206,42 +2204,42 @@ public List zpopmin(byte[] key, int count) { @Override public long zcount(byte[] key, double min, double max) { - return checkAndClientSideCacheCommand(commandObjects.zcount(key, min, max), key); + return executeCommand(commandObjects.zcount(key, min, max)); } @Override public long zcount(byte[] key, byte[] min, byte[] max) { - return checkAndClientSideCacheCommand(commandObjects.zcount(key, min, max), key); + return executeCommand(commandObjects.zcount(key, min, max)); } @Override public List zrange(String key, long start, long stop) { - return checkAndClientSideCacheCommand(commandObjects.zrange(key, start, stop), key); + return executeCommand(commandObjects.zrange(key, start, stop)); } @Override public List zrevrange(String key, long start, long stop) { - return checkAndClientSideCacheCommand(commandObjects.zrevrange(key, start, stop), key); + return executeCommand(commandObjects.zrevrange(key, start, stop)); } @Override public List zrangeWithScores(String key, long start, long stop) { - return checkAndClientSideCacheCommand(commandObjects.zrangeWithScores(key, start, stop), key); + return executeCommand(commandObjects.zrangeWithScores(key, start, stop)); } @Override public List zrevrangeWithScores(String key, long start, long stop) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeWithScores(key, start, stop), key); + return executeCommand(commandObjects.zrevrangeWithScores(key, start, stop)); } @Override public List zrange(String key, ZRangeParams zRangeParams) { - return checkAndClientSideCacheCommand(commandObjects.zrange(key, zRangeParams), key); + return executeCommand(commandObjects.zrange(key, zRangeParams)); } @Override public List zrangeWithScores(String key, ZRangeParams zRangeParams) { - return checkAndClientSideCacheCommand(commandObjects.zrangeWithScores(key, zRangeParams), key); + return executeCommand(commandObjects.zrangeWithScores(key, zRangeParams)); } @Override @@ -2251,112 +2249,112 @@ public long zrangestore(String dest, String src, ZRangeParams zRangeParams) { @Override public List zrangeByScore(String key, double min, double max) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByScore(key, min, max), key); + return executeCommand(commandObjects.zrangeByScore(key, min, max)); } @Override public List zrangeByScore(String key, String min, String max) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByScore(key, min, max), key); + return executeCommand(commandObjects.zrangeByScore(key, min, max)); } @Override public List zrevrangeByScore(String key, double max, double min) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByScore(key, max, min), key); + return executeCommand(commandObjects.zrevrangeByScore(key, max, min)); } @Override public List zrangeByScore(String key, double min, double max, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByScore(key, min, max, offset, count), key); + return executeCommand(commandObjects.zrangeByScore(key, min, max, offset, count)); } @Override public List zrevrangeByScore(String key, String max, String min) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByScore(key, max, min), key); + return executeCommand(commandObjects.zrevrangeByScore(key, max, min)); } @Override public List zrangeByScore(String key, String min, String max, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByScore(key, min, max, offset, count), key); + return executeCommand(commandObjects.zrangeByScore(key, min, max, offset, count)); } @Override public List zrevrangeByScore(String key, double max, double min, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByScore(key, max, min, offset, count), key); + return executeCommand(commandObjects.zrevrangeByScore(key, max, min, offset, count)); } @Override public List zrangeByScoreWithScores(String key, double min, double max) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByScoreWithScores(key, min, max), key); + return executeCommand(commandObjects.zrangeByScoreWithScores(key, min, max)); } @Override public List zrevrangeByScoreWithScores(String key, double max, double min) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByScoreWithScores(key, max, min), key); + return executeCommand(commandObjects.zrevrangeByScoreWithScores(key, max, min)); } @Override public List zrangeByScoreWithScores(String key, double min, double max, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByScoreWithScores(key, min, max, offset, count), key); + return executeCommand(commandObjects.zrangeByScoreWithScores(key, min, max, offset, count)); } @Override public List zrevrangeByScore(String key, String max, String min, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByScore(key, max, min, offset, count), key); + return executeCommand(commandObjects.zrevrangeByScore(key, max, min, offset, count)); } @Override public List zrangeByScoreWithScores(String key, String min, String max) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByScoreWithScores(key, min, max), key); + return executeCommand(commandObjects.zrangeByScoreWithScores(key, min, max)); } @Override public List zrevrangeByScoreWithScores(String key, String max, String min) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByScoreWithScores(key, max, min), key); + return executeCommand(commandObjects.zrevrangeByScoreWithScores(key, max, min)); } @Override public List zrangeByScoreWithScores(String key, String min, String max, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByScoreWithScores(key, min, max, offset, count), key); + return executeCommand(commandObjects.zrangeByScoreWithScores(key, min, max, offset, count)); } @Override public List zrevrangeByScoreWithScores(String key, double max, double min, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByScoreWithScores(key, max, min, offset, count), key); + return executeCommand(commandObjects.zrevrangeByScoreWithScores(key, max, min, offset, count)); } @Override public List zrevrangeByScoreWithScores(String key, String max, String min, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByScoreWithScores(key, max, min, offset, count), key); + return executeCommand(commandObjects.zrevrangeByScoreWithScores(key, max, min, offset, count)); } @Override public List zrange(byte[] key, long start, long stop) { - return checkAndClientSideCacheCommand(commandObjects.zrange(key, start, stop), key); + return executeCommand(commandObjects.zrange(key, start, stop)); } @Override public List zrevrange(byte[] key, long start, long stop) { - return checkAndClientSideCacheCommand(commandObjects.zrevrange(key, start, stop), key); + return executeCommand(commandObjects.zrevrange(key, start, stop)); } @Override public List zrangeWithScores(byte[] key, long start, long stop) { - return checkAndClientSideCacheCommand(commandObjects.zrangeWithScores(key, start, stop), key); + return executeCommand(commandObjects.zrangeWithScores(key, start, stop)); } @Override public List zrevrangeWithScores(byte[] key, long start, long stop) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeWithScores(key, start, stop), key); + return executeCommand(commandObjects.zrevrangeWithScores(key, start, stop)); } @Override public List zrange(byte[] key, ZRangeParams zRangeParams) { - return checkAndClientSideCacheCommand(commandObjects.zrange(key, zRangeParams), key); + return executeCommand(commandObjects.zrange(key, zRangeParams)); } @Override public List zrangeWithScores(byte[] key, ZRangeParams zRangeParams) { - return checkAndClientSideCacheCommand(commandObjects.zrangeWithScores(key, zRangeParams), key); + return executeCommand(commandObjects.zrangeWithScores(key, zRangeParams)); } @Override @@ -2366,82 +2364,82 @@ public long zrangestore(byte[] dest, byte[] src, ZRangeParams zRangeParams) { @Override public List zrangeByScore(byte[] key, double min, double max) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByScore(key, min, max), key); + return executeCommand(commandObjects.zrangeByScore(key, min, max)); } @Override public List zrangeByScore(byte[] key, byte[] min, byte[] max) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByScore(key, min, max), key); + return executeCommand(commandObjects.zrangeByScore(key, min, max)); } @Override public List zrevrangeByScore(byte[] key, double max, double min) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByScore(key, max, min), key); + return executeCommand(commandObjects.zrevrangeByScore(key, max, min)); } @Override public List zrangeByScore(byte[] key, double min, double max, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByScore(key, min, max, offset, count), key); + return executeCommand(commandObjects.zrangeByScore(key, min, max, offset, count)); } @Override public List zrevrangeByScore(byte[] key, byte[] max, byte[] min) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByScore(key, max, min), key); + return executeCommand(commandObjects.zrevrangeByScore(key, max, min)); } @Override public List zrangeByScore(byte[] key, byte[] min, byte[] max, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByScore(key, min, max, offset, count), key); + return executeCommand(commandObjects.zrangeByScore(key, min, max, offset, count)); } @Override public List zrevrangeByScore(byte[] key, double max, double min, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByScore(key, max, min, offset, count), key); + return executeCommand(commandObjects.zrevrangeByScore(key, max, min, offset, count)); } @Override public List zrangeByScoreWithScores(byte[] key, double min, double max) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByScoreWithScores(key, min, max), key); + return executeCommand(commandObjects.zrangeByScoreWithScores(key, min, max)); } @Override public List zrevrangeByScoreWithScores(byte[] key, double max, double min) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByScoreWithScores(key, max, min), key); + return executeCommand(commandObjects.zrevrangeByScoreWithScores(key, max, min)); } @Override public List zrangeByScoreWithScores(byte[] key, double min, double max, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByScoreWithScores(key, min, max, offset, count), key); + return executeCommand(commandObjects.zrangeByScoreWithScores(key, min, max, offset, count)); } @Override public List zrevrangeByScore(byte[] key, byte[] max, byte[] min, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByScore(key, max, min, offset, count), key); + return executeCommand(commandObjects.zrevrangeByScore(key, max, min, offset, count)); } @Override public List zrangeByScoreWithScores(byte[] key, byte[] min, byte[] max) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByScoreWithScores(key, min, max), key); + return executeCommand(commandObjects.zrangeByScoreWithScores(key, min, max)); } @Override public List zrevrangeByScoreWithScores(byte[] key, byte[] max, byte[] min) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByScoreWithScores(key, max, min), key); + return executeCommand(commandObjects.zrevrangeByScoreWithScores(key, max, min)); } @Override public List zrangeByScoreWithScores(byte[] key, byte[] min, byte[] max, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByScoreWithScores(key, min, max, offset, count), key); + return executeCommand(commandObjects.zrangeByScoreWithScores(key, min, max, offset, count)); } @Override public List zrevrangeByScoreWithScores(byte[] key, double max, double min, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByScoreWithScores(key, max, min, offset, count), key); + return executeCommand(commandObjects.zrevrangeByScoreWithScores(key, max, min, offset, count)); } @Override public List zrevrangeByScoreWithScores(byte[] key, byte[] max, byte[] min, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByScoreWithScores(key, max, min, offset, count), key); + return executeCommand(commandObjects.zrevrangeByScoreWithScores(key, max, min, offset, count)); } @Override @@ -2476,27 +2474,27 @@ public long zremrangeByScore(byte[] key, byte[] min, byte[] max) { @Override public long zlexcount(String key, String min, String max) { - return checkAndClientSideCacheCommand(commandObjects.zlexcount(key, min, max), key); + return executeCommand(commandObjects.zlexcount(key, min, max)); } @Override public List zrangeByLex(String key, String min, String max) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByLex(key, min, max), key); + return executeCommand(commandObjects.zrangeByLex(key, min, max)); } @Override public List zrangeByLex(String key, String min, String max, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByLex(key, min, max, offset, count), key); + return executeCommand(commandObjects.zrangeByLex(key, min, max, offset, count)); } @Override public List zrevrangeByLex(String key, String max, String min) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByLex(key, max, min), key); + return executeCommand(commandObjects.zrevrangeByLex(key, max, min)); } @Override public List zrevrangeByLex(String key, String max, String min, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByLex(key, max, min, offset, count), key); + return executeCommand(commandObjects.zrevrangeByLex(key, max, min, offset, count)); } @Override @@ -2506,27 +2504,27 @@ public long zremrangeByLex(String key, String min, String max) { @Override public long zlexcount(byte[] key, byte[] min, byte[] max) { - return checkAndClientSideCacheCommand(commandObjects.zlexcount(key, min, max), key); + return executeCommand(commandObjects.zlexcount(key, min, max)); } @Override public List zrangeByLex(byte[] key, byte[] min, byte[] max) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByLex(key, min, max), key); + return executeCommand(commandObjects.zrangeByLex(key, min, max)); } @Override public List zrangeByLex(byte[] key, byte[] min, byte[] max, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrangeByLex(key, min, max, offset, count), key); + return executeCommand(commandObjects.zrangeByLex(key, min, max, offset, count)); } @Override public List zrevrangeByLex(byte[] key, byte[] max, byte[] min) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByLex(key, max, min), key); + return executeCommand(commandObjects.zrevrangeByLex(key, max, min)); } @Override public List zrevrangeByLex(byte[] key, byte[] max, byte[] min, int offset, int count) { - return checkAndClientSideCacheCommand(commandObjects.zrevrangeByLex(key, max, min, offset, count), key); + return executeCommand(commandObjects.zrevrangeByLex(key, max, min, offset, count)); } @Override @@ -2765,22 +2763,22 @@ public long geoadd(String key, GeoAddParams params, Map m @Override public Double geodist(String key, String member1, String member2) { - return checkAndClientSideCacheCommand(commandObjects.geodist(key, member1, member2), key); + return executeCommand(commandObjects.geodist(key, member1, member2)); } @Override public Double geodist(String key, String member1, String member2, GeoUnit unit) { - return checkAndClientSideCacheCommand(commandObjects.geodist(key, member1, member2, unit), key); + return executeCommand(commandObjects.geodist(key, member1, member2, unit)); } @Override public List geohash(String key, String... members) { - return checkAndClientSideCacheCommand(commandObjects.geohash(key, members), key); + return executeCommand(commandObjects.geohash(key, members)); } @Override public List geopos(String key, String... members) { - return checkAndClientSideCacheCommand(commandObjects.geopos(key, members), key); + return executeCommand(commandObjects.geopos(key, members)); } @Override @@ -2800,22 +2798,22 @@ public long geoadd(byte[] key, GeoAddParams params, Map m @Override public Double geodist(byte[] key, byte[] member1, byte[] member2) { - return checkAndClientSideCacheCommand(commandObjects.geodist(key, member1, member2), key); + return executeCommand(commandObjects.geodist(key, member1, member2)); } @Override public Double geodist(byte[] key, byte[] member1, byte[] member2, GeoUnit unit) { - return checkAndClientSideCacheCommand(commandObjects.geodist(key, member1, member2, unit), key); + return executeCommand(commandObjects.geodist(key, member1, member2, unit)); } @Override public List geohash(byte[] key, byte[]... members) { - return checkAndClientSideCacheCommand(commandObjects.geohash(key, members), key); + return executeCommand(commandObjects.geohash(key, members)); } @Override public List geopos(byte[] key, byte[]... members) { - return checkAndClientSideCacheCommand(commandObjects.geopos(key, members), key); + return executeCommand(commandObjects.geopos(key, members)); } @Override @@ -2825,7 +2823,7 @@ public List georadius(String key, double longitude, double la @Override public List georadiusReadonly(String key, double longitude, double latitude, double radius, GeoUnit unit) { - return checkAndClientSideCacheCommand(commandObjects.georadiusReadonly(key, longitude, latitude, radius, unit), key); + return executeCommand(commandObjects.georadiusReadonly(key, longitude, latitude, radius, unit)); } @Override @@ -2835,7 +2833,7 @@ public List georadius(String key, double longitude, double la @Override public List georadiusReadonly(String key, double longitude, double latitude, double radius, GeoUnit unit, GeoRadiusParam param) { - return checkAndClientSideCacheCommand(commandObjects.georadiusReadonly(key, longitude, latitude, radius, unit, param), key); + return executeCommand(commandObjects.georadiusReadonly(key, longitude, latitude, radius, unit, param)); } @Override @@ -2845,7 +2843,7 @@ public List georadiusByMember(String key, String member, doub @Override public List georadiusByMemberReadonly(String key, String member, double radius, GeoUnit unit) { - return checkAndClientSideCacheCommand(commandObjects.georadiusByMemberReadonly(key, member, radius, unit), key); + return executeCommand(commandObjects.georadiusByMemberReadonly(key, member, radius, unit)); } @Override @@ -2855,7 +2853,7 @@ public List georadiusByMember(String key, String member, doub @Override public List georadiusByMemberReadonly(String key, String member, double radius, GeoUnit unit, GeoRadiusParam param) { - return checkAndClientSideCacheCommand(commandObjects.georadiusByMemberReadonly(key, member, radius, unit, param), key); + return executeCommand(commandObjects.georadiusByMemberReadonly(key, member, radius, unit, param)); } @Override @@ -2870,27 +2868,27 @@ public long georadiusByMemberStore(String key, String member, double radius, Geo @Override public List geosearch(String key, String member, double radius, GeoUnit unit) { - return checkAndClientSideCacheCommand(commandObjects.geosearch(key, member, radius, unit), key); + return executeCommand(commandObjects.geosearch(key, member, radius, unit)); } @Override public List geosearch(String key, GeoCoordinate coord, double radius, GeoUnit unit) { - return checkAndClientSideCacheCommand(commandObjects.geosearch(key, coord, radius, unit), key); + return executeCommand(commandObjects.geosearch(key, coord, radius, unit)); } @Override public List geosearch(String key, String member, double width, double height, GeoUnit unit) { - return checkAndClientSideCacheCommand(commandObjects.geosearch(key, member, width, height, unit), key); + return executeCommand(commandObjects.geosearch(key, member, width, height, unit)); } @Override public List geosearch(String key, GeoCoordinate coord, double width, double height, GeoUnit unit) { - return checkAndClientSideCacheCommand(commandObjects.geosearch(key, coord, width, height, unit), key); + return executeCommand(commandObjects.geosearch(key, coord, width, height, unit)); } @Override public List geosearch(String key, GeoSearchParam params) { - return checkAndClientSideCacheCommand(commandObjects.geosearch(key, params), key); + return executeCommand(commandObjects.geosearch(key, params)); } @Override @@ -2930,7 +2928,7 @@ public List georadius(byte[] key, double longitude, double la @Override public List georadiusReadonly(byte[] key, double longitude, double latitude, double radius, GeoUnit unit) { - return checkAndClientSideCacheCommand(commandObjects.georadiusReadonly(key, longitude, latitude, radius, unit), key); + return executeCommand(commandObjects.georadiusReadonly(key, longitude, latitude, radius, unit)); } @Override @@ -2940,7 +2938,7 @@ public List georadius(byte[] key, double longitude, double la @Override public List georadiusReadonly(byte[] key, double longitude, double latitude, double radius, GeoUnit unit, GeoRadiusParam param) { - return checkAndClientSideCacheCommand(commandObjects.georadiusReadonly(key, longitude, latitude, radius, unit, param), key); + return executeCommand(commandObjects.georadiusReadonly(key, longitude, latitude, radius, unit, param)); } @Override @@ -2950,7 +2948,7 @@ public List georadiusByMember(byte[] key, byte[] member, doub @Override public List georadiusByMemberReadonly(byte[] key, byte[] member, double radius, GeoUnit unit) { - return checkAndClientSideCacheCommand(commandObjects.georadiusByMemberReadonly(key, member, radius, unit), key); + return executeCommand(commandObjects.georadiusByMemberReadonly(key, member, radius, unit)); } @Override @@ -2960,7 +2958,7 @@ public List georadiusByMember(byte[] key, byte[] member, doub @Override public List georadiusByMemberReadonly(byte[] key, byte[] member, double radius, GeoUnit unit, GeoRadiusParam param) { - return checkAndClientSideCacheCommand(commandObjects.georadiusByMemberReadonly(key, member, radius, unit, param), key); + return executeCommand(commandObjects.georadiusByMemberReadonly(key, member, radius, unit, param)); } @Override @@ -2975,27 +2973,27 @@ public long georadiusByMemberStore(byte[] key, byte[] member, double radius, Geo @Override public List geosearch(byte[] key, byte[] member, double radius, GeoUnit unit) { - return checkAndClientSideCacheCommand(commandObjects.geosearch(key, member, radius, unit), key); + return executeCommand(commandObjects.geosearch(key, member, radius, unit)); } @Override public List geosearch(byte[] key, GeoCoordinate coord, double radius, GeoUnit unit) { - return checkAndClientSideCacheCommand(commandObjects.geosearch(key, coord, radius, unit), key); + return executeCommand(commandObjects.geosearch(key, coord, radius, unit)); } @Override public List geosearch(byte[] key, byte[] member, double width, double height, GeoUnit unit) { - return checkAndClientSideCacheCommand(commandObjects.geosearch(key, member, width, height, unit), key); + return executeCommand(commandObjects.geosearch(key, member, width, height, unit)); } @Override public List geosearch(byte[] key, GeoCoordinate coord, double width, double height, GeoUnit unit) { - return checkAndClientSideCacheCommand(commandObjects.geosearch(key, coord, width, height, unit), key); + return executeCommand(commandObjects.geosearch(key, coord, width, height, unit)); } @Override public List geosearch(byte[] key, GeoSearchParam params) { - return checkAndClientSideCacheCommand(commandObjects.geosearch(key, params), key); + return executeCommand(commandObjects.geosearch(key, params)); } @Override @@ -3084,47 +3082,47 @@ public StreamEntryID xadd(String key, XAddParams params, Map has @Override public long xlen(String key) { - return checkAndClientSideCacheCommand(commandObjects.xlen(key), key); + return executeCommand(commandObjects.xlen(key)); } @Override public List xrange(String key, StreamEntryID start, StreamEntryID end) { - return checkAndClientSideCacheCommand(commandObjects.xrange(key, start, end), key); + return executeCommand(commandObjects.xrange(key, start, end)); } @Override public List xrange(String key, StreamEntryID start, StreamEntryID end, int count) { - return checkAndClientSideCacheCommand(commandObjects.xrange(key, start, end, count), key); + return executeCommand(commandObjects.xrange(key, start, end, count)); } @Override public List xrevrange(String key, StreamEntryID end, StreamEntryID start) { - return checkAndClientSideCacheCommand(commandObjects.xrevrange(key, end, start), key); + return executeCommand(commandObjects.xrevrange(key, end, start)); } @Override public List xrevrange(String key, StreamEntryID end, StreamEntryID start, int count) { - return checkAndClientSideCacheCommand(commandObjects.xrevrange(key, end, start, count), key); + return executeCommand(commandObjects.xrevrange(key, end, start, count)); } @Override public List xrange(String key, String start, String end) { - return checkAndClientSideCacheCommand(commandObjects.xrange(key, start, end), key); + return executeCommand(commandObjects.xrange(key, start, end)); } @Override public List xrange(String key, String start, String end, int count) { - return checkAndClientSideCacheCommand(commandObjects.xrange(key, start, end, count), key); + return executeCommand(commandObjects.xrange(key, start, end, count)); } @Override public List xrevrange(String key, String end, String start) { - return checkAndClientSideCacheCommand(commandObjects.xrevrange(key, end, start), key); + return executeCommand(commandObjects.xrevrange(key, end, start)); } @Override public List xrevrange(String key, String end, String start, int count) { - return checkAndClientSideCacheCommand(commandObjects.xrevrange(key, end, start, count), key); + return executeCommand(commandObjects.xrevrange(key, end, start, count)); } @Override @@ -3159,12 +3157,12 @@ public long xgroupDelConsumer(String key, String groupName, String consumerName) @Override public StreamPendingSummary xpending(String key, String groupName) { - return checkAndClientSideCacheCommand(commandObjects.xpending(key, groupName), key); + return executeCommand(commandObjects.xpending(key, groupName)); } @Override public List xpending(String key, String groupName, XPendingParams params) { - return checkAndClientSideCacheCommand(commandObjects.xpending(key, groupName, params), key); + return executeCommand(commandObjects.xpending(key, groupName, params)); } @Override @@ -3243,14 +3241,12 @@ public Map> xreadAsMap(XReadParams xReadParams, Map>> xreadGroup(String groupName, String consumer, - XReadGroupParams xReadGroupParams, Map streams) { + public List>> xreadGroup(String groupName, String consumer, XReadGroupParams xReadGroupParams, Map streams) { return executeCommand(commandObjects.xreadGroup(groupName, consumer, xReadGroupParams, streams)); } @Override - public Map> xreadGroupAsMap(String groupName, String consumer, - XReadGroupParams xReadGroupParams, Map streams) { + public Map> xreadGroupAsMap(String groupName, String consumer, XReadGroupParams xReadGroupParams, Map streams) { return executeCommand(commandObjects.xreadGroupAsMap(groupName, consumer, xReadGroupParams, streams)); } @@ -3261,27 +3257,27 @@ public byte[] xadd(byte[] key, XAddParams params, Map hash) { @Override public long xlen(byte[] key) { - return checkAndClientSideCacheCommand(commandObjects.xlen(key), key); + return executeCommand(commandObjects.xlen(key)); } @Override public List xrange(byte[] key, byte[] start, byte[] end) { - return checkAndClientSideCacheCommand(commandObjects.xrange(key, start, end), key); + return executeCommand(commandObjects.xrange(key, start, end)); } @Override public List xrange(byte[] key, byte[] start, byte[] end, int count) { - return checkAndClientSideCacheCommand(commandObjects.xrange(key, start, end, count), key); + return executeCommand(commandObjects.xrange(key, start, end, count)); } @Override public List xrevrange(byte[] key, byte[] end, byte[] start) { - return checkAndClientSideCacheCommand(commandObjects.xrevrange(key, end, start), key); + return executeCommand(commandObjects.xrevrange(key, end, start)); } @Override public List xrevrange(byte[] key, byte[] end, byte[] start, int count) { - return checkAndClientSideCacheCommand(commandObjects.xrevrange(key, end, start, count), key); + return executeCommand(commandObjects.xrevrange(key, end, start, count)); } @Override @@ -3331,12 +3327,12 @@ public long xtrim(byte[] key, XTrimParams params) { @Override public Object xpending(byte[] key, byte[] groupName) { - return checkAndClientSideCacheCommand(commandObjects.xpending(key, groupName), key); + return executeCommand(commandObjects.xpending(key, groupName)); } @Override public List xpending(byte[] key, byte[] groupName, XPendingParams params) { - return checkAndClientSideCacheCommand(commandObjects.xpending(key, groupName, params), key); + return executeCommand(commandObjects.xpending(key, groupName, params)); } @Override @@ -3716,7 +3712,7 @@ public List scriptExists(List sha1s) { @Override public Boolean scriptExists(String sha1, String sampleKey) { - return scriptExists(sampleKey, new String[]{sha1}).get(0); + return scriptExists(sampleKey, new String[] { sha1 }).get(0); } @Override @@ -3726,7 +3722,7 @@ public List scriptExists(String sampleKey, String... sha1s) { @Override public Boolean scriptExists(byte[] sha1, byte[] sampleKey) { - return scriptExists(sampleKey, new byte[][]{sha1}).get(0); + return scriptExists(sampleKey, new byte[][] { sha1 }).get(0); } @Override @@ -3891,6 +3887,7 @@ public SearchResult ftSearch(String indexName, String query, FTSearchParams para /** * {@link FTSearchParams#limit(int, int)} will be ignored. + * * @param batchSize batch size * @param indexName index name * @param query query @@ -4022,7 +4019,8 @@ public Map> ftSpellCheck(String index, String query) } @Override - public Map> ftSpellCheck(String index, String query, FTSpellCheckParams spellCheckParams) { + public Map> ftSpellCheck(String index, String query, + FTSpellCheckParams spellCheckParams) { return executeCommand(commandObjects.ftSpellCheck(index, query, spellCheckParams)); } @@ -4154,47 +4152,47 @@ public String jsonMerge(String key, Path path, Object pojo) { @Override public Object jsonGet(String key) { - return checkAndClientSideCacheCommand(commandObjects.jsonGet(key), key); + return executeCommand(commandObjects.jsonGet(key)); } @Override @Deprecated public T jsonGet(String key, Class clazz) { - return checkAndClientSideCacheCommand(commandObjects.jsonGet(key, clazz), key); + return executeCommand(commandObjects.jsonGet(key, clazz)); } @Override public Object jsonGet(String key, Path2... paths) { - return checkAndClientSideCacheCommand(commandObjects.jsonGet(key, paths), key); + return executeCommand(commandObjects.jsonGet(key, paths)); } @Override @Deprecated public Object jsonGet(String key, Path... paths) { - return checkAndClientSideCacheCommand(commandObjects.jsonGet(key, paths), key); + return executeCommand(commandObjects.jsonGet(key, paths)); } @Override @Deprecated public String jsonGetAsPlainString(String key, Path path) { - return checkAndClientSideCacheCommand(commandObjects.jsonGetAsPlainString(key, path), key); + return executeCommand(commandObjects.jsonGetAsPlainString(key, path)); } @Override @Deprecated public T jsonGet(String key, Class clazz, Path... paths) { - return checkAndClientSideCacheCommand(commandObjects.jsonGet(key, clazz, paths), key); + return executeCommand(commandObjects.jsonGet(key, clazz, paths)); } @Override public List jsonMGet(Path2 path, String... keys) { - return checkAndClientSideCacheCommand(commandObjects.jsonMGet(path, keys), (Object[]) keys); + return executeCommand(commandObjects.jsonMGet(path, keys)); } @Override @Deprecated public List jsonMGet(Path path, Class clazz, String... keys) { - return checkAndClientSideCacheCommand(commandObjects.jsonMGet(path, clazz, keys), (Object[]) keys); + return executeCommand(commandObjects.jsonMGet(path, clazz, keys)); } @Override @@ -4243,18 +4241,18 @@ public String jsonToggle(String key, Path path) { @Override @Deprecated public Class jsonType(String key) { - return checkAndClientSideCacheCommand(commandObjects.jsonType(key), key); + return executeCommand(commandObjects.jsonType(key)); } @Override public List> jsonType(String key, Path2 path) { - return checkAndClientSideCacheCommand(commandObjects.jsonType(key, path), key); + return executeCommand(commandObjects.jsonType(key, path)); } @Override @Deprecated public Class jsonType(String key, Path path) { - return checkAndClientSideCacheCommand(commandObjects.jsonType(key, path), key); + return executeCommand(commandObjects.jsonType(key, path)); } @Override @@ -4277,18 +4275,18 @@ public long jsonStrAppend(String key, Path path, Object string) { @Override @Deprecated public Long jsonStrLen(String key) { - return checkAndClientSideCacheCommand(commandObjects.jsonStrLen(key), key); + return executeCommand(commandObjects.jsonStrLen(key)); } @Override public List jsonStrLen(String key, Path2 path) { - return checkAndClientSideCacheCommand(commandObjects.jsonStrLen(key, path), key); + return executeCommand(commandObjects.jsonStrLen(key, path)); } @Override @Deprecated public Long jsonStrLen(String key, Path path) { - return checkAndClientSideCacheCommand(commandObjects.jsonStrLen(key, path), key); + return executeCommand(commandObjects.jsonStrLen(key, path)); } @Override @@ -4320,18 +4318,18 @@ public Long jsonArrAppend(String key, Path path, Object... pojos) { @Override public List jsonArrIndex(String key, Path2 path, Object scalar) { - return checkAndClientSideCacheCommand(commandObjects.jsonArrIndex(key, path, scalar), key); + return executeCommand(commandObjects.jsonArrIndex(key, path, scalar)); } @Override public List jsonArrIndexWithEscape(String key, Path2 path, Object scalar) { - return checkAndClientSideCacheCommand(commandObjects.jsonArrIndexWithEscape(key, path, scalar), key); + return executeCommand(commandObjects.jsonArrIndexWithEscape(key, path, scalar)); } @Override @Deprecated public long jsonArrIndex(String key, Path path, Object scalar) { - return checkAndClientSideCacheCommand(commandObjects.jsonArrIndex(key, path, scalar), key); + return executeCommand(commandObjects.jsonArrIndex(key, path, scalar)); } @Override @@ -4399,18 +4397,18 @@ public T jsonArrPop(String key, Class clazz, Path path, int index) { @Override @Deprecated public Long jsonArrLen(String key) { - return checkAndClientSideCacheCommand(commandObjects.jsonArrLen(key), key); + return executeCommand(commandObjects.jsonArrLen(key)); } @Override public List jsonArrLen(String key, Path2 path) { - return checkAndClientSideCacheCommand(commandObjects.jsonArrLen(key, path), key); + return executeCommand(commandObjects.jsonArrLen(key, path)); } @Override @Deprecated public Long jsonArrLen(String key, Path path) { - return checkAndClientSideCacheCommand(commandObjects.jsonArrLen(key, path), key); + return executeCommand(commandObjects.jsonArrLen(key, path)); } @Override @@ -4427,35 +4425,35 @@ public Long jsonArrTrim(String key, Path path, int start, int stop) { @Override @Deprecated public Long jsonObjLen(String key) { - return checkAndClientSideCacheCommand(commandObjects.jsonObjLen(key), key); + return executeCommand(commandObjects.jsonObjLen(key)); } @Override @Deprecated public Long jsonObjLen(String key, Path path) { - return checkAndClientSideCacheCommand(commandObjects.jsonObjLen(key, path), key); + return executeCommand(commandObjects.jsonObjLen(key, path)); } @Override public List jsonObjLen(String key, Path2 path) { - return checkAndClientSideCacheCommand(commandObjects.jsonObjLen(key, path), key); + return executeCommand(commandObjects.jsonObjLen(key, path)); } @Override @Deprecated public List jsonObjKeys(String key) { - return checkAndClientSideCacheCommand(commandObjects.jsonObjKeys(key), key); + return executeCommand(commandObjects.jsonObjKeys(key)); } @Override @Deprecated public List jsonObjKeys(String key, Path path) { - return checkAndClientSideCacheCommand(commandObjects.jsonObjKeys(key, path), key); + return executeCommand(commandObjects.jsonObjKeys(key, path)); } @Override public List> jsonObjKeys(String key, Path2 path) { - return checkAndClientSideCacheCommand(commandObjects.jsonObjKeys(key, path), key); + return executeCommand(commandObjects.jsonObjKeys(key, path)); } @Override @@ -4554,22 +4552,22 @@ public long tsDecrBy(String key, double subtrahend, TSDecrByParams decrByParams) @Override public List tsRange(String key, long fromTimestamp, long toTimestamp) { - return checkAndClientSideCacheCommand(commandObjects.tsRange(key, fromTimestamp, toTimestamp), key); + return executeCommand(commandObjects.tsRange(key, fromTimestamp, toTimestamp)); } @Override public List tsRange(String key, TSRangeParams rangeParams) { - return checkAndClientSideCacheCommand(commandObjects.tsRange(key, rangeParams), key); + return executeCommand(commandObjects.tsRange(key, rangeParams)); } @Override public List tsRevRange(String key, long fromTimestamp, long toTimestamp) { - return checkAndClientSideCacheCommand(commandObjects.tsRevRange(key, fromTimestamp, toTimestamp), key); + return executeCommand(commandObjects.tsRevRange(key, fromTimestamp, toTimestamp)); } @Override public List tsRevRange(String key, TSRangeParams rangeParams) { - return checkAndClientSideCacheCommand(commandObjects.tsRevRange(key, rangeParams), key); + return executeCommand(commandObjects.tsRevRange(key, rangeParams)); } @Override @@ -4594,12 +4592,12 @@ public Map tsMRevRange(TSMRangeParams multiRangeParams @Override public TSElement tsGet(String key) { - return checkAndClientSideCacheCommand(commandObjects.tsGet(key), key); + return executeCommand(commandObjects.tsGet(key)); } @Override public TSElement tsGet(String key, TSGetParams getParams) { - return checkAndClientSideCacheCommand(commandObjects.tsGet(key, getParams), key); + return executeCommand(commandObjects.tsGet(key, getParams)); } @Override @@ -4614,7 +4612,8 @@ public String tsCreateRule(String sourceKey, String destKey, AggregationType agg @Override public String tsCreateRule(String sourceKey, String destKey, AggregationType aggregationType, long bucketDuration, long alignTimestamp) { - return executeCommand(commandObjects.tsCreateRule(sourceKey, destKey, aggregationType, bucketDuration, alignTimestamp)); + return executeCommand( + commandObjects.tsCreateRule(sourceKey, destKey, aggregationType, bucketDuration, alignTimestamp)); } @Override @@ -4629,7 +4628,7 @@ public List tsQueryIndex(String... filters) { @Override public TSInfo tsInfo(String key) { - return checkAndClientSideCacheCommand(commandObjects.tsInfo(key), key); + return executeCommand(commandObjects.tsInfo(key)); } @Override @@ -5108,7 +5107,8 @@ public Object sendCommand(byte[] sampleKey, ProtocolCommand cmd, byte[]... args) } public Object sendBlockingCommand(byte[] sampleKey, ProtocolCommand cmd, byte[]... args) { - return executeCommand(commandObjects.commandArguments(cmd).addObjects((Object[]) args).blocking().processKey(sampleKey)); + return executeCommand( + commandObjects.commandArguments(cmd).addObjects((Object[]) args).blocking().processKey(sampleKey)); } public Object sendCommand(String sampleKey, ProtocolCommand cmd, String... args) { @@ -5116,7 +5116,8 @@ public Object sendCommand(String sampleKey, ProtocolCommand cmd, String... args) } public Object sendBlockingCommand(String sampleKey, ProtocolCommand cmd, String... args) { - return executeCommand(commandObjects.commandArguments(cmd).addObjects((Object[]) args).blocking().processKey(sampleKey)); + return executeCommand( + commandObjects.commandArguments(cmd).addObjects((Object[]) args).blocking().processKey(sampleKey)); } public Object executeCommand(CommandArguments args) { diff --git a/src/main/java/redis/clients/jedis/csc/AbstractCache.java b/src/main/java/redis/clients/jedis/csc/AbstractCache.java new file mode 100644 index 0000000000..c5750d385b --- /dev/null +++ b/src/main/java/redis/clients/jedis/csc/AbstractCache.java @@ -0,0 +1,230 @@ +package redis.clients.jedis.csc; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; + +import redis.clients.jedis.annots.Experimental; +import redis.clients.jedis.util.SafeEncoder; + +/** + * The class to manage the client-side caching. User can provide any of implementation of this class + * to the client object; e.g. {@link redis.clients.jedis.csc.CaffeineClientSideCache + * CaffeineClientSideCache} or {@link redis.clients.jedis.csc.GuavaClientSideCache + * GuavaClientSideCache} or a custom implementation of their own. + */ +@Experimental +public abstract class AbstractCache implements Cache { + + private ClientSideCacheable cacheable; + private final Map>> redisKeysToCacheKeys = new ConcurrentHashMap<>(); + private final int maximumSize; + private ReentrantLock lock = new ReentrantLock(); + private volatile CacheStats stats = new CacheStats(); + + protected AbstractCache(int maximumSize) { + this(maximumSize, DefaultClientSideCacheable.INSTANCE); + } + + protected AbstractCache(int maximumSize, ClientSideCacheable cacheable) { + this.maximumSize = maximumSize; + this.cacheable = cacheable; + } + + // Cache interface methods + + @Override + public int getMaxSize() { + return maximumSize; + } + + @Override + public abstract int getSize(); + + @Override + public abstract Collection getCacheEntries(); + + @Override + public CacheEntry get(CacheKey cacheKey) { + CacheEntry entry = getFromStore(cacheKey); + if (entry != null) { + getEvictionPolicy().touch(cacheKey); + } + return entry; + } + + @Override + public CacheEntry set(CacheKey cacheKey, CacheEntry entry) { + lock.lock(); + try { + entry = putIntoStore(cacheKey, entry); + EvictionPolicy policy = getEvictionPolicy(); + policy.touch(cacheKey); + CacheKey evictedKey = policy.evictNext(); + if (evictedKey != null) { + delete(evictedKey); + stats.evict(); + } + for (Object redisKey : cacheKey.getRedisKeys()) { + ByteBuffer mapKey = makeKeyForRedisKeysToCacheKeys(redisKey); + if (redisKeysToCacheKeys.containsKey(mapKey)) { + redisKeysToCacheKeys.get(mapKey).add(cacheKey); + } else { + Set> set = ConcurrentHashMap.newKeySet(); + set.add(cacheKey); + redisKeysToCacheKeys.put(mapKey, set); + } + } + stats.load(); + return entry; + } finally { + lock.unlock(); + } + } + + @Override + public Boolean delete(CacheKey cacheKey) { + lock.lock(); + try { + boolean removed = removeFromStore(cacheKey); + getEvictionPolicy().reset(cacheKey); + + // removing it from redisKeysToCacheKeys as well + // TODO: considering not doing it, what is the impact of not doing it ?? + for (Object redisKey : cacheKey.getRedisKeys()) { + ByteBuffer mapKey = makeKeyForRedisKeysToCacheKeys(redisKey); + Set> cacheKeysRelatedtoRedisKey = redisKeysToCacheKeys.get(mapKey); + if (cacheKeysRelatedtoRedisKey != null) { + cacheKeysRelatedtoRedisKey.remove(cacheKey); + } + } + return removed; + } finally { + lock.unlock(); + } + } + + @Override + public List delete(List cacheKeys) { + lock.lock(); + try { + return cacheKeys.stream().map(this::delete).collect(Collectors.toList()); + } finally { + lock.unlock(); + } + } + + @Override + public List deleteByRedisKey(Object key) { + lock.lock(); + try { + final ByteBuffer mapKey = makeKeyForRedisKeysToCacheKeys(key); + + Set> commands = redisKeysToCacheKeys.get(mapKey); + List cacheKeys = new ArrayList<>(); + if (commands != null) { + cacheKeys.addAll(commands.stream().filter(this::removeFromStore).collect(Collectors.toList())); + stats.invalidationByServer(cacheKeys.size()); + redisKeysToCacheKeys.remove(mapKey); + } + stats.invalidationMessages(); + return cacheKeys; + } finally { + lock.unlock(); + } + } + + @Override + public List deleteByRedisKeys(List keys) { + if (keys == null) { + flush(); + return null; + } + lock.lock(); + try { + return ((List) keys).stream() + .map(this::deleteByRedisKey).flatMap(List::stream).collect(Collectors.toList()); + } finally { + lock.unlock(); + } + } + + @Override + public int flush() { + lock.lock(); + try { + int result = this.getSize(); + clearStore(); + redisKeysToCacheKeys.clear(); + getEvictionPolicy().resetAll(); + getStats().flush(); + return result; + } finally { + lock.unlock(); + } + } + + @Override + public Boolean isCacheable(CacheKey cacheKey) { + return cacheable.isCacheable(cacheKey.getCommand().getArguments().getCommand(), cacheKey.getRedisKeys()); + } + + @Override + public Boolean hasCacheKey(CacheKey cacheKey) { + return containsKeyInStore(cacheKey); + } + + @Override + public abstract EvictionPolicy getEvictionPolicy(); + + @Override + public CacheStats getStats() { + return stats; + } + + @Override + public CacheStats getAndResetStats() { + CacheStats result = stats; + stats = new CacheStats(); + return result; + } + + // End of Cache interface methods + + // abstract methods to be implemented by the concrete classes + protected abstract CacheEntry getFromStore(CacheKey cacheKey); + + protected abstract CacheEntry putIntoStore(CacheKey cacheKey, CacheEntry entry); + + protected abstract Boolean removeFromStore(CacheKey cacheKey); + + // protected abstract Collection remove(Set> commands); + + protected abstract void clearStore(); + + protected abstract Boolean containsKeyInStore(CacheKey cacheKey); + + // End of abstract methods to be implemented by the concrete classes + + private ByteBuffer makeKeyForRedisKeysToCacheKeys(Object key) { + if (key instanceof byte[]) { + return makeKeyForRedisKeysToCacheKeys((byte[]) key); + } else if (key instanceof String) { + return makeKeyForRedisKeysToCacheKeys(SafeEncoder.encode((String) key)); + } else { + throw new IllegalArgumentException(key.getClass().getSimpleName() + " is not supported." + + " Value: \"" + String.valueOf(key) + "\"."); + } + } + + private static ByteBuffer makeKeyForRedisKeysToCacheKeys(byte[] b) { + return ByteBuffer.wrap(b); + } + +} diff --git a/src/main/java/redis/clients/jedis/csc/Cache.java b/src/main/java/redis/clients/jedis/csc/Cache.java new file mode 100644 index 0000000000..3a7f801383 --- /dev/null +++ b/src/main/java/redis/clients/jedis/csc/Cache.java @@ -0,0 +1,108 @@ +package redis.clients.jedis.csc; + +import java.util.Collection; +import java.util.List; + +/** + * The cache that is used by a connection + */ +public interface Cache { + + /** + * @return The size of the cache + */ + int getMaxSize(); + + /** + * @return The current size of the cache + */ + int getSize(); + + /** + * @return All the entries within the cache + */ + Collection getCacheEntries(); + + /** + * Fetches a value from the cache + * + * @param cacheKey The key within the cache + * @return The entry within the cache + */ + CacheEntry get(CacheKey cacheKey); + + /** + * Puts a value into the cache + * + * @param cacheKey The key by which the value can be accessed within the cache + * @param value The value to be put into the cache + * @return The cache entry + */ + CacheEntry set(CacheKey cacheKey, CacheEntry value); + + /** + * Delete an entry by cache key + * @param cacheKey The cache key of the entry in the cache + * @return True if the entry could be deleted, false if the entry wasn't found. + */ + Boolean delete(CacheKey cacheKey); + + /** + * Delete entries by cache key from the cache + * + * @param cacheKeys The cache keys of the entries that should be deleted + * @return True for every entry that could be deleted. False if the entry was not there. + */ + List delete(List cacheKeys); + + /** + * Delete an entry by the Redis key from the cache + * + * @param key The Redis key as binary + * @return True if the entry could be deleted. False if the entry was not there. + */ + List deleteByRedisKey(Object key); + + /** + * Delete entries by the Redis key from the cache + * + * @param keys The Redis keys as binaries + * @return True for every entry that could be deleted. False if the entry was not there. + */ + List deleteByRedisKeys(List keys); + + /** + * Flushes the entire cache + * + * @return Return the number of entries that were flushed + */ + int flush(); + + /** + * @param cacheKey The key of the cache entry + * @return True if the entry is cachable, false otherwise + */ + Boolean isCacheable(CacheKey cacheKey); + + /** + * + * @param cacheKey The key of the cache entry + * @return True if the cache already contains the key + */ + Boolean hasCacheKey(CacheKey cacheKey); + + /** + * @return The eviction policy that is used by the cache + */ + EvictionPolicy getEvictionPolicy(); + + /** + * @return The statistics of the cache + */ + public CacheStats getStats(); + + /** + * @return The statistics of the cache + */ + public CacheStats getAndResetStats(); +} diff --git a/src/main/java/redis/clients/jedis/csc/CacheConnection.java b/src/main/java/redis/clients/jedis/csc/CacheConnection.java index 0573cc1093..e5851e7140 100644 --- a/src/main/java/redis/clients/jedis/csc/CacheConnection.java +++ b/src/main/java/redis/clients/jedis/csc/CacheConnection.java @@ -1,7 +1,9 @@ package redis.clients.jedis.csc; +import java.lang.ref.WeakReference; import java.util.Objects; import java.util.concurrent.locks.ReentrantLock; +import redis.clients.jedis.CommandObject; import redis.clients.jedis.Connection; import redis.clients.jedis.JedisClientConfig; import redis.clients.jedis.JedisSocketFactory; @@ -12,12 +14,10 @@ public class CacheConnection extends Connection { - private final ClientSideCache clientSideCache; - private final ReentrantLock lock; - - public CacheConnection(final JedisSocketFactory socketFactory, JedisClientConfig clientConfig, - ClientSideCache clientSideCache) { + private final Cache clientSideCache; + private ReentrantLock lock; + public CacheConnection(final JedisSocketFactory socketFactory, JedisClientConfig clientConfig, Cache clientSideCache) { super(socketFactory, clientConfig); if (protocol != RedisProtocol.RESP3) { @@ -25,37 +25,73 @@ public CacheConnection(final JedisSocketFactory socketFactory, JedisClientConfig } this.clientSideCache = Objects.requireNonNull(clientSideCache); initializeClientSideCache(); + } + @Override + protected void initializeFromClientConfig(JedisClientConfig config) { lock = new ReentrantLock(); + super.initializeFromClientConfig(config); } @Override protected Object protocolRead(RedisInputStream inputStream) { - if (lock != null) { - lock.lock(); - try { - return Protocol.read(inputStream); - } finally { - lock.unlock(); - } - } else { - return Protocol.read(inputStream); + lock.lock(); + try { + return Protocol.read(inputStream, clientSideCache); + } finally { + lock.unlock(); } } @Override protected void protocolReadPushes(RedisInputStream inputStream) { - if (lock != null && lock.tryLock()) { + if (lock.tryLock()) { try { - //super.setSoTimeout(1); - Protocol.readPushes(inputStream, clientSideCache); + Protocol.readPushes(inputStream, clientSideCache, true); } finally { - //super.rollbackTimeout(); lock.unlock(); } } } + @Override + public void disconnect() { + super.disconnect(); + clientSideCache.flush(); + } + + @Override + public T executeCommand(final CommandObject commandObject) { + CacheKey key = new CacheKey<>(commandObject); + if (!clientSideCache.isCacheable(key)) { + clientSideCache.getStats().nonCacheable(); + return super.executeCommand(commandObject); + } + + final CacheKey cacheKey = new CacheKey(commandObject); + CacheEntry cacheEntry = clientSideCache.get(cacheKey); + + // CACHE HIT !! + if (cacheEntry != null) { + cacheEntry = validateEntry(cacheEntry); + if (cacheEntry != null) { + clientSideCache.getStats().hit(); + return (T) cacheEntry.getValue(); + } + } + + // CACHE MISS!! + clientSideCache.getStats().miss(); + T value = super.executeCommand(commandObject); + if (value != null) { + cacheEntry = new CacheEntry(cacheKey, value, new WeakReference(this)); + clientSideCache.set(cacheKey, cacheEntry); + // this line actually provides a deep copy of cached object instance + value = cacheEntry.getValue(); + } + return value; + } + private void initializeClientSideCache() { sendCommand(Protocol.Command.CLIENT, "TRACKING", "ON"); String reply = getStatusCodeReply(); @@ -63,4 +99,21 @@ private void initializeClientSideCache() { throw new JedisException("Could not enable client tracking. Reply: " + reply); } } + + private CacheEntry validateEntry(CacheEntry cacheEntry) { + CacheConnection cacheOwner = (CacheConnection) cacheEntry.getConnection().get(); + if (cacheOwner == null || cacheOwner.isBroken() || !cacheOwner.isConnected()) { + clientSideCache.delete(cacheEntry.getCacheKey()); + return null; + } else { + try { + cacheOwner.readPushesWithCheckingBroken(); + } catch (JedisException e) { + clientSideCache.delete(cacheEntry.getCacheKey()); + return null; + } + + return clientSideCache.get(cacheEntry.getCacheKey()); + } + } } diff --git a/src/main/java/redis/clients/jedis/csc/CacheEntry.java b/src/main/java/redis/clients/jedis/csc/CacheEntry.java index f2a3243cf4..c0de029db3 100644 --- a/src/main/java/redis/clients/jedis/csc/CacheEntry.java +++ b/src/main/java/redis/clients/jedis/csc/CacheEntry.java @@ -1,19 +1,27 @@ package redis.clients.jedis.csc; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.ref.WeakReference; + import redis.clients.jedis.Connection; import redis.clients.jedis.annots.Internal; +import redis.clients.jedis.exceptions.JedisCacheException; @Internal public class CacheEntry { private final CacheKey cacheKey; - private final T value; - private final Connection connection; + private final WeakReference connection; + private final byte[] bytes; - public CacheEntry(CacheKey cacheKey, T value, Connection connection) { + public CacheEntry(CacheKey cacheKey, T value, WeakReference connection) { this.cacheKey = cacheKey; - this.value = value; this.connection = connection; + this.bytes = toBytes(value); } public CacheKey getCacheKey() { @@ -21,10 +29,33 @@ public CacheKey getCacheKey() { } public T getValue() { - return value; + return toObject(bytes); } - public Connection getConnection() { + public WeakReference getConnection() { return connection; } + + private static byte[] toBytes(Object object) { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(object); + oos.flush(); + oos.close(); + return baos.toByteArray(); + } catch (IOException e) { + throw new JedisCacheException("Failed to serialize object", e); + } + } + + private T toObject(byte[] data) { + try (ByteArrayInputStream bais = new ByteArrayInputStream(data); + ObjectInputStream ois = new ObjectInputStream(bais)) { + return (T) ois.readObject(); + } catch (IOException e) { + throw new JedisCacheException("Failed to deserialize object", e); + } catch (ClassNotFoundException e) { + throw new JedisCacheException("Failed to deserialize object", e); + } + } } diff --git a/src/main/java/redis/clients/jedis/csc/CacheKey.java b/src/main/java/redis/clients/jedis/csc/CacheKey.java index b3e8244b20..4e854550fe 100644 --- a/src/main/java/redis/clients/jedis/csc/CacheKey.java +++ b/src/main/java/redis/clients/jedis/csc/CacheKey.java @@ -25,4 +25,12 @@ public boolean equals(Object obj) { final CacheKey other = (CacheKey) obj; return Objects.equals(this.command, other.command); } + + public Object[] getRedisKeys() { + return command.getArguments().getKeys(); + } + + public CommandObject getCommand() { + return command; + } } diff --git a/src/main/java/redis/clients/jedis/csc/CacheStats.java b/src/main/java/redis/clients/jedis/csc/CacheStats.java new file mode 100644 index 0000000000..e689ea0d77 --- /dev/null +++ b/src/main/java/redis/clients/jedis/csc/CacheStats.java @@ -0,0 +1,89 @@ +package redis.clients.jedis.csc; + +import java.util.concurrent.atomic.AtomicLong; + +public class CacheStats { + + private AtomicLong hits = new AtomicLong(0); + private AtomicLong misses = new AtomicLong(0); + private AtomicLong loads = new AtomicLong(0); + private AtomicLong evicts = new AtomicLong(0); + private AtomicLong nonCacheable = new AtomicLong(0); + private AtomicLong flush = new AtomicLong(0); + private AtomicLong invalidationsByServer = new AtomicLong(0); + private AtomicLong invalidationMessages = new AtomicLong(0); + + protected void hit() { + hits.incrementAndGet(); + } + + protected void miss() { + misses.incrementAndGet(); + } + + protected void load() { + loads.incrementAndGet(); + } + + protected void evict() { + evicts.incrementAndGet(); + } + + protected void nonCacheable() { + nonCacheable.incrementAndGet(); + } + + protected void flush() { + flush.incrementAndGet(); + } + + protected void invalidationByServer(int size) { + invalidationsByServer.addAndGet(size); + } + + protected void invalidationMessages() { + invalidationMessages.incrementAndGet(); + } + + public long getHitCount() { + return hits.get(); + } + + public long getMissCount() { + return misses.get(); + } + + public long getLoadCount() { + return loads.get(); + } + + public long getEvictCount() { + return evicts.get(); + } + + public long getNonCacheableCount() { + return nonCacheable.get(); + } + + public long getFlushCount() { + return flush.get(); + } + + public long getInvalidationCount() { + return invalidationsByServer.get(); + } + + public String toString() { + return "CacheStats{" + + "hits=" + hits + + ", misses=" + misses + + ", loads=" + loads + + ", evicts=" + evicts + + ", nonCacheable=" + nonCacheable + + ", flush=" + flush + + ", invalidationsByServer=" + invalidationsByServer + + ", invalidationMessages=" + invalidationMessages + + '}'; + } + +} diff --git a/src/main/java/redis/clients/jedis/csc/CaffeineClientSideCache.java b/src/main/java/redis/clients/jedis/csc/CaffeineClientSideCache.java index fe320418e9..85627dba29 100644 --- a/src/main/java/redis/clients/jedis/csc/CaffeineClientSideCache.java +++ b/src/main/java/redis/clients/jedis/csc/CaffeineClientSideCache.java @@ -2,66 +2,70 @@ import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; -import java.util.concurrent.TimeUnit; -public class CaffeineClientSideCache extends ClientSideCache { +import redis.clients.jedis.annots.Experimental; + +import java.util.Collection; + +@Experimental +public class CaffeineClientSideCache extends AbstractCache { private final Cache cache; + private final EvictionPolicy evictionPolicy; - public CaffeineClientSideCache(Cache caffeineCache) { - this.cache = caffeineCache; + public CaffeineClientSideCache(int maximumSize) { + this(maximumSize, new LRUEviction(maximumSize)); } - @Override - protected final void clear() { - cache.invalidateAll(); + public CaffeineClientSideCache(int maximumSize, EvictionPolicy evictionPolicy) { + super(maximumSize); + this.cache = Caffeine.newBuilder().build(); + this.evictionPolicy = evictionPolicy; + this.evictionPolicy.setCache(this); } @Override - protected void remove(Iterable> keys) { - cache.invalidateAll(keys); + protected final void clearStore() { + cache.invalidateAll(); } @Override - protected void put(CacheKey key, CacheEntry entry) { + public CacheEntry putIntoStore(CacheKey key, CacheEntry entry) { cache.put(key, entry); + return entry; } @Override - protected CacheEntry get(CacheKey key) { + public CacheEntry getFromStore(CacheKey key) { return cache.getIfPresent(key); } - public static Builder builder() { - return new Builder(); - } - - public static class Builder { - - private long maximumSize = DEFAULT_MAXIMUM_SIZE; - private long expireTime = DEFAULT_EXPIRE_SECONDS; - private final TimeUnit expireTimeUnit = TimeUnit.SECONDS; - - private Builder() { } - - public Builder maximumSize(int size) { - this.maximumSize = size; - return this; - } + // TODO: we should discuss if/how we utilize Caffeine and get back to here ! - public Builder ttl(int seconds) { - this.expireTime = seconds; - return this; - } + @Override + public int getSize() { + return (int) cache.estimatedSize(); + } - public CaffeineClientSideCache build() { - Caffeine cb = Caffeine.newBuilder(); + @Override + public Collection getCacheEntries() { + throw new UnsupportedOperationException("Unimplemented method 'getCacheEntries'"); + } - cb.maximumSize(maximumSize); + @Override + public EvictionPolicy getEvictionPolicy() { + return this.evictionPolicy; + } - cb.expireAfterWrite(expireTime, expireTimeUnit); + @Override + protected Boolean removeFromStore(CacheKey cacheKey) { + cache.invalidate(cacheKey); + return true; + } - return new CaffeineClientSideCache(cb.build()); - } + @Override + protected Boolean containsKeyInStore(CacheKey cacheKey) { + return cache.getIfPresent(cacheKey) != null; } + } diff --git a/src/main/java/redis/clients/jedis/csc/ClientSideCache.java b/src/main/java/redis/clients/jedis/csc/ClientSideCache.java deleted file mode 100644 index 94a235873d..0000000000 --- a/src/main/java/redis/clients/jedis/csc/ClientSideCache.java +++ /dev/null @@ -1,132 +0,0 @@ -package redis.clients.jedis.csc; - -import java.nio.ByteBuffer; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; - -import redis.clients.jedis.CommandObject; -import redis.clients.jedis.annots.Experimental; -import redis.clients.jedis.util.SafeEncoder; - -/** - * The class to manage the client-side caching. User can provide any of implementation of this class to the client - * object; e.g. {@link redis.clients.jedis.csc.CaffeineClientSideCache CaffeineClientSideCache} or - * {@link redis.clients.jedis.csc.GuavaClientSideCache GuavaClientSideCache} or a custom implementation of their own. - */ -@Experimental -public abstract class ClientSideCache { - - protected static final int DEFAULT_MAXIMUM_SIZE = 10_000; - protected static final int DEFAULT_EXPIRE_SECONDS = 100; - - private final Map>> redisKeysToCacheKeys = new ConcurrentHashMap<>(); - private ClientSideCacheable cacheable = DefaultClientSideCacheable.INSTANCE; // TODO: volatile - - protected ClientSideCache() { - } - - public void setCacheable(ClientSideCacheable cacheable) { - this.cacheable = Objects.requireNonNull(cacheable, "'cacheable' must not be null"); - } - - protected abstract void clear(); - - protected abstract void remove(Iterable> keys); - - protected abstract void put(CacheKey key, CacheEntry entry); - - protected abstract CacheEntry get(CacheKey key); - - public final void flush() { - invalidateAllRedisKeysAndCacheEntries(); - } - - public final void invalidateKey(Object key) { - invalidateRedisKeyAndRespectiveCacheEntries(key); - } - - public final void invalidate(List list) { - if (list == null) { - invalidateAllRedisKeysAndCacheEntries(); - return; - } - - list.forEach(this::invalidateRedisKeyAndRespectiveCacheEntries); - } - - private void invalidateAllRedisKeysAndCacheEntries() { - clear(); - redisKeysToCacheKeys.clear(); - } - - private void invalidateRedisKeyAndRespectiveCacheEntries(Object key) { -// if (!(key instanceof byte[])) { -// // This should be called internally. That's why throwing AssertionError instead of IllegalArgumentException. -// throw new AssertionError("" + key.getClass().getSimpleName() + " is not supported. Value: " + String.valueOf(key)); -// } -// -// final ByteBuffer mapKey = makeKeyForKeyToCommandHashes((byte[]) key); - final ByteBuffer mapKey = makeKeyForRedisKeysToCacheKeys(key); - - Set> commands = redisKeysToCacheKeys.get(mapKey); - if (commands != null) { - remove(commands); - redisKeysToCacheKeys.remove(mapKey); - } - } - - public final T get(Function, T> loader, CommandObject command, Object... keys) { - - if (!cacheable.isCacheable(command.getArguments().getCommand(), keys)) { - return loader.apply(command); - } - - final CacheKey cacheKey = new CacheKey(command); - CacheEntry cacheEntry = get(cacheKey); - if (cacheEntry != null) { - // CACHE HIT!!! - // TODO: connection ... - //cacheEntry.getConnection().ping(); - //cacheEntry = get(cacheKey); // get cache again - return (T) cacheEntry.getValue(); - } - - // CACHE MISS!! - T value = loader.apply(command); - if (value != null) { - cacheEntry = new CacheEntry(cacheKey, value, /*connection*/ null); // TODO: connection - put(cacheKey, cacheEntry); - for (Object key : keys) { - ByteBuffer mapKey = makeKeyForRedisKeysToCacheKeys(key); - if (redisKeysToCacheKeys.containsKey(mapKey)) { - redisKeysToCacheKeys.get(mapKey).add(cacheKey); - } else { - Set> set = ConcurrentHashMap.newKeySet(); - set.add(cacheKey); - redisKeysToCacheKeys.put(mapKey, set); - } - } - } - - return value; - } - - private ByteBuffer makeKeyForRedisKeysToCacheKeys(Object key) { - if (key instanceof byte[]) { - return makeKeyForRedisKeysToCacheKeys((byte[]) key); - } else if (key instanceof String) { - return makeKeyForRedisKeysToCacheKeys(SafeEncoder.encode((String) key)); - } else { - throw new IllegalArgumentException(key.getClass().getSimpleName() + " is not supported." - + " Value: \"" + String.valueOf(key) + "\"."); - } - } - - private static ByteBuffer makeKeyForRedisKeysToCacheKeys(byte[] b) { - return ByteBuffer.wrap(b); - } -} diff --git a/src/main/java/redis/clients/jedis/csc/DefaultCache.java b/src/main/java/redis/clients/jedis/csc/DefaultCache.java new file mode 100644 index 0000000000..a382dc7623 --- /dev/null +++ b/src/main/java/redis/clients/jedis/csc/DefaultCache.java @@ -0,0 +1,71 @@ +package redis.clients.jedis.csc; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public class DefaultCache extends AbstractCache { + + protected final Map cache; + private final EvictionPolicy evictionPolicy; + + public DefaultCache(int maximumSize) { + this(maximumSize, new HashMap()); + } + + public DefaultCache(int maximumSize, Map map) { + this(maximumSize, map, DefaultClientSideCacheable.INSTANCE, new LRUEviction(maximumSize)); + } + + public DefaultCache(int maximumSize, ClientSideCacheable cacheable) { + this(maximumSize, new HashMap(), cacheable, new LRUEviction(maximumSize)); + } + + public DefaultCache(int maximumSize, Map map, ClientSideCacheable cacheable, EvictionPolicy evictionPolicy) { + super(maximumSize, cacheable); + this.cache = map; + this.evictionPolicy = evictionPolicy; + this.evictionPolicy.setCache(this); + } + + @Override + public int getSize() { + return cache.size(); + } + + @Override + public Collection getCacheEntries() { + return cache.values(); + } + + @Override + public EvictionPolicy getEvictionPolicy() { + return this.evictionPolicy; + } + + @Override + public CacheEntry getFromStore(CacheKey key) { + return cache.get(key); + } + + @Override + public CacheEntry putIntoStore(CacheKey key, CacheEntry entry) { + return cache.put(key, entry); + } + + @Override + public Boolean removeFromStore(CacheKey key) { + return cache.remove(key) != null; + } + + @Override + protected final void clearStore() { + cache.clear(); + } + + @Override + protected Boolean containsKeyInStore(CacheKey cacheKey) { + return cache.containsKey(cacheKey); + } + +} \ No newline at end of file diff --git a/src/main/java/redis/clients/jedis/csc/DefaultClientSideCacheable.java b/src/main/java/redis/clients/jedis/csc/DefaultClientSideCacheable.java index d97ca6a2ee..b510b5bf0d 100644 --- a/src/main/java/redis/clients/jedis/csc/DefaultClientSideCacheable.java +++ b/src/main/java/redis/clients/jedis/csc/DefaultClientSideCacheable.java @@ -1,15 +1,94 @@ package redis.clients.jedis.csc; +import java.util.HashMap; +import java.util.Map; + +import redis.clients.jedis.Protocol.Command; import redis.clients.jedis.commands.ProtocolCommand; +import redis.clients.jedis.json.JsonProtocol.JsonCommand; +import redis.clients.jedis.timeseries.TimeSeriesProtocol.TimeSeriesCommand; public class DefaultClientSideCacheable implements ClientSideCacheable { public static final DefaultClientSideCacheable INSTANCE = new DefaultClientSideCacheable(); - public DefaultClientSideCacheable() { } + private Map commandsToCache = new HashMap() { + { + put(Command.BITCOUNT, true); + put(Command.BITFIELD_RO, true); + put(Command.BITPOS, true); + put(Command.EXISTS, true); + put(Command.GEODIST, true); + put(Command.GEOHASH, true); + put(Command.GEOPOS, true); + put(Command.GEORADIUSBYMEMBER_RO, true); + put(Command.GEORADIUS_RO, true); + put(Command.GEOSEARCH, true); + put(Command.GET, true); + put(Command.GETBIT, true); + put(Command.GETRANGE, true); + put(Command.HEXISTS, true); + put(Command.HGET, true); + put(Command.HGETALL, true); + put(Command.HKEYS, true); + put(Command.HLEN, true); + put(Command.HMGET, true); + put(Command.HSTRLEN, true); + put(Command.HVALS, true); + put(JsonCommand.ARRINDEX, true); + put(JsonCommand.ARRLEN, true); + put(JsonCommand.GET, true); + put(JsonCommand.MGET, true); + put(JsonCommand.OBJKEYS, true); + put(JsonCommand.OBJLEN, true); + put(JsonCommand.STRLEN, true); + put(JsonCommand.TYPE, true); + put(Command.LCS, true); + put(Command.LINDEX, true); + put(Command.LLEN, true); + put(Command.LPOS, true); + put(Command.LRANGE, true); + put(Command.MGET, true); + put(Command.SCARD, true); + put(Command.SDIFF, true); + put(Command.SINTER, true); + put(Command.SISMEMBER, true); + put(Command.SMEMBERS, true); + put(Command.SMISMEMBER, true); + put(Command.STRLEN, true); + put(Command.SUBSTR, true); + put(Command.SUNION, true); + put(TimeSeriesCommand.GET, true); + put(TimeSeriesCommand.INFO, true); + put(TimeSeriesCommand.RANGE, true); + put(TimeSeriesCommand.REVRANGE, true); + put(Command.TYPE, true); + put(Command.XLEN, true); + put(Command.XPENDING, true); + put(Command.XRANGE, true); + put(Command.XREVRANGE, true); + put(Command.ZCARD, true); + put(Command.ZCOUNT, true); + put(Command.ZLEXCOUNT, true); + put(Command.ZMSCORE, true); + put(Command.ZRANGE, true); + put(Command.ZRANGEBYLEX, true); + put(Command.ZRANGEBYSCORE, true); + put(Command.ZRANK, true); + put(Command.ZREVRANGE, true); + put(Command.ZREVRANGEBYLEX, true); + put(Command.ZREVRANGEBYSCORE, true); + put(Command.ZREVRANK, true); + put(Command.ZSCORE, true); + } + }; + + public DefaultClientSideCacheable() { + } @Override public boolean isCacheable(ProtocolCommand command, Object... keys) { - return true; + Boolean cachable = commandsToCache.get(command); + return (cachable != null) ? cachable : false; } } diff --git a/src/main/java/redis/clients/jedis/csc/EvictionPolicy.java b/src/main/java/redis/clients/jedis/csc/EvictionPolicy.java new file mode 100644 index 0000000000..217b04263e --- /dev/null +++ b/src/main/java/redis/clients/jedis/csc/EvictionPolicy.java @@ -0,0 +1,77 @@ +package redis.clients.jedis.csc; + +import java.util.List; + +/** + * Describes the properties and functionality of an eviction policy + *

+ * One policy instance belongs to exactly one cache instance + */ +public interface EvictionPolicy { + + /** + * Types of eviction policies + * + * AGE - based on the time of access, e.g., LRU + * FREQ - based on the frequency of access, e.g., LFU + * HYBR - AGE + FREQ, e.g., CLOCK + * MISC - Anythin that isn't time based, frequency based or a combination of the two, e.g., FIFO + */ + enum EvictionType { + AGE, FREQ, HYBR, MISC + } + + /** + * @return The cache that is associated to this policy instance + */ + Cache getCache(); + + /** + * Sets the cache that is associated to this policy instance + * @param cache The cache instance + */ + void setCache(Cache cache); + + /** + * @return The type of policy + */ + EvictionType getType(); + + /** + * @return The name of the policy + */ + String getName(); + + /** + * Evict the next element from the cache + * This one should provide O(1) complexity + * @return The key of the entry that was evicted + */ + CacheKey evictNext(); + + /** + * + * @param n The number of entries to evict + * @return The list of keys of evicted entries + */ + List evictMany(int n); + + /** + * Indicates that a cache key was touched + * This one should provide O(1) complexity + * @param cacheKey The key within the cache + */ + void touch(CacheKey cacheKey); + + /** + * Resets the state that the eviction policy maintains about the cache key + * @param cacheKey + */ + boolean reset(CacheKey cacheKey); + + /** + * Resets the entire state of the eviction data + * @return True if the reset could be performed successfully + */ + int resetAll(); +} diff --git a/src/main/java/redis/clients/jedis/csc/GuavaClientSideCache.java b/src/main/java/redis/clients/jedis/csc/GuavaClientSideCache.java index 8adfc69b26..81853ad651 100644 --- a/src/main/java/redis/clients/jedis/csc/GuavaClientSideCache.java +++ b/src/main/java/redis/clients/jedis/csc/GuavaClientSideCache.java @@ -2,67 +2,79 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; -import java.util.concurrent.TimeUnit; -public class GuavaClientSideCache extends ClientSideCache { +import redis.clients.jedis.annots.Experimental; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +@Experimental +public class GuavaClientSideCache extends AbstractCache { private final Cache cache; + private final EvictionPolicy evictionPolicy; - public GuavaClientSideCache(Cache guavaCache) { - super(); - this.cache = guavaCache; + public GuavaClientSideCache(int maximumSize) { + this(maximumSize, new LRUEviction(maximumSize)); + } + + public GuavaClientSideCache(int maximumSize, EvictionPolicy evictionPolicy) { + super(maximumSize); + this.cache = CacheBuilder.newBuilder().build(); + this.evictionPolicy = evictionPolicy; + this.evictionPolicy.setCache(this); } @Override - protected final void clear() { + public final void clearStore() { cache.invalidateAll(); } - @Override - protected void remove(Iterable> keys) { + public List remove(Iterable> keys) { cache.invalidateAll(keys); + return StreamSupport.stream(keys.spliterator(), false) + .collect(Collectors.toList()); } @Override - protected void put(CacheKey key, CacheEntry entry) { + public CacheEntry putIntoStore(CacheKey key, CacheEntry entry) { cache.put(key, entry); + return entry; } @Override - protected CacheEntry get(CacheKey key) { + public CacheEntry getFromStore(CacheKey key) { return cache.getIfPresent(key); } - public static Builder builder() { - return new Builder(); - } - - public static class Builder { - - private long maximumSize = DEFAULT_MAXIMUM_SIZE; - private long expireTime = DEFAULT_EXPIRE_SECONDS; - private final TimeUnit expireTimeUnit = TimeUnit.SECONDS; - - private Builder() { } - - public Builder maximumSize(int size) { - this.maximumSize = size; - return this; - } + // TODO: we should discuss if/how we utilize Guava and get back to here ! - public Builder ttl(int seconds) { - this.expireTime = seconds; - return this; - } + @Override + public int getSize() { + return (int) cache.size(); + } - public GuavaClientSideCache build() { - CacheBuilder cb = CacheBuilder.newBuilder(); + @Override + public Collection getCacheEntries() { + throw new UnsupportedOperationException("Unimplemented method 'getCacheEntries'"); + } - cb.maximumSize(maximumSize); + @Override + public EvictionPolicy getEvictionPolicy() { + return this.evictionPolicy; + } - cb.expireAfterWrite(expireTime, expireTimeUnit); + @Override + protected Boolean removeFromStore(CacheKey cacheKey) { + cache.invalidate(cacheKey); + return true; + } - return new GuavaClientSideCache(cb.build()); - } + @Override + protected Boolean containsKeyInStore(CacheKey cacheKey) { + return cache.getIfPresent(cacheKey) != null; } + } diff --git a/src/main/java/redis/clients/jedis/csc/LRUEviction.java b/src/main/java/redis/clients/jedis/csc/LRUEviction.java new file mode 100644 index 0000000000..b75c7338ba --- /dev/null +++ b/src/main/java/redis/clients/jedis/csc/LRUEviction.java @@ -0,0 +1,106 @@ +package redis.clients.jedis.csc; + +import java.util.*; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * Simple L(east) R(ecently) U(sed) eviction policy + * ATTENTION: this class is not thread safe + */ +public class LRUEviction implements EvictionPolicy { + + // For future reference, in case there is a need to make it thread safe, + // the LinkedHashMap can be wrapped in a Collections.synchronizedMap + + /** + * The cache that is associated to that policy instance + */ + protected Cache cache; + protected LinkedHashMap accessTimes; + + protected ArrayDeque pendingEvictions = new ArrayDeque(); + + protected ConcurrentLinkedQueue msg = new ConcurrentLinkedQueue(); + + private int initialCapacity; + + /** + * Constructor that gets the cache passed + * + * @param initialCapacity + */ + public LRUEviction(int initialCapacity) { + this.initialCapacity = initialCapacity; + } + + @Override + public void setCache(Cache cache) { + this.cache = cache; + this.accessTimes = new LinkedHashMap(initialCapacity, 1f, true) { + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + boolean evictionRequired = cache.getSize() > cache.getMaxSize() + || accessTimes.size() > cache.getMaxSize(); + // here the cache check is only for performance gain; we are trying to avoid the sequence add + poll + hasCacheKey + // and prefer to check it in cache once in early stage. + // if there is nothing to remove in actual cache as of now, stop worrying about it. + if (evictionRequired && cache.hasCacheKey(eldest.getKey())) { + pendingEvictions.addLast(eldest.getKey()); + + } + return evictionRequired; + } + }; + } + + @Override + public Cache getCache() { + return this.cache; + } + + @Override + public EvictionType getType() { + return EvictionType.AGE; + } + + @Override + public String getName() { + return "Simple L(east) R(ecently) U(sed)"; + } + + @Override + public synchronized CacheKey evictNext() { + CacheKey cacheKey = pendingEvictions.pollFirst(); + while (cacheKey != null && !cache.hasCacheKey(cacheKey)) { + cacheKey = pendingEvictions.pollFirst(); + } + return cacheKey; + } + + @Override + public synchronized List evictMany(int n) { + List result = new ArrayList<>(); + for (int i = 0; i < n; i++) { + result.add(this.evictNext()); + } + return result; + } + + @Override + public synchronized void touch(CacheKey cacheKey) { + this.accessTimes.put(cacheKey, new Date().getTime()); + } + + @Override + public synchronized boolean reset(CacheKey cacheKey) { + return this.accessTimes.remove(cacheKey) != null; + } + + @Override + public synchronized int resetAll() { + int result = this.accessTimes.size(); + accessTimes.clear(); + return result; + } + +} diff --git a/src/main/java/redis/clients/jedis/csc/util/AllowAndDenyListWithStringKeys.java b/src/main/java/redis/clients/jedis/csc/util/AllowAndDenyListWithStringKeys.java index e9adbea37c..f0167bc532 100644 --- a/src/main/java/redis/clients/jedis/csc/util/AllowAndDenyListWithStringKeys.java +++ b/src/main/java/redis/clients/jedis/csc/util/AllowAndDenyListWithStringKeys.java @@ -2,9 +2,9 @@ import java.util.Set; import redis.clients.jedis.commands.ProtocolCommand; -import redis.clients.jedis.csc.ClientSideCacheable; +import redis.clients.jedis.csc.DefaultClientSideCacheable; -public class AllowAndDenyListWithStringKeys implements ClientSideCacheable { +public class AllowAndDenyListWithStringKeys extends DefaultClientSideCacheable { private final Set allowCommands; private final Set denyCommands; @@ -22,15 +22,20 @@ public AllowAndDenyListWithStringKeys(Set allowCommands, Set clusterNodes, JedisClientConfi } @Experimental - public ClusterConnectionProvider(Set clusterNodes, JedisClientConfig clientConfig, ClientSideCache clientSideCache) { + public ClusterConnectionProvider(Set clusterNodes, JedisClientConfig clientConfig, Cache clientSideCache) { this.cache = new JedisClusterInfoCache(clientConfig, clientSideCache, clusterNodes); initializeSlotsCache(clusterNodes, clientConfig); } @@ -44,7 +44,7 @@ public ClusterConnectionProvider(Set clusterNodes, JedisClientConfi } @Experimental - public ClusterConnectionProvider(Set clusterNodes, JedisClientConfig clientConfig, ClientSideCache clientSideCache, + public ClusterConnectionProvider(Set clusterNodes, JedisClientConfig clientConfig, Cache clientSideCache, GenericObjectPoolConfig poolConfig) { this.cache = new JedisClusterInfoCache(clientConfig, clientSideCache, poolConfig, clusterNodes); initializeSlotsCache(clusterNodes, clientConfig); @@ -57,7 +57,7 @@ public ClusterConnectionProvider(Set clusterNodes, JedisClientConfi } @Experimental - public ClusterConnectionProvider(Set clusterNodes, JedisClientConfig clientConfig, ClientSideCache clientSideCache, + public ClusterConnectionProvider(Set clusterNodes, JedisClientConfig clientConfig, Cache clientSideCache, GenericObjectPoolConfig poolConfig, Duration topologyRefreshPeriod) { this.cache = new JedisClusterInfoCache(clientConfig, clientSideCache, poolConfig, clusterNodes, topologyRefreshPeriod); initializeSlotsCache(clusterNodes, clientConfig); diff --git a/src/main/java/redis/clients/jedis/providers/PooledConnectionProvider.java b/src/main/java/redis/clients/jedis/providers/PooledConnectionProvider.java index 14d1b2c9da..ddbd768f9b 100644 --- a/src/main/java/redis/clients/jedis/providers/PooledConnectionProvider.java +++ b/src/main/java/redis/clients/jedis/providers/PooledConnectionProvider.java @@ -12,7 +12,7 @@ import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisClientConfig; import redis.clients.jedis.annots.Experimental; -import redis.clients.jedis.csc.ClientSideCache; +import redis.clients.jedis.csc.Cache; import redis.clients.jedis.util.Pool; public class PooledConnectionProvider implements ConnectionProvider { @@ -31,7 +31,7 @@ public PooledConnectionProvider(HostAndPort hostAndPort, JedisClientConfig clien } @Experimental - public PooledConnectionProvider(HostAndPort hostAndPort, JedisClientConfig clientConfig, ClientSideCache clientSideCache) { + public PooledConnectionProvider(HostAndPort hostAndPort, JedisClientConfig clientConfig, Cache clientSideCache) { this(new ConnectionPool(hostAndPort, clientConfig, clientSideCache)); this.connectionMapKey = hostAndPort; } @@ -43,7 +43,7 @@ public PooledConnectionProvider(HostAndPort hostAndPort, JedisClientConfig clien } @Experimental - public PooledConnectionProvider(HostAndPort hostAndPort, JedisClientConfig clientConfig, ClientSideCache clientSideCache, + public PooledConnectionProvider(HostAndPort hostAndPort, JedisClientConfig clientConfig, Cache clientSideCache, GenericObjectPoolConfig poolConfig) { this(new ConnectionPool(hostAndPort, clientConfig, clientSideCache, poolConfig)); this.connectionMapKey = hostAndPort; diff --git a/src/main/java/redis/clients/jedis/providers/SentineledConnectionProvider.java b/src/main/java/redis/clients/jedis/providers/SentineledConnectionProvider.java index 8a16d3e2e4..dedf34fb69 100644 --- a/src/main/java/redis/clients/jedis/providers/SentineledConnectionProvider.java +++ b/src/main/java/redis/clients/jedis/providers/SentineledConnectionProvider.java @@ -20,7 +20,7 @@ import redis.clients.jedis.JedisClientConfig; import redis.clients.jedis.JedisPubSub; import redis.clients.jedis.annots.Experimental; -import redis.clients.jedis.csc.ClientSideCache; +import redis.clients.jedis.csc.Cache; import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisException; import redis.clients.jedis.util.IOUtils; @@ -39,7 +39,7 @@ public class SentineledConnectionProvider implements ConnectionProvider { private final JedisClientConfig masterClientConfig; - private final ClientSideCache clientSideCache; + private final Cache clientSideCache; private final GenericObjectPoolConfig masterPoolConfig; @@ -58,7 +58,7 @@ public SentineledConnectionProvider(String masterName, final JedisClientConfig m @Experimental public SentineledConnectionProvider(String masterName, final JedisClientConfig masterClientConfig, - ClientSideCache clientSideCache, Set sentinels, final JedisClientConfig sentinelClientConfig) { + Cache clientSideCache, Set sentinels, final JedisClientConfig sentinelClientConfig) { this(masterName, masterClientConfig, clientSideCache, null, sentinels, sentinelClientConfig); } @@ -71,7 +71,7 @@ public SentineledConnectionProvider(String masterName, final JedisClientConfig m @Experimental public SentineledConnectionProvider(String masterName, final JedisClientConfig masterClientConfig, - ClientSideCache clientSideCache, final GenericObjectPoolConfig poolConfig, + Cache clientSideCache, final GenericObjectPoolConfig poolConfig, Set sentinels, final JedisClientConfig sentinelClientConfig) { this(masterName, masterClientConfig, clientSideCache, poolConfig, sentinels, sentinelClientConfig, DEFAULT_SUBSCRIBE_RETRY_WAIT_TIME_MILLIS); @@ -86,7 +86,7 @@ public SentineledConnectionProvider(String masterName, final JedisClientConfig m @Experimental public SentineledConnectionProvider(String masterName, final JedisClientConfig masterClientConfig, - ClientSideCache clientSideCache, final GenericObjectPoolConfig poolConfig, + Cache clientSideCache, final GenericObjectPoolConfig poolConfig, Set sentinels, final JedisClientConfig sentinelClientConfig, final long subscribeRetryWaitTimeMillis) { @@ -125,7 +125,7 @@ public HostAndPort getCurrentMaster() { private void initMaster(HostAndPort master) { initPoolLock.lock(); - + try { if (!master.equals(currentMaster)) { currentMaster = master; @@ -283,8 +283,8 @@ public void onMessage(String channel, String message) { initMaster(toHostAndPort(switchMasterMsg[3], switchMasterMsg[4])); } else { LOG.debug( - "Ignoring message on +switch-master for master {}. Our master is {}.", - switchMasterMsg[0], masterName); + "Ignoring message on +switch-master for master {}. Our master is {}.", + switchMasterMsg[0], masterName); } } else { diff --git a/src/main/java/redis/clients/jedis/util/RedisInputStream.java b/src/main/java/redis/clients/jedis/util/RedisInputStream.java index 0226961028..5baf1b3225 100644 --- a/src/main/java/redis/clients/jedis/util/RedisInputStream.java +++ b/src/main/java/redis/clients/jedis/util/RedisInputStream.java @@ -184,9 +184,12 @@ public boolean readBooleanCrLf() { ensureCrLf(); switch (b) { - case 't': return true; - case 'f': return false; - default: throw new JedisConnectionException("Unexpected character!"); + case 't': + return true; + case 'f': + return false; + default: + throw new JedisConnectionException("Unexpected character!"); } } @@ -260,4 +263,12 @@ private void ensureFill() throws JedisConnectionException { } } } + + @Override + public int available() throws IOException { + int availableInBuf = limit - count; + int availableInSocket = this.in.available(); + return (availableInBuf > availableInSocket) ? availableInBuf : availableInSocket; + } + } diff --git a/src/test/java/redis/clients/jedis/benchmark/CSCPooleadBenchmark.java b/src/test/java/redis/clients/jedis/benchmark/CSCPooleadBenchmark.java new file mode 100644 index 0000000000..8ee0580011 --- /dev/null +++ b/src/test/java/redis/clients/jedis/benchmark/CSCPooleadBenchmark.java @@ -0,0 +1,79 @@ +package redis.clients.jedis.benchmark; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import redis.clients.jedis.*; +import redis.clients.jedis.csc.Cache; +import redis.clients.jedis.csc.TestCache; + +public class CSCPooleadBenchmark { + + private static EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0"); + private static final int TOTAL_OPERATIONS = 1000000; + private static final int NUMBER_OF_THREADS = 50; + + public static void main(String[] args) throws Exception { + + try (Jedis j = new Jedis(endpoint.getHost(), endpoint.getPort())) { + j.auth(endpoint.getPassword()); + j.flushAll(); + j.disconnect(); + } + + int totalRounds = 50; + long withoutCache = 0; + long withCache = 0; + + for (int i = 0; i < totalRounds; i++) { + withoutCache += runBenchmark(null); + withCache += runBenchmark(new TestCache()); + } + for (int i = 0; i < totalRounds; i++) { + } + System.out.println(String.format("after %d rounds withoutCache: %d ms, withCache: %d ms", totalRounds, + withoutCache, withCache)); + System.out.println("execution time ratio: " + (double) withCache / withoutCache); + } + + private static long runBenchmark(Cache cache) throws Exception { + long start = System.currentTimeMillis(); + withPool(cache); + long elapsed = System.currentTimeMillis() - start; + System.out.println(String.format("%s round elapsed: %d ms", cache == null ? "no cache" : "cached", elapsed)); + return elapsed; + } + + private static void withPool(Cache cache) throws Exception { + JedisClientConfig config = DefaultJedisClientConfig.builder().protocol(RedisProtocol.RESP3) + .password(endpoint.getPassword()).build(); + List tds = new ArrayList<>(); + final AtomicInteger ind = new AtomicInteger(); + try (JedisPooled jedis = new JedisPooled(endpoint.getHostAndPort(), config, cache)) { + for (int i = 0; i < NUMBER_OF_THREADS; i++) { + Thread hj = new Thread(new Runnable() { + @Override + public void run() { + for (int i = 0; (i = ind.getAndIncrement()) < TOTAL_OPERATIONS;) { + try { + final String key = "foo" + i; + jedis.set(key, key); + jedis.get(key); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + } + }); + tds.add(hj); + hj.start(); + } + + for (Thread t : tds) { + t.join(); + } + } + } +} diff --git a/src/test/java/redis/clients/jedis/csc/AllowAndDenyListClientSideCacheTest.java b/src/test/java/redis/clients/jedis/csc/AllowAndDenyListClientSideCacheTest.java index 3d63a79fa2..83371c7f44 100644 --- a/src/test/java/redis/clients/jedis/csc/AllowAndDenyListClientSideCacheTest.java +++ b/src/test/java/redis/clients/jedis/csc/AllowAndDenyListClientSideCacheTest.java @@ -15,9 +15,8 @@ public class AllowAndDenyListClientSideCacheTest extends ClientSideCacheTestBase { - private static MapClientSideCache createMapClientSideCache(Map map, ClientSideCacheable cacheable) { - MapClientSideCache mapCache = new MapClientSideCache(map); - mapCache.setCacheable(cacheable); + private static Cache createTestCache(Map map, ClientSideCacheable cacheable) { + Cache mapCache = new TestCache(map, cacheable); return mapCache; } @@ -25,7 +24,7 @@ private static MapClientSideCache createMapClientSideCache(Map map = new HashMap<>(); try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), - createMapClientSideCache(map, new AllowAndDenyListWithStringKeys(null, null, null, null)), + createTestCache(map, new AllowAndDenyListWithStringKeys(null, null, null, null)), singleConnectionPoolConfig.get())) { control.set("foo", "bar"); assertThat(map, Matchers.aMapWithSize(0)); @@ -38,7 +37,7 @@ public void none() { public void whiteListCommand() { HashMap map = new HashMap<>(); try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), - createMapClientSideCache(map, new AllowAndDenyListWithStringKeys(singleton(Protocol.Command.GET), null, null, null)), + createTestCache(map, new AllowAndDenyListWithStringKeys(singleton(Protocol.Command.GET), null, null, null)), singleConnectionPoolConfig.get())) { control.set("foo", "bar"); assertThat(map, Matchers.aMapWithSize(0)); @@ -51,7 +50,7 @@ public void whiteListCommand() { public void blackListCommand() { HashMap map = new HashMap<>(); try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), - createMapClientSideCache(map, new AllowAndDenyListWithStringKeys(null, singleton(Protocol.Command.GET), null, null)), + createTestCache(map, new AllowAndDenyListWithStringKeys(null, singleton(Protocol.Command.GET), null, null)), singleConnectionPoolConfig.get())) { control.set("foo", "bar"); assertThat(map, Matchers.aMapWithSize(0)); @@ -64,7 +63,7 @@ public void blackListCommand() { public void whiteListKey() { HashMap map = new HashMap<>(); try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), - createMapClientSideCache(map, new AllowAndDenyListWithStringKeys(null, null, singleton("foo"), null)), + createTestCache(map, new AllowAndDenyListWithStringKeys(null, null, singleton("foo"), null)), singleConnectionPoolConfig.get())) { control.set("foo", "bar"); assertThat(map, Matchers.aMapWithSize(0)); @@ -77,7 +76,7 @@ public void whiteListKey() { public void blackListKey() { HashMap map = new HashMap<>(); try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), - createMapClientSideCache(map, new AllowAndDenyListWithStringKeys(null, null, null, singleton("foo"))), + createTestCache(map, new AllowAndDenyListWithStringKeys(null, null, null, singleton("foo"))), singleConnectionPoolConfig.get())) { control.set("foo", "bar"); assertThat(map, Matchers.aMapWithSize(0)); diff --git a/src/test/java/redis/clients/jedis/csc/CaffeineClientSideCacheTest.java b/src/test/java/redis/clients/jedis/csc/CaffeineClientSideCacheTest.java index 8308233603..18a9b28d15 100644 --- a/src/test/java/redis/clients/jedis/csc/CaffeineClientSideCacheTest.java +++ b/src/test/java/redis/clients/jedis/csc/CaffeineClientSideCacheTest.java @@ -8,91 +8,82 @@ import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.stats.CacheStats; -import java.net.URI; import java.util.concurrent.TimeUnit; import org.hamcrest.Matchers; import org.junit.Test; import redis.clients.jedis.JedisPooled; -import redis.clients.jedis.util.JedisURIHelper; public class CaffeineClientSideCacheTest extends ClientSideCacheTestBase { @Test public void simple() { - CaffeineClientSideCache caffeine = CaffeineClientSideCache.builder().maximumSize(10).ttl(10).build(); + CaffeineClientSideCache caffeine = new CaffeineClientSideCache(10); try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), caffeine)) { control.set("foo", "bar"); assertEquals("bar", jedis.get("foo")); control.del("foo"); - assertThat(jedis.get("foo"), Matchers.oneOf("bar", null)); // ? + assertEquals(null, jedis.get("foo")); } } @Test public void individualCommandsAndThenStats() { - Cache caffeine = Caffeine.newBuilder().recordStats().build(); + CaffeineClientSideCache caffeine = new CaffeineClientSideCache(100); - try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), - new CaffeineClientSideCache(caffeine), singleConnectionPoolConfig.get())) { + try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), caffeine, singleConnectionPoolConfig.get())) { control.set("foo", "bar"); - assertEquals(0, caffeine.estimatedSize()); - assertEquals("bar", jedis.get("foo")); - assertEquals(1, caffeine.estimatedSize()); + assertEquals(0, caffeine.getSize()); + assertEquals("bar", jedis.get("foo")); // cache miss + assertEquals(1, caffeine.getSize()); control.flushAll(); - assertEquals(1, caffeine.estimatedSize()); - assertEquals("bar", jedis.get("foo")); - assertEquals(1, caffeine.estimatedSize()); + assertEquals(1, caffeine.getSize()); + assertEquals(null, jedis.get("foo")); // cache miss + assertEquals(0, caffeine.getSize()); jedis.ping(); - assertEquals(0, caffeine.estimatedSize()); - assertNull(jedis.get("foo")); - assertEquals(0, caffeine.estimatedSize()); + assertEquals(0, caffeine.getSize()); + assertNull(jedis.get("foo")); // cache miss + assertEquals(0, caffeine.getSize()); } - CacheStats stats = caffeine.stats(); - assertEquals(1L, stats.hitCount()); - assertThat(stats.missCount(), Matchers.greaterThan(0L)); + assertEquals(0, caffeine.getStats().getHitCount()); + assertEquals(caffeine.getStats().getMissCount(), 3); } @Test - public void maximumSize() { - final long maxSize = 10; - final long maxEstimatedSize = 52; - int count = 1000; - for (int i = 0; i < count; i++) { - control.set("k" + i, "v" + i); - } + public void maximumSizeExact() { + control.set("k1", "v1"); + control.set("k2", "v2"); - Cache caffeine = Caffeine.newBuilder().maximumSize(maxSize).recordStats().build(); - try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new CaffeineClientSideCache(caffeine))) { - for (int i = 0; i < count; i++) { - jedis.get("k" + i); - assertThat(caffeine.estimatedSize(), Matchers.lessThanOrEqualTo(maxEstimatedSize)); - } + CaffeineClientSideCache caffeine = new CaffeineClientSideCache(1); + try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), caffeine)) { + assertEquals(0, caffeine.getSize()); + jedis.get("k1"); + assertEquals(1, caffeine.getSize()); + assertEquals(0, caffeine.getStats().getEvictCount()); + jedis.get("k2"); + assertEquals(1, caffeine.getSize()); + assertEquals(1, caffeine.getStats().getEvictCount()); } - assertThat(caffeine.stats().evictionCount(), Matchers.greaterThanOrEqualTo(count - maxEstimatedSize)); } @Test - public void timeToLive() throws InterruptedException { + public void maximumSize() { + final int maxSize = 10; + final int maxEstimatedSize = 10; int count = 1000; for (int i = 0; i < count; i++) { control.set("k" + i, "v" + i); } - Cache caffeine = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.SECONDS).recordStats().build(); - try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new CaffeineClientSideCache(caffeine))) { + CaffeineClientSideCache caffeine = new CaffeineClientSideCache(maxSize); + try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), caffeine)) { for (int i = 0; i < count; i++) { jedis.get("k" + i); + assertThat(caffeine.getSize(), Matchers.lessThanOrEqualTo(maxEstimatedSize)); } } - assertThat(caffeine.estimatedSize(), Matchers.equalTo((long) count)); - assertThat(caffeine.stats().evictionCount(), Matchers.equalTo(0L)); - - TimeUnit.SECONDS.sleep(2); - caffeine.cleanUp(); - assertThat(caffeine.estimatedSize(), Matchers.equalTo(0L)); - assertThat(caffeine.stats().evictionCount(), Matchers.equalTo((long) count)); + assertThat(caffeine.getStats().getEvictCount(), Matchers.greaterThanOrEqualTo((long) count - maxEstimatedSize)); } } diff --git a/src/test/java/redis/clients/jedis/csc/ClientSideCacheFunctionalityTest.java b/src/test/java/redis/clients/jedis/csc/ClientSideCacheFunctionalityTest.java index 332648f424..77e04c5e3b 100644 --- a/src/test/java/redis/clients/jedis/csc/ClientSideCacheFunctionalityTest.java +++ b/src/test/java/redis/clients/jedis/csc/ClientSideCacheFunctionalityTest.java @@ -1,67 +1,76 @@ package redis.clients.jedis.csc; -import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import java.net.URI; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.junit.Assert; import org.junit.Test; +import org.mockito.Mockito; +import redis.clients.jedis.CommandObjects; import redis.clients.jedis.JedisPooled; -import redis.clients.jedis.util.JedisURIHelper; +import redis.clients.jedis.UnifiedJedis; public class ClientSideCacheFunctionalityTest extends ClientSideCacheTestBase { @Test public void flushEntireCache() { - int count = 1000; + int count = 100; for (int i = 0; i < count; i++) { control.set("k" + i, "v" + i); } HashMap map = new HashMap<>(); - ClientSideCache clientSideCache = new MapClientSideCache(map); - try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), clientSideCache)) { + Cache clientSideCache = new TestCache(map); + JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), clientSideCache); + try { for (int i = 0; i < count; i++) { jedis.get("k" + i); } - } - assertEquals(count, map.size()); - clientSideCache.flush(); - assertEquals(0, map.size()); + assertEquals(count, map.size()); + clientSideCache.flush(); + assertEquals(0, map.size()); + } finally { + jedis.close(); + } } @Test public void removeSpecificKey() { - int count = 1000; + int count = 100; for (int i = 0; i < count; i++) { control.set("k" + i, "v" + i); } // By using LinkedHashMap, we can get the hashes (map keys) at the same order of the actual keys. LinkedHashMap map = new LinkedHashMap<>(); - ClientSideCache clientSideCache = new MapClientSideCache(map); - try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), clientSideCache)) { + Cache clientSideCache = new TestCache(map); + JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), clientSideCache); + try { for (int i = 0; i < count; i++) { jedis.get("k" + i); } - } - ArrayList commandHashes = new ArrayList<>(map.keySet()); - assertEquals(count, map.size()); - for (int i = 0; i < count; i++) { - String key = "k" + i; - CacheKey command = commandHashes.get(i); - assertTrue(map.containsKey(command)); - clientSideCache.invalidateKey(key); - assertFalse(map.containsKey(command)); + ArrayList commandHashes = new ArrayList<>(map.keySet()); + assertEquals(count, map.size()); + for (int i = 0; i < count; i++) { + String key = "k" + i; + CacheKey command = commandHashes.get(i); + assertTrue(map.containsKey(command)); + clientSideCache.deleteByRedisKey(key); + assertFalse(map.containsKey(command)); + } + } finally { + jedis.close(); } } @@ -71,10 +80,82 @@ public void multiKeyOperation() { control.set("k2", "v2"); HashMap map = new HashMap<>(); - try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new MapClientSideCache(map))) { + try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new TestCache(map))) { jedis.mget("k1", "k2"); assertEquals(1, map.size()); } } + @Test + public void maximumSizeExact() { + control.set("k1", "v1"); + control.set("k2", "v2"); + + DefaultCache cache = new DefaultCache(1); + try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), cache)) { + assertEquals(0, cache.getSize()); + jedis.get("k1"); + assertEquals(1, cache.getSize()); + assertEquals(0, cache.getStats().getEvictCount()); + jedis.get("k2"); + assertEquals(1, cache.getSize()); + assertEquals(1, cache.getStats().getEvictCount()); + } + } + + @Test + public void testInvalidationWithUnifiedJedis() { + Cache cache = new TestCache(); + Cache mock = Mockito.spy(cache); + UnifiedJedis client = new UnifiedJedis(hnp, clientConfig.get(), mock); + UnifiedJedis controlClient = new UnifiedJedis(hnp, clientConfig.get()); + + try { + // "foo" is cached + client.set("foo", "bar"); + client.get("foo"); // read from the server + Assert.assertEquals("bar", client.get("foo")); // cache hit + + // Using another connection + controlClient.set("foo", "bar2"); + Assert.assertEquals("bar2", controlClient.get("foo")); + + //invalidating the cache and read it back from server + Assert.assertEquals("bar2", client.get("foo")); + + // ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(GuavaClientSideCache.class); + Mockito.verify(mock, Mockito.times(1)).deleteByRedisKeys(Mockito.anyList()); + Mockito.verify(mock, Mockito.times(2)).set(Mockito.any(CacheKey.class), Mockito.any(CacheEntry.class)); + } finally { + client.close(); + controlClient.close(); + } + } + + @Test + public void differentInstanceOnEachCacheHit() { + ConcurrentHashMap map = new ConcurrentHashMap(); + TestCache testCache = new TestCache(map); + + // fill the cache for maxSize + try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), testCache)) { + jedis.sadd("foo", "a"); + jedis.sadd("foo", "b"); + + Set expected = new HashSet(); + expected.add("a"); + expected.add("b"); + + Set members1 = jedis.smembers("foo"); + Set members2 = jedis.smembers("foo"); + + Set fromMap = (Set) testCache.get(new CacheKey<>(new CommandObjects().smembers("foo"))) + .getValue(); + assertEquals(expected, members1); + assertEquals(expected, members2); + assertEquals(expected, fromMap); + assertTrue(members1 != members2); + assertTrue(members1 != fromMap); + } + } } diff --git a/src/test/java/redis/clients/jedis/csc/ClientSideCacheTestBase.java b/src/test/java/redis/clients/jedis/csc/ClientSideCacheTestBase.java index 15531a5dfb..4bde3be30d 100644 --- a/src/test/java/redis/clients/jedis/csc/ClientSideCacheTestBase.java +++ b/src/test/java/redis/clients/jedis/csc/ClientSideCacheTestBase.java @@ -7,7 +7,6 @@ import redis.clients.jedis.Connection; import redis.clients.jedis.ConnectionPoolConfig; -import redis.clients.jedis.DefaultJedisClientConfig; import redis.clients.jedis.EndpointConfig; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.HostAndPorts; @@ -20,13 +19,11 @@ abstract class ClientSideCacheTestBase { protected static final HostAndPort hnp = endpoint.getHostAndPort(); - protected static final String baseUrl = "redis://:foobared@" + hnp.toString() + "/"; // TODO: use EndpointConfig - protected Jedis control; @Before public void setUp() throws Exception { - control = new Jedis(hnp, DefaultJedisClientConfig.builder().password("foobared").build()); // TODO: use EndpointConfig + control = new Jedis(hnp, endpoint.getClientConfigBuilder().build()); control.flushAll(); } @@ -35,14 +32,12 @@ public void tearDown() throws Exception { control.close(); } - protected static final Supplier clientConfig - = () -> DefaultJedisClientConfig.builder().resp3().password("foobared").build(); // TODO: use EndpointConfig + protected static final Supplier clientConfig = () -> endpoint.getClientConfigBuilder().resp3().build(); - protected static final Supplier> singleConnectionPoolConfig - = () -> { - ConnectionPoolConfig poolConfig = new ConnectionPoolConfig(); - poolConfig.setMaxTotal(1); - return poolConfig; - }; + protected static final Supplier> singleConnectionPoolConfig = () -> { + ConnectionPoolConfig poolConfig = new ConnectionPoolConfig(); + poolConfig.setMaxTotal(1); + return poolConfig; + }; } diff --git a/src/test/java/redis/clients/jedis/csc/GuavaClientSideCacheTest.java b/src/test/java/redis/clients/jedis/csc/GuavaClientSideCacheTest.java index 4c7362e63b..fad64df8ab 100644 --- a/src/test/java/redis/clients/jedis/csc/GuavaClientSideCacheTest.java +++ b/src/test/java/redis/clients/jedis/csc/GuavaClientSideCacheTest.java @@ -4,54 +4,47 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheStats; - -import java.net.URI; import java.util.concurrent.TimeUnit; import org.hamcrest.Matchers; import org.junit.Test; import redis.clients.jedis.JedisPooled; -import redis.clients.jedis.util.JedisURIHelper; public class GuavaClientSideCacheTest extends ClientSideCacheTestBase { @Test public void simple() { - GuavaClientSideCache guava = GuavaClientSideCache.builder().maximumSize(10).ttl(10).build(); + GuavaClientSideCache guava = new GuavaClientSideCache(10); try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), guava)) { control.set("foo", "bar"); assertEquals("bar", jedis.get("foo")); control.del("foo"); - assertThat(jedis.get("foo"), Matchers.oneOf("bar", null)); // ? + assertEquals(null, jedis.get("foo")); } } @Test public void individualCommandsAndThenStats() { - Cache guava = CacheBuilder.newBuilder().recordStats().build(); + GuavaClientSideCache guava = new GuavaClientSideCache(10000); - try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new GuavaClientSideCache(guava), + try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), guava, singleConnectionPoolConfig.get())) { control.set("foo", "bar"); - assertEquals(0, guava.size()); - assertEquals("bar", jedis.get("foo")); - assertEquals(1, guava.size()); + assertEquals(0, guava.getSize()); + assertEquals("bar", jedis.get("foo")); // cache miss + assertEquals(1, guava.getSize()); control.flushAll(); - assertEquals(1, guava.size()); - assertEquals("bar", jedis.get("foo")); - assertEquals(1, guava.size()); + assertEquals(1, guava.getSize()); + assertEquals(null, jedis.get("foo")); // cache miss + assertEquals(0, guava.getSize()); jedis.ping(); - assertEquals(0, guava.size()); - assertNull(jedis.get("foo")); - assertEquals(0, guava.size()); + assertEquals(0, guava.getSize()); + assertNull(jedis.get("foo")); // cache miss + assertEquals(0, guava.getSize()); } - CacheStats stats = guava.stats(); - assertEquals(1L, stats.hitCount()); - assertThat(stats.missCount(), Matchers.greaterThan(0L)); + assertEquals(0, guava.getStats().getHitCount()); + assertEquals(guava.getStats().getMissCount(), 3); } @Test @@ -59,57 +52,35 @@ public void maximumSizeExact() { control.set("k1", "v1"); control.set("k2", "v2"); - Cache guava = CacheBuilder.newBuilder().maximumSize(1).recordStats().build(); - try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new GuavaClientSideCache(guava))) { - assertEquals(0, guava.size()); + GuavaClientSideCache guava = new GuavaClientSideCache(1); + try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), guava)) { + assertEquals(0, guava.getSize()); jedis.get("k1"); - assertEquals(1, guava.size()); - assertEquals(0, guava.stats().evictionCount()); + assertEquals(1, guava.getSize()); + assertEquals(0, guava.getStats().getEvictCount()); jedis.get("k2"); - assertEquals(1, guava.size()); - assertEquals(1, guava.stats().evictionCount()); + assertEquals(1, guava.getSize()); + assertEquals(1, guava.getStats().getEvictCount()); } } @Test public void maximumSize() { - final long maxSize = 10; - final long maxEstimatedSize = 40; - int count = 1000; - for (int i = 0; i < count; i++) { - control.set("k" + i, "v" + i); - } - - Cache guava = CacheBuilder.newBuilder().maximumSize(maxSize).recordStats().build(); - try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new GuavaClientSideCache(guava))) { - for (int i = 0; i < count; i++) { - jedis.get("k" + i); - assertThat(guava.size(), Matchers.lessThanOrEqualTo(maxEstimatedSize)); - } - } - assertThat(guava.stats().evictionCount(), Matchers.greaterThan(count - maxEstimatedSize)); - } - - @Test - public void timeToLive() throws InterruptedException { + final int maxSize = 10; + final int maxEstimatedSize = 40; int count = 1000; for (int i = 0; i < count; i++) { control.set("k" + i, "v" + i); } - Cache guava = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.SECONDS).recordStats().build(); - try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new GuavaClientSideCache(guava))) { + GuavaClientSideCache guava = new GuavaClientSideCache(maxSize); + try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), guava)) { for (int i = 0; i < count; i++) { jedis.get("k" + i); + assertThat(guava.getSize(), Matchers.lessThanOrEqualTo(maxEstimatedSize)); } } - assertThat(guava.size(), Matchers.equalTo((long) count)); - assertThat(guava.stats().evictionCount(), Matchers.equalTo(0L)); - - TimeUnit.SECONDS.sleep(2); - guava.cleanUp(); - assertThat(guava.size(), Matchers.equalTo(0L)); - assertThat(guava.stats().evictionCount(), Matchers.equalTo((long) count)); + assertThat(guava.getStats().getEvictCount(), Matchers.greaterThan((long) count - maxEstimatedSize)); } } diff --git a/src/test/java/redis/clients/jedis/csc/JedisClusterClientSideCacheTest.java b/src/test/java/redis/clients/jedis/csc/JedisClusterClientSideCacheTest.java index 4c3f25b5e8..6434bf1111 100644 --- a/src/test/java/redis/clients/jedis/csc/JedisClusterClientSideCacheTest.java +++ b/src/test/java/redis/clients/jedis/csc/JedisClusterClientSideCacheTest.java @@ -52,18 +52,18 @@ public void tearDown() throws Exception { @Test public void simple() { - try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new MapClientSideCache())) { + try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new TestCache())) { control.set("foo", "bar"); assertEquals("bar", jedis.get("foo")); control.del("foo"); - assertThat(jedis.get("foo"), Matchers.oneOf("bar", null)); // ? + assertEquals(null, jedis.get("foo")); } } @Test public void simpleWithSimpleMap() { HashMap map = new HashMap<>(); - try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new MapClientSideCache(map), + try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new TestCache(map), singleConnectionPoolConfig.get())) { control.set("foo", "bar"); assertThat(map, Matchers.aMapWithSize(0)); @@ -71,8 +71,8 @@ public void simpleWithSimpleMap() { assertThat(map, Matchers.aMapWithSize(1)); control.del("foo"); assertThat(map, Matchers.aMapWithSize(1)); - assertEquals("bar", jedis.get("foo")); - assertThat(map, Matchers.aMapWithSize(1)); + assertEquals(null, jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(0)); jedis.ping(); assertThat(map, Matchers.aMapWithSize(0)); assertNull(jedis.get("foo")); @@ -82,18 +82,18 @@ public void simpleWithSimpleMap() { @Test public void flushAll() { - try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new MapClientSideCache())) { + try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new TestCache())) { control.set("foo", "bar"); assertEquals("bar", jedis.get("foo")); control.flushAll(); - assertThat(jedis.get("foo"), Matchers.oneOf("bar", null)); // ? + assertEquals(null, jedis.get("foo")); } } @Test public void flushAllWithSimpleMap() { HashMap map = new HashMap<>(); - try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new MapClientSideCache(map), + try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new TestCache(map), singleConnectionPoolConfig.get())) { control.set("foo", "bar"); assertThat(map, Matchers.aMapWithSize(0)); @@ -101,8 +101,8 @@ public void flushAllWithSimpleMap() { assertThat(map, Matchers.aMapWithSize(1)); control.flushAll(); assertThat(map, Matchers.aMapWithSize(1)); - assertEquals("bar", jedis.get("foo")); - assertThat(map, Matchers.aMapWithSize(1)); + assertEquals(null, jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(0)); jedis.ping(); assertThat(map, Matchers.aMapWithSize(0)); assertNull(jedis.get("foo")); diff --git a/src/test/java/redis/clients/jedis/csc/JedisPooledClientSideCacheTest.java b/src/test/java/redis/clients/jedis/csc/JedisPooledClientSideCacheTest.java index 20933fd237..de2e3e8144 100644 --- a/src/test/java/redis/clients/jedis/csc/JedisPooledClientSideCacheTest.java +++ b/src/test/java/redis/clients/jedis/csc/JedisPooledClientSideCacheTest.java @@ -3,37 +3,84 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; - +import static org.junit.Assert.assertTrue; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.function.Supplier; - import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.locationtech.jts.util.Assert; +import redis.clients.jedis.CommandObjects; import redis.clients.jedis.Connection; import redis.clients.jedis.ConnectionPoolConfig; -import redis.clients.jedis.DefaultJedisClientConfig; import redis.clients.jedis.EndpointConfig; -import redis.clients.jedis.HostAndPort; import redis.clients.jedis.HostAndPorts; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisClientConfig; import redis.clients.jedis.JedisPooled; -public class JedisPooledClientSideCacheTest { +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; - private static final EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone1"); +@RunWith(Parameterized.class) +public class JedisPooledClientSideCacheTest { - protected static final HostAndPort hnp = endpoint.getHostAndPort(); + private EndpointConfig endpoint; protected Jedis control; + protected static final EndpointConfig sslEndpoint = HostAndPorts.getRedisEndpoint("standalone0-tls"); + + protected Jedis sslControl; + + public JedisPooledClientSideCacheTest(EndpointConfig endpoint) { + this.endpoint = endpoint; + } + + @Parameters + public static Collection data() { + return Arrays.asList(new Object[][] { + { HostAndPorts.getRedisEndpoint("standalone1") }, + { HostAndPorts.getRedisEndpoint("standalone0-tls") }, + }); + } + + @BeforeClass + public static void prepare() { + setupTrustStore(); + } + + static void setupTrustStore() { + setJvmTrustStore("src/test/resources/truststore.jceks", "jceks"); + } + + private static void setJvmTrustStore(String trustStoreFilePath, String trustStoreType) { + assertTrue(String.format("Could not find trust store at '%s'.", trustStoreFilePath), + new File(trustStoreFilePath).exists()); + System.setProperty("javax.net.ssl.trustStore", trustStoreFilePath); + System.setProperty("javax.net.ssl.trustStoreType", trustStoreType); + } + @Before public void setUp() throws Exception { - control = new Jedis(hnp, DefaultJedisClientConfig.builder().password("foobared").build()); // TODO: use EndpointConfig + + control = new Jedis(endpoint.getHostAndPort(), endpoint.getClientConfigBuilder().build()); control.flushAll(); } @@ -42,30 +89,37 @@ public void tearDown() throws Exception { control.close(); } - private static final Supplier clientConfig - = () -> DefaultJedisClientConfig.builder().resp3().password("foobared").build(); // TODO: use EndpointConfig + private final Supplier clientConfig = () -> endpoint.getClientConfigBuilder().resp3().build(); - private static final Supplier> singleConnectionPoolConfig - = () -> { - ConnectionPoolConfig poolConfig = new ConnectionPoolConfig(); - poolConfig.setMaxTotal(1); - return poolConfig; - }; + private final Supplier> singleConnectionPoolConfig = () -> { + ConnectionPoolConfig poolConfig = new ConnectionPoolConfig(); + poolConfig.setMaxTotal(1); + return poolConfig; + }; + + private void sleep() { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } @Test public void simple() { - try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new MapClientSideCache())) { + try (JedisPooled jedis = new JedisPooled(endpoint.getHostAndPort(), clientConfig.get(), new TestCache())) { control.set("foo", "bar"); assertEquals("bar", jedis.get("foo")); control.del("foo"); - assertThat(jedis.get("foo"), Matchers.oneOf("bar", null)); // ? + sleep(); + assertNull(jedis.get("foo")); } } @Test public void simpleWithSimpleMap() { HashMap map = new HashMap<>(); - try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new MapClientSideCache(map), + try (JedisPooled jedis = new JedisPooled(endpoint.getHostAndPort(), clientConfig.get(), new TestCache(map), singleConnectionPoolConfig.get())) { control.set("foo", "bar"); assertThat(map, Matchers.aMapWithSize(0)); @@ -73,10 +127,12 @@ public void simpleWithSimpleMap() { assertThat(map, Matchers.aMapWithSize(1)); control.del("foo"); assertThat(map, Matchers.aMapWithSize(1)); - assertEquals("bar", jedis.get("foo")); - assertThat(map, Matchers.aMapWithSize(1)); - jedis.ping(); + sleep(); + assertNull(jedis.get("foo")); assertThat(map, Matchers.aMapWithSize(0)); + sleep(); + assertThat(map, Matchers.aMapWithSize(0)); + sleep(); assertNull(jedis.get("foo")); assertThat(map, Matchers.aMapWithSize(0)); } @@ -84,18 +140,19 @@ public void simpleWithSimpleMap() { @Test public void flushAll() { - try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new MapClientSideCache())) { + try (JedisPooled jedis = new JedisPooled(endpoint.getHostAndPort(), clientConfig.get(), new TestCache())) { control.set("foo", "bar"); assertEquals("bar", jedis.get("foo")); control.flushAll(); - assertThat(jedis.get("foo"), Matchers.oneOf("bar", null)); // ? + sleep(); + assertNull(jedis.get("foo")); } } @Test public void flushAllWithSimpleMap() { HashMap map = new HashMap<>(); - try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new MapClientSideCache(map), + try (JedisPooled jedis = new JedisPooled(endpoint.getHostAndPort(), clientConfig.get(), new TestCache(map), singleConnectionPoolConfig.get())) { control.set("foo", "bar"); assertThat(map, Matchers.aMapWithSize(0)); @@ -103,12 +160,228 @@ public void flushAllWithSimpleMap() { assertThat(map, Matchers.aMapWithSize(1)); control.flushAll(); assertThat(map, Matchers.aMapWithSize(1)); - assertEquals("bar", jedis.get("foo")); - assertThat(map, Matchers.aMapWithSize(1)); - jedis.ping(); + sleep(); + assertNull(jedis.get("foo")); assertThat(map, Matchers.aMapWithSize(0)); + sleep(); assertNull(jedis.get("foo")); assertThat(map, Matchers.aMapWithSize(0)); } } + + @Test + public void testSequentialAccess() throws InterruptedException { + int threadCount = 10; + int iterations = 10000; + + try (JedisPooled jedis = new JedisPooled(endpoint.getHostAndPort(), clientConfig.get())) { + jedis.set("foo", "0"); + } + + ReentrantLock lock = new ReentrantLock(true); + ExecutorService executorService = Executors.newFixedThreadPool(threadCount); + + // Create the shared mock instance of cache + TestCache testCache = new TestCache(); + + // Submit multiple threads to perform concurrent operations + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; i++) { + executorService.submit(() -> { + try (JedisPooled jedis = new JedisPooled(endpoint.getHostAndPort(), clientConfig.get(), testCache)) { + for (int j = 0; j < iterations; j++) { + lock.lock(); + try { + // Simulate continious get and update operations and consume invalidation events meanwhile + assertEquals(control.get("foo"), jedis.get("foo")); + Integer value = new Integer(jedis.get("foo")); + assertEquals("OK", jedis.set("foo", (++value).toString())); + } finally { + lock.unlock(); + } + } + } finally { + latch.countDown(); + } + }); + } + + // wait for all threads to complete + latch.await(); + + // Verify the final value of "foo" in Redis + String finalValue = control.get("foo"); + assertEquals(threadCount * iterations, Integer.parseInt(finalValue)); + + } + + @Test + public void testConcurrentAccessWithStats() throws InterruptedException { + int threadCount = 10; + int iterations = 10000; + + try (JedisPooled jedis = new JedisPooled(endpoint.getHostAndPort(), clientConfig.get())) { + jedis.set("foo", "0"); + } + + ExecutorService executorService = Executors.newFixedThreadPool(threadCount); + + // Create the shared mock instance of cache + TestCache testCache = new TestCache(); + + // Submit multiple threads to perform concurrent operations + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; i++) { + executorService.submit(() -> { + try (JedisPooled jedis = new JedisPooled(endpoint.getHostAndPort(), clientConfig.get(), testCache)) { + for (int j = 0; j < iterations; j++) { + // Simulate continious get and update operations and consume invalidation events meanwhile + Integer value = new Integer(jedis.get("foo")) + 1; + assertEquals("OK", jedis.set("foo", value.toString())); + } + } finally { + latch.countDown(); + } + }); + } + + // wait for all threads to complete + latch.await(); + + CacheStats stats = testCache.getStats(); + assertEquals(threadCount * iterations, stats.getMissCount() + stats.getHitCount()); + assertEquals(stats.getMissCount(), stats.getLoadCount()); + } + + @Test + public void testMaxSize() throws InterruptedException { + int threadCount = 10; + int iterations = 11000; + int maxSize = 1000; + + ExecutorService executorService = Executors.newFixedThreadPool(threadCount); + + ConcurrentHashMap map = new ConcurrentHashMap(); + // Create the shared mock instance of cache + TestCache testCache = new TestCache(maxSize, map, DefaultClientSideCacheable.INSTANCE); + + // Submit multiple threads to perform concurrent operations + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; i++) { + executorService.submit(() -> { + try (JedisPooled jedis = new JedisPooled(endpoint.getHostAndPort(), clientConfig.get(), testCache)) { + for (int j = 0; j < iterations; j++) { + // Simulate continious get and update operations and consume invalidation events meanwhile + assertEquals("OK", jedis.set("foo" + j, "foo" + j)); + jedis.get("foo" + j); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + latch.countDown(); + } + }); + } + + // wait for all threads to complete + latch.await(); + + CacheStats stats = testCache.getStats(); + + assertEquals(threadCount * iterations, stats.getMissCount() + stats.getHitCount()); + assertEquals(stats.getMissCount(), stats.getLoadCount()); + assertEquals(threadCount * iterations, stats.getNonCacheableCount()); + assertTrue(maxSize >= testCache.getSize()); + } + + @Test + public void testEvictionPolicy() throws InterruptedException { + int maxSize = 100; + int expectedEvictions = 20; + int touchOffset = 10; + + HashMap map = new HashMap(); + TestCache testCache = new TestCache(maxSize, map, DefaultClientSideCacheable.INSTANCE); + + // fill the cache for maxSize + try (JedisPooled jedis = new JedisPooled(endpoint.getHostAndPort(), clientConfig.get(), testCache)) { + for (int i = 0; i < maxSize; i++) { + jedis.set("foo" + i, "bar" + i); + assertEquals("bar" + i, jedis.get("foo" + i)); + } + + // touch a set of keys to prevent from eviction from index 10 to 29 + for (int i = touchOffset; i < touchOffset + expectedEvictions; i++) { + assertEquals("bar" + i, jedis.get("foo" + i)); + } + + // add more keys to trigger eviction, adding from 100 to 119 + for (int i = maxSize; i < maxSize + expectedEvictions; i++) { + jedis.set("foo" + i, "bar" + i); + assertEquals("bar" + i, jedis.get("foo" + i)); + } + + // check touched keys not evicted + for (int i = touchOffset; i < touchOffset + expectedEvictions; i++) { + + assertTrue(map.containsKey(new CacheKey(new CommandObjects().get("foo" + i)))); + } + + // check expected evictions are done till the offset + for (int i = 0; i < touchOffset; i++) { + assertTrue(!map.containsKey(new CacheKey(new CommandObjects().get("foo" + i)))); + } + + /// check expected evictions are done after the touched keys + for (int i = touchOffset + expectedEvictions; i < (2 * expectedEvictions); i++) { + assertTrue(!map.containsKey(new CacheKey(new CommandObjects().get("foo" + i)))); + } + + assertEquals(maxSize, testCache.getSize()); + } + } + + @Test + public void testEvictionPolicyMultithreaded() throws InterruptedException { + int NUMBER_OF_THREADS = 100; + int TOTAL_OPERATIONS = 1000000; + int NUMBER_OF_DISTINCT_KEYS = 53; + int MAX_SIZE = 20; + List exceptions = new ArrayList<>(); + + TestCache cache = new TestCache(MAX_SIZE, new HashMap<>(), DefaultClientSideCacheable.INSTANCE); + List tds = new ArrayList<>(); + final AtomicInteger ind = new AtomicInteger(); + try (JedisPooled jedis = new JedisPooled(endpoint.getHostAndPort(), clientConfig.get(), cache)) { + for (int i = 0; i < NUMBER_OF_THREADS; i++) { + Thread hj = new Thread(new Runnable() { + @Override + public void run() { + for (int i = 0; (i = ind.getAndIncrement()) < TOTAL_OPERATIONS;) { + try { + final String key = "foo" + i % NUMBER_OF_DISTINCT_KEYS; + if (i < NUMBER_OF_DISTINCT_KEYS) { + jedis.set(key, key); + } + jedis.get(key); + } catch (Exception e) { + exceptions.add(e); + throw e; + } + } + } + }); + tds.add(hj); + hj.start(); + } + + for (Thread t : tds) { + t.join(); + } + + Assert.equals(MAX_SIZE, cache.getSize()); + Assert.equals(0, exceptions.size()); + } + } + } diff --git a/src/test/java/redis/clients/jedis/csc/JedisSentineledClientSideCacheTest.java b/src/test/java/redis/clients/jedis/csc/JedisSentineledClientSideCacheTest.java index 1660396d23..13130416ce 100644 --- a/src/test/java/redis/clients/jedis/csc/JedisSentineledClientSideCacheTest.java +++ b/src/test/java/redis/clients/jedis/csc/JedisSentineledClientSideCacheTest.java @@ -48,19 +48,19 @@ public void tearDown() throws Exception { @Test public void simple() { - try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new MapClientSideCache(), + try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new TestCache(), sentinels, sentinelClientConfig)) { control.set("foo", "bar"); assertEquals("bar", jedis.get("foo")); control.del("foo"); - assertThat(jedis.get("foo"), Matchers.oneOf("bar", null)); // ? + assertEquals(null, jedis.get("foo")); } } @Test public void simpleWithSimpleMap() { HashMap map = new HashMap<>(); - try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new MapClientSideCache(map), + try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new TestCache(map), sentinels, sentinelClientConfig)) { control.set("foo", "bar"); assertThat(map, Matchers.aMapWithSize(0)); @@ -68,8 +68,8 @@ public void simpleWithSimpleMap() { assertThat(map, Matchers.aMapWithSize(1)); control.del("foo"); assertThat(map, Matchers.aMapWithSize(1)); - assertEquals("bar", jedis.get("foo")); - assertThat(map, Matchers.aMapWithSize(1)); + assertEquals(null, jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(0)); jedis.ping(); assertThat(map, Matchers.aMapWithSize(0)); assertNull(jedis.get("foo")); @@ -79,19 +79,19 @@ public void simpleWithSimpleMap() { @Test public void flushAll() { - try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new MapClientSideCache(), + try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new TestCache(), sentinels, sentinelClientConfig)) { control.set("foo", "bar"); assertEquals("bar", jedis.get("foo")); control.flushAll(); - assertThat(jedis.get("foo"), Matchers.oneOf("bar", null)); // ? + assertEquals(null, jedis.get("foo")); } } @Test public void flushAllWithSimpleMap() { HashMap map = new HashMap<>(); - try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new MapClientSideCache(map), + try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new TestCache(map), sentinels, sentinelClientConfig)) { control.set("foo", "bar"); assertThat(map, Matchers.aMapWithSize(0)); @@ -99,8 +99,8 @@ public void flushAllWithSimpleMap() { assertThat(map, Matchers.aMapWithSize(1)); control.flushAll(); assertThat(map, Matchers.aMapWithSize(1)); - assertEquals("bar", jedis.get("foo")); - assertThat(map, Matchers.aMapWithSize(1)); + assertEquals(null, jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(0)); jedis.ping(); assertThat(map, Matchers.aMapWithSize(0)); assertNull(jedis.get("foo")); diff --git a/src/test/java/redis/clients/jedis/csc/MapClientSideCache.java b/src/test/java/redis/clients/jedis/csc/MapClientSideCache.java deleted file mode 100644 index a0b33c52d7..0000000000 --- a/src/test/java/redis/clients/jedis/csc/MapClientSideCache.java +++ /dev/null @@ -1,38 +0,0 @@ -package redis.clients.jedis.csc; - -import java.util.HashMap; -import java.util.Map; - -public class MapClientSideCache extends ClientSideCache { - - private final Map cache; - - public MapClientSideCache() { - this(new HashMap<>()); - } - - public MapClientSideCache(Map map) { - super(); - this.cache = map; - } - - @Override - protected final void clear() { - cache.clear(); - } - - @Override - protected void remove(Iterable> keys) { - keys.forEach(hash -> cache.remove(hash)); - } - - @Override - protected void put(CacheKey key, CacheEntry entry) { - cache.put(key, entry); - } - - @Override - protected CacheEntry get(CacheKey key) { - return cache.get(key); - } -} diff --git a/src/test/java/redis/clients/jedis/csc/TestCache.java b/src/test/java/redis/clients/jedis/csc/TestCache.java new file mode 100644 index 0000000000..fd90b1229b --- /dev/null +++ b/src/test/java/redis/clients/jedis/csc/TestCache.java @@ -0,0 +1,30 @@ +package redis.clients.jedis.csc; + +import java.util.HashMap; +import java.util.Map; + +public class TestCache extends DefaultCache { + + public TestCache() { + this(new HashMap()); + } + + public TestCache(Map map) { + super(10000, map); + } + + public TestCache(Map map, ClientSideCacheable cacheable) { + + super(10000, map, cacheable, new LRUEviction(10000)); + } + + public TestCache(int maxSize, Map map, ClientSideCacheable cacheable) { + this(maxSize, map, cacheable, new LRUEviction(maxSize)); + } + + public TestCache(int maxSize, Map map, ClientSideCacheable cacheable, + EvictionPolicy evictionPolicy) { + super(maxSize, map, cacheable, evictionPolicy); + } + +}