diff --git a/src/main/java/redis/clients/jedis/ClientSideCache.java b/src/main/java/redis/clients/jedis/ClientSideCache.java index 5dd31b17e9..62c5be28c2 100644 --- a/src/main/java/redis/clients/jedis/ClientSideCache.java +++ b/src/main/java/redis/clients/jedis/ClientSideCache.java @@ -10,14 +10,27 @@ public class ClientSideCache { - private final Map cache = new HashMap<>(); + private final Map cache; - protected ClientSideCache() { + public ClientSideCache() { + this.cache = new HashMap<>(); } - protected void invalidateKeys(List list) { + /** + * For testing purpose only. + * @param map + */ + ClientSideCache(Map map) { + this.cache = map; + } + + public final void clear() { + cache.clear(); + } + + public final void invalidateKeys(List list) { if (list == null) { - cache.clear(); + clear(); return; } diff --git a/src/main/java/redis/clients/jedis/Connection.java b/src/main/java/redis/clients/jedis/Connection.java index a8af741f42..bff5898f8d 100644 --- a/src/main/java/redis/clients/jedis/Connection.java +++ b/src/main/java/redis/clients/jedis/Connection.java @@ -52,9 +52,7 @@ public Connection(final HostAndPort hostAndPort) { } public Connection(final HostAndPort hostAndPort, final JedisClientConfig clientConfig) { - this(new DefaultJedisSocketFactory(hostAndPort, clientConfig)); - this.infiniteSoTimeout = clientConfig.getBlockingSocketTimeoutMillis(); - initializeFromClientConfig(clientConfig); + this(new DefaultJedisSocketFactory(hostAndPort, clientConfig), clientConfig); } public Connection(final JedisSocketFactory socketFactory) { @@ -65,7 +63,15 @@ public Connection(final JedisSocketFactory socketFactory, JedisClientConfig clie this.socketFactory = socketFactory; this.soTimeout = clientConfig.getSocketTimeoutMillis(); this.infiniteSoTimeout = clientConfig.getBlockingSocketTimeoutMillis(); - initializeFromClientConfig(clientConfig); + initializeConnection(clientConfig); + } + + public Connection(final JedisSocketFactory socketFactory, JedisClientConfig clientConfig, ClientSideCache csCache) { + this.socketFactory = socketFactory; + this.soTimeout = clientConfig.getSocketTimeoutMillis(); + this.infiniteSoTimeout = clientConfig.getBlockingSocketTimeoutMillis(); + initializeConnection(clientConfig); + initializeClientSideCache(csCache); } @Override @@ -122,10 +128,6 @@ public void rollbackTimeout() { } } - final void setClientSideCache(ClientSideCache clientSideCache) { - this.clientSideCache = clientSideCache; - } - public Object executeCommand(final ProtocolCommand cmd) { return executeCommand(new CommandArguments(cmd)); } @@ -389,7 +391,7 @@ private static boolean validateClientInfo(String info) { return true; } - private void initializeFromClientConfig(final JedisClientConfig config) { + private void initializeConnection(final JedisClientConfig config) { try { connect(); @@ -516,4 +518,19 @@ public boolean ping() { } return true; } + + private void initializeClientSideCache(ClientSideCache csCache) { + this.clientSideCache = csCache; + if (clientSideCache != null) { + if (protocol != RedisProtocol.RESP3) { + throw new JedisException("Client side caching is only supported with RESP3."); + } + + sendCommand(Protocol.Command.CLIENT, "TRACKING", "ON"); + String reply = getStatusCodeReply(); + if (!"OK".equals(reply)) { + throw new JedisException("Could not enable client tracking. Reply: " + reply); + } + } + } } diff --git a/src/main/java/redis/clients/jedis/ConnectionFactory.java b/src/main/java/redis/clients/jedis/ConnectionFactory.java index d286462347..5b43606205 100644 --- a/src/main/java/redis/clients/jedis/ConnectionFactory.java +++ b/src/main/java/redis/clients/jedis/ConnectionFactory.java @@ -17,8 +17,8 @@ public class ConnectionFactory implements PooledObjectFactory { private static final Logger logger = LoggerFactory.getLogger(ConnectionFactory.class); private final JedisSocketFactory jedisSocketFactory; - private final JedisClientConfig clientConfig; + private ClientSideCache clientSideCache = null; public ConnectionFactory(final HostAndPort hostAndPort) { this.clientConfig = DefaultJedisClientConfig.builder().build(); @@ -26,12 +26,18 @@ public ConnectionFactory(final HostAndPort hostAndPort) { } public ConnectionFactory(final HostAndPort hostAndPort, final JedisClientConfig clientConfig) { - this.clientConfig = DefaultJedisClientConfig.copyConfig(clientConfig); + this.clientConfig = clientConfig; this.jedisSocketFactory = new DefaultJedisSocketFactory(hostAndPort, this.clientConfig); } + public ConnectionFactory(final HostAndPort hostAndPort, final JedisClientConfig clientConfig, ClientSideCache csCache) { + this.clientConfig = clientConfig; + this.jedisSocketFactory = new DefaultJedisSocketFactory(hostAndPort, this.clientConfig); + this.clientSideCache = csCache; + } + public ConnectionFactory(final JedisSocketFactory jedisSocketFactory, final JedisClientConfig clientConfig) { - this.clientConfig = DefaultJedisClientConfig.copyConfig(clientConfig); + this.clientConfig = clientConfig; this.jedisSocketFactory = jedisSocketFactory; } @@ -54,9 +60,11 @@ public void destroyObject(PooledObject pooledConnection) throws Exce @Override public PooledObject makeObject() throws Exception { - Connection jedis = null; try { - jedis = new Connection(jedisSocketFactory, clientConfig); + Connection jedis = clientSideCache == null + ? new Connection(jedisSocketFactory, clientConfig) + : new Connection(jedisSocketFactory, clientConfig, clientSideCache); + return new DefaultPooledObject<>(jedis); } catch (JedisException je) { logger.debug("Error while makeObject", je); diff --git a/src/main/java/redis/clients/jedis/ConnectionPool.java b/src/main/java/redis/clients/jedis/ConnectionPool.java index 5899b22260..70202deeae 100644 --- a/src/main/java/redis/clients/jedis/ConnectionPool.java +++ b/src/main/java/redis/clients/jedis/ConnectionPool.java @@ -10,6 +10,10 @@ public ConnectionPool(HostAndPort hostAndPort, JedisClientConfig clientConfig) { this(new ConnectionFactory(hostAndPort, clientConfig)); } + public ConnectionPool(HostAndPort hostAndPort, JedisClientConfig clientConfig, ClientSideCache csCache) { + this(new ConnectionFactory(hostAndPort, clientConfig, csCache)); + } + public ConnectionPool(PooledObjectFactory factory) { super(factory); } @@ -19,6 +23,11 @@ public ConnectionPool(HostAndPort hostAndPort, JedisClientConfig clientConfig, this(new ConnectionFactory(hostAndPort, clientConfig), poolConfig); } + public ConnectionPool(HostAndPort hostAndPort, JedisClientConfig clientConfig, ClientSideCache csCache, + GenericObjectPoolConfig poolConfig) { + this(new ConnectionFactory(hostAndPort, clientConfig, csCache), poolConfig); + } + public ConnectionPool(PooledObjectFactory factory, GenericObjectPoolConfig poolConfig) { super(factory, poolConfig); diff --git a/src/main/java/redis/clients/jedis/JedisClientSideCache.java b/src/main/java/redis/clients/jedis/JedisClientSideCache.java deleted file mode 100644 index 7128f7a1d5..0000000000 --- a/src/main/java/redis/clients/jedis/JedisClientSideCache.java +++ /dev/null @@ -1,44 +0,0 @@ -package redis.clients.jedis; - -import redis.clients.jedis.exceptions.JedisException; - -public class JedisClientSideCache extends Jedis { - - private final ClientSideCache cache; - - public JedisClientSideCache(final HostAndPort hostPort, final JedisClientConfig config) { - this(hostPort, config, new ClientSideCache()); - } - - public JedisClientSideCache(final HostAndPort hostPort, final JedisClientConfig config, - ClientSideCache cache) { - super(hostPort, config); - if (config.getRedisProtocol() != RedisProtocol.RESP3) { - throw new JedisException("Client side caching is only supported with RESP3."); - } - - this.cache = cache; - this.connection.setClientSideCache(cache); - clientTrackingOn(); - } - - private void clientTrackingOn() { - String reply = connection.executeCommand(new CommandObject<>( - new CommandArguments(Protocol.Command.CLIENT).add("TRACKING").add("ON"), - BuilderFactory.STRING)); - if (!"OK".equals(reply)) { - throw new JedisException("Could not enable client tracking. Reply: " + reply); - } - } - - @Override - public String get(String key) { - String cachedValue = cache.getValue(key); - if (cachedValue != null) return cachedValue; - - String value = super.get(key); - if (value != null) cache.setKey(key, value); - return value; - } - -} diff --git a/src/main/java/redis/clients/jedis/JedisCluster.java b/src/main/java/redis/clients/jedis/JedisCluster.java index 55495e6513..0138058d66 100644 --- a/src/main/java/redis/clients/jedis/JedisCluster.java +++ b/src/main/java/redis/clients/jedis/JedisCluster.java @@ -6,7 +6,6 @@ import java.util.Set; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; - import redis.clients.jedis.providers.ClusterConnectionProvider; import redis.clients.jedis.util.JedisClusterCRC16; @@ -198,6 +197,12 @@ public JedisCluster(Set clusterNodes, JedisClientConfig clientConfi Duration.ofMillis((long) clientConfig.getSocketTimeoutMillis() * maxAttempts), poolConfig); } + public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, int maxAttempts, + Duration maxTotalRetriesDuration, GenericObjectPoolConfig poolConfig) { + this(new ClusterConnectionProvider(clusterNodes, clientConfig, poolConfig), maxAttempts, maxTotalRetriesDuration, + clientConfig.getRedisProtocol()); + } + public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, GenericObjectPoolConfig poolConfig, Duration topologyRefreshPeriod, int maxAttempts, Duration maxTotalRetriesDuration) { @@ -205,21 +210,50 @@ public JedisCluster(Set clusterNodes, JedisClientConfig clientConfi maxAttempts, maxTotalRetriesDuration, clientConfig.getRedisProtocol()); } - public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, int maxAttempts, - Duration maxTotalRetriesDuration, GenericObjectPoolConfig poolConfig) { - this(new ClusterConnectionProvider(clusterNodes, clientConfig, poolConfig), maxAttempts, maxTotalRetriesDuration, - clientConfig.getRedisProtocol()); + private JedisCluster(ClusterConnectionProvider provider, int maxAttempts, Duration maxTotalRetriesDuration, + RedisProtocol protocol) { + super(provider, maxAttempts, maxTotalRetriesDuration, protocol); } - // Uses a fetched connection to process protocol. Should be avoided if possible. - public JedisCluster(ClusterConnectionProvider provider, int maxAttempts, + public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, ClientSideCache clientSideCache) { + this(clusterNodes, clientConfig, clientSideCache, DEFAULT_MAX_ATTEMPTS, + Duration.ofMillis(DEFAULT_MAX_ATTEMPTS * clientConfig.getSocketTimeoutMillis())); + } + + public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, ClientSideCache clientSideCache, + int maxAttempts, Duration maxTotalRetriesDuration) { + this(new ClusterConnectionProvider(clusterNodes, clientConfig, clientSideCache), maxAttempts, maxTotalRetriesDuration, + clientConfig.getRedisProtocol(), clientSideCache); + } + + public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, ClientSideCache clientSideCache, + int maxAttempts, Duration maxTotalRetriesDuration, GenericObjectPoolConfig poolConfig) { + this(new ClusterConnectionProvider(clusterNodes, clientConfig, clientSideCache, poolConfig), + maxAttempts, maxTotalRetriesDuration, clientConfig.getRedisProtocol(), clientSideCache); + } + + public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, ClientSideCache clientSideCache, + GenericObjectPoolConfig poolConfig) { + this(new ClusterConnectionProvider(clusterNodes, clientConfig, clientSideCache, poolConfig), + DEFAULT_MAX_ATTEMPTS, Duration.ofMillis(DEFAULT_MAX_ATTEMPTS * clientConfig.getSocketTimeoutMillis()), + clientConfig.getRedisProtocol(), clientSideCache); + } + + public JedisCluster(Set clusterNodes, JedisClientConfig clientConfig, ClientSideCache clientSideCache, + GenericObjectPoolConfig poolConfig, Duration topologyRefreshPeriod, int maxAttempts, Duration maxTotalRetriesDuration) { - super(provider, maxAttempts, maxTotalRetriesDuration); + this(new ClusterConnectionProvider(clusterNodes, clientConfig, clientSideCache, poolConfig, topologyRefreshPeriod), + maxAttempts, maxTotalRetriesDuration, clientConfig.getRedisProtocol(), clientSideCache); } private JedisCluster(ClusterConnectionProvider provider, int maxAttempts, Duration maxTotalRetriesDuration, - RedisProtocol protocol) { - super(provider, maxAttempts, maxTotalRetriesDuration, protocol); + RedisProtocol protocol, ClientSideCache clientSideCache) { + super(provider, maxAttempts, maxTotalRetriesDuration, protocol, clientSideCache); + } + + // Uses a fetched connection to process protocol. Should be avoided if possible. + public JedisCluster(ClusterConnectionProvider provider, int maxAttempts, Duration maxTotalRetriesDuration) { + super(provider, maxAttempts, maxTotalRetriesDuration); } public Map getClusterNodes() { diff --git a/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java b/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java index bea4982fd4..5646dbfb59 100644 --- a/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java +++ b/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java @@ -42,6 +42,7 @@ public class JedisClusterInfoCache { private final GenericObjectPoolConfig poolConfig; private final JedisClientConfig clientConfig; + private final ClientSideCache clientSideCache; private final Set startNodes; private static final int MASTER_NODE_INDEX = 2; @@ -61,19 +62,35 @@ public void run() { } public JedisClusterInfoCache(final JedisClientConfig clientConfig, final Set startNodes) { - this(clientConfig, null, startNodes); + this(clientConfig, null, null, startNodes); + } + + public JedisClusterInfoCache(final JedisClientConfig clientConfig, ClientSideCache csCache, final Set startNodes) { + this(clientConfig, csCache, null, startNodes); } public JedisClusterInfoCache(final JedisClientConfig clientConfig, final GenericObjectPoolConfig poolConfig, final Set startNodes) { - this(clientConfig, poolConfig, startNodes, null); + this(clientConfig, null, poolConfig, startNodes); + } + + public JedisClusterInfoCache(final JedisClientConfig clientConfig, ClientSideCache csCache, + final GenericObjectPoolConfig poolConfig, final Set startNodes) { + this(clientConfig, csCache, poolConfig, startNodes, null); } public JedisClusterInfoCache(final JedisClientConfig clientConfig, final GenericObjectPoolConfig poolConfig, final Set startNodes, final Duration topologyRefreshPeriod) { + this(clientConfig, null, poolConfig, startNodes, topologyRefreshPeriod); + } + + public JedisClusterInfoCache(final JedisClientConfig clientConfig, ClientSideCache csCache, + final GenericObjectPoolConfig poolConfig, final Set startNodes, + final Duration topologyRefreshPeriod) { this.poolConfig = poolConfig; this.clientConfig = clientConfig; + this.clientSideCache = csCache; this.startNodes = startNodes; if (topologyRefreshPeriod != null) { logger.info("Cluster topology refresh start, period: {}, startNodes: {}", topologyRefreshPeriod, startNodes); @@ -209,6 +226,9 @@ private void discoverClusterSlots(Connection jedis) { try { Arrays.fill(slots, null); Arrays.fill(slotNodes, null); + if (clientSideCache != null) { + clientSideCache.clear(); + } Set hostAndPortKeys = new HashSet<>(); for (Object slotInfoObj : slotsInfo) { @@ -270,8 +290,7 @@ public ConnectionPool setupNodeIfNotExist(final HostAndPort node) { ConnectionPool existingPool = nodes.get(nodeKey); if (existingPool != null) return existingPool; - ConnectionPool nodePool = poolConfig == null ? new ConnectionPool(node, clientConfig) - : new ConnectionPool(node, clientConfig, poolConfig); + ConnectionPool nodePool = createNodePool(node); nodes.put(nodeKey, nodePool); return nodePool; } finally { @@ -279,6 +298,22 @@ public ConnectionPool setupNodeIfNotExist(final HostAndPort node) { } } + private ConnectionPool createNodePool(HostAndPort node) { + if (poolConfig == null) { + if (clientSideCache == null) { + return new ConnectionPool(node, clientConfig); + } else { + return new ConnectionPool(node, clientConfig, clientSideCache); + } + } else { + if (clientSideCache == null) { + return new ConnectionPool(node, clientConfig, poolConfig); + } else { + return new ConnectionPool(node, clientConfig, clientSideCache, poolConfig); + } + } + } + public void assignSlotToNode(int slot, HostAndPort targetNode) { w.lock(); try { diff --git a/src/main/java/redis/clients/jedis/JedisFactory.java b/src/main/java/redis/clients/jedis/JedisFactory.java index b84e2b05ae..820a066a0d 100644 --- a/src/main/java/redis/clients/jedis/JedisFactory.java +++ b/src/main/java/redis/clients/jedis/JedisFactory.java @@ -66,7 +66,7 @@ protected JedisFactory(final String host, final int port, final int connectionTi } protected JedisFactory(final HostAndPort hostAndPort, final JedisClientConfig clientConfig) { - this.clientConfig = DefaultJedisClientConfig.copyConfig(clientConfig); + this.clientConfig = clientConfig; this.jedisSocketFactory = new DefaultJedisSocketFactory(hostAndPort, this.clientConfig); } @@ -83,7 +83,7 @@ protected JedisFactory(final String host, final int port, final int connectionTi } protected JedisFactory(final JedisSocketFactory jedisSocketFactory, final JedisClientConfig clientConfig) { - this.clientConfig = DefaultJedisClientConfig.copyConfig(clientConfig); + this.clientConfig = clientConfig; this.jedisSocketFactory = jedisSocketFactory; } diff --git a/src/main/java/redis/clients/jedis/JedisPooled.java b/src/main/java/redis/clients/jedis/JedisPooled.java index c6d022e094..44e476d7b8 100644 --- a/src/main/java/redis/clients/jedis/JedisPooled.java +++ b/src/main/java/redis/clients/jedis/JedisPooled.java @@ -7,7 +7,6 @@ import org.apache.commons.pool2.PooledObjectFactory; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; - import redis.clients.jedis.providers.PooledConnectionProvider; import redis.clients.jedis.util.JedisURIHelper; import redis.clients.jedis.util.Pool; @@ -76,6 +75,10 @@ public JedisPooled(final HostAndPort hostAndPort, final JedisClientConfig client super(hostAndPort, clientConfig); } + public JedisPooled(final HostAndPort hostAndPort, final JedisClientConfig clientConfig, ClientSideCache csCache) { + super(new PooledConnectionProvider(hostAndPort, clientConfig, csCache), clientConfig.getRedisProtocol(), csCache); + } + public JedisPooled(PooledObjectFactory factory) { this(new PooledConnectionProvider(factory)); } @@ -376,6 +379,12 @@ public JedisPooled(final HostAndPort hostAndPort, final JedisClientConfig client super(new PooledConnectionProvider(hostAndPort, clientConfig, poolConfig), clientConfig.getRedisProtocol()); } + public JedisPooled(final HostAndPort hostAndPort, final JedisClientConfig clientConfig, ClientSideCache csCache, + final GenericObjectPoolConfig poolConfig) { + super(new PooledConnectionProvider(hostAndPort, clientConfig, csCache, poolConfig), + clientConfig.getRedisProtocol(), csCache); + } + public JedisPooled(final GenericObjectPoolConfig poolConfig, final JedisSocketFactory jedisSocketFactory, final JedisClientConfig clientConfig) { super(new PooledConnectionProvider(new ConnectionFactory(jedisSocketFactory, clientConfig), poolConfig), diff --git a/src/main/java/redis/clients/jedis/JedisSentineled.java b/src/main/java/redis/clients/jedis/JedisSentineled.java index 0ea0221c1a..f1cb8ea650 100644 --- a/src/main/java/redis/clients/jedis/JedisSentineled.java +++ b/src/main/java/redis/clients/jedis/JedisSentineled.java @@ -12,6 +12,12 @@ public JedisSentineled(String masterName, final JedisClientConfig masterClientCo masterClientConfig.getRedisProtocol()); } + public JedisSentineled(String masterName, final JedisClientConfig masterClientConfig, ClientSideCache clientSideCache, + Set sentinels, final JedisClientConfig sentinelClientConfig) { + super(new SentineledConnectionProvider(masterName, masterClientConfig, clientSideCache, + sentinels, sentinelClientConfig), masterClientConfig.getRedisProtocol(), clientSideCache); + } + public JedisSentineled(String masterName, final JedisClientConfig masterClientConfig, final GenericObjectPoolConfig poolConfig, Set sentinels, final JedisClientConfig sentinelClientConfig) { @@ -19,6 +25,13 @@ public JedisSentineled(String masterName, final JedisClientConfig masterClientCo masterClientConfig.getRedisProtocol()); } + public JedisSentineled(String masterName, final JedisClientConfig masterClientConfig, ClientSideCache clientSideCache, + final GenericObjectPoolConfig poolConfig, + Set sentinels, final JedisClientConfig sentinelClientConfig) { + super(new SentineledConnectionProvider(masterName, masterClientConfig, clientSideCache, poolConfig, + sentinels, sentinelClientConfig), masterClientConfig.getRedisProtocol(), clientSideCache); + } + public JedisSentineled(SentineledConnectionProvider sentineledConnectionProvider) { super(sentineledConnectionProvider); } diff --git a/src/main/java/redis/clients/jedis/UnifiedJedis.java b/src/main/java/redis/clients/jedis/UnifiedJedis.java index b628be6933..ba7b36b134 100644 --- a/src/main/java/redis/clients/jedis/UnifiedJedis.java +++ b/src/main/java/redis/clients/jedis/UnifiedJedis.java @@ -48,7 +48,8 @@ public class UnifiedJedis implements JedisCommands, JedisBinaryCommands, SampleKeyedCommands, SampleBinaryKeyedCommands, RedisModuleCommands, AutoCloseable { - protected RedisProtocol protocol = null; + @Deprecated protected RedisProtocol protocol = null; + private final ClientSideCache clientSideCache; protected final ConnectionProvider provider; protected final CommandExecutor executor; protected final CommandObjects commandObjects; @@ -99,6 +100,10 @@ protected UnifiedJedis(ConnectionProvider provider, RedisProtocol protocol) { this(new DefaultCommandExecutor(provider), provider, new CommandObjects(), protocol); } + protected UnifiedJedis(ConnectionProvider provider, RedisProtocol protocol, ClientSideCache clientSideCache) { + this(new DefaultCommandExecutor(provider), provider, new CommandObjects(), protocol, clientSideCache); + } + /** * The constructor to directly use a custom {@link JedisSocketFactory}. *

@@ -132,6 +137,7 @@ public UnifiedJedis(Connection connection) { RedisProtocol proto = connection.getRedisProtocol(); if (proto != null) this.commandObjects.setProtocol(proto); this.graphCommandObjects = new GraphCommandObjects(this); + this.clientSideCache = null; // TODO: } @Deprecated @@ -165,6 +171,12 @@ protected UnifiedJedis(ClusterConnectionProvider provider, int maxAttempts, Dura new ClusterCommandObjects(), protocol); } + protected UnifiedJedis(ClusterConnectionProvider provider, int maxAttempts, Duration maxTotalRetriesDuration, + RedisProtocol protocol, ClientSideCache clientSideCache) { + this(new ClusterCommandExecutor(provider, maxAttempts, maxTotalRetriesDuration), provider, + new ClusterCommandObjects(), protocol, clientSideCache); + } + /** * @deprecated Sharding/Sharded feature will be removed in next major release. */ @@ -212,7 +224,7 @@ private UnifiedJedis(CommandExecutor executor, ConnectionProvider provider) { // Uses a fetched connection to process protocol. Should be avoided if possible. private UnifiedJedis(CommandExecutor executor, ConnectionProvider provider, CommandObjects commandObjects) { - this(executor, provider, commandObjects, null); + this(executor, provider, commandObjects, null, null); if (this.provider != null) { try (Connection conn = this.provider.getConnection()) { if (conn != null) { @@ -225,16 +237,26 @@ private UnifiedJedis(CommandExecutor executor, ConnectionProvider provider, Comm private UnifiedJedis(CommandExecutor executor, ConnectionProvider provider, CommandObjects commandObjects, RedisProtocol protocol) { + this(executor, provider, commandObjects, protocol, (ClientSideCache) null); + } + + private UnifiedJedis(CommandExecutor executor, ConnectionProvider provider, CommandObjects commandObjects, + RedisProtocol protocol, ClientSideCache clientSideCache) { + + if (clientSideCache != null && protocol != RedisProtocol.RESP3) { + throw new IllegalArgumentException("Client-side caching is only supported with RESP3."); + } + this.provider = provider; 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 @@ -727,6 +749,14 @@ public String set(String key, String value, SetParams params) { @Override public String get(String key) { + if (clientSideCache != null) { + String cachedValue = clientSideCache.getValue(key); + if (cachedValue != null) return cachedValue; + + String value = executeCommand(commandObjects.get(key)); + if (value != null) clientSideCache.setKey(key, value); + return value; + } return executeCommand(commandObjects.get(key)); } diff --git a/src/main/java/redis/clients/jedis/providers/ClusterConnectionProvider.java b/src/main/java/redis/clients/jedis/providers/ClusterConnectionProvider.java index c21640713d..be83aa7388 100644 --- a/src/main/java/redis/clients/jedis/providers/ClusterConnectionProvider.java +++ b/src/main/java/redis/clients/jedis/providers/ClusterConnectionProvider.java @@ -8,6 +8,7 @@ import java.util.Set; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import redis.clients.jedis.ClientSideCache; import redis.clients.jedis.ClusterCommandArguments; import redis.clients.jedis.CommandArguments; import redis.clients.jedis.HostAndPort; @@ -29,18 +30,35 @@ public ClusterConnectionProvider(Set clusterNodes, JedisClientConfi initializeSlotsCache(clusterNodes, clientConfig); } + public ClusterConnectionProvider(Set clusterNodes, JedisClientConfig clientConfig, ClientSideCache csCache) { + this.cache = new JedisClusterInfoCache(clientConfig, csCache, clusterNodes); + initializeSlotsCache(clusterNodes, clientConfig); + } + public ClusterConnectionProvider(Set clusterNodes, JedisClientConfig clientConfig, GenericObjectPoolConfig poolConfig) { this.cache = new JedisClusterInfoCache(clientConfig, poolConfig, clusterNodes); initializeSlotsCache(clusterNodes, clientConfig); } + public ClusterConnectionProvider(Set clusterNodes, JedisClientConfig clientConfig, ClientSideCache csCache, + GenericObjectPoolConfig poolConfig) { + this.cache = new JedisClusterInfoCache(clientConfig, csCache, poolConfig, clusterNodes); + initializeSlotsCache(clusterNodes, clientConfig); + } + public ClusterConnectionProvider(Set clusterNodes, JedisClientConfig clientConfig, GenericObjectPoolConfig poolConfig, Duration topologyRefreshPeriod) { this.cache = new JedisClusterInfoCache(clientConfig, poolConfig, clusterNodes, topologyRefreshPeriod); initializeSlotsCache(clusterNodes, clientConfig); } + public ClusterConnectionProvider(Set clusterNodes, JedisClientConfig clientConfig, ClientSideCache csCache, + GenericObjectPoolConfig poolConfig, Duration topologyRefreshPeriod) { + this.cache = new JedisClusterInfoCache(clientConfig, csCache, poolConfig, clusterNodes, topologyRefreshPeriod); + initializeSlotsCache(clusterNodes, clientConfig); + } + private void initializeSlotsCache(Set startNodes, JedisClientConfig clientConfig) { if (startNodes.isEmpty()) { throw new JedisClusterOperationException("No nodes to initialize cluster slots cache."); diff --git a/src/main/java/redis/clients/jedis/providers/PooledConnectionProvider.java b/src/main/java/redis/clients/jedis/providers/PooledConnectionProvider.java index f7b90e2953..85fa3cecd2 100644 --- a/src/main/java/redis/clients/jedis/providers/PooledConnectionProvider.java +++ b/src/main/java/redis/clients/jedis/providers/PooledConnectionProvider.java @@ -5,6 +5,7 @@ import org.apache.commons.pool2.PooledObjectFactory; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import redis.clients.jedis.ClientSideCache; import redis.clients.jedis.CommandArguments; import redis.clients.jedis.Connection; import redis.clients.jedis.ConnectionFactory; @@ -28,9 +29,20 @@ public PooledConnectionProvider(HostAndPort hostAndPort, JedisClientConfig clien this.connectionMapKey = hostAndPort; } + public PooledConnectionProvider(HostAndPort hostAndPort, JedisClientConfig clientConfig, ClientSideCache csCache) { + this(new ConnectionPool(hostAndPort, clientConfig, csCache)); + this.connectionMapKey = hostAndPort; + } + public PooledConnectionProvider(HostAndPort hostAndPort, JedisClientConfig clientConfig, GenericObjectPoolConfig poolConfig) { - this(new ConnectionFactory(hostAndPort, clientConfig), poolConfig); + this(new ConnectionPool(hostAndPort, clientConfig, poolConfig)); + this.connectionMapKey = hostAndPort; + } + + public PooledConnectionProvider(HostAndPort hostAndPort, JedisClientConfig clientConfig, ClientSideCache csCache, + GenericObjectPoolConfig poolConfig) { + this(new ConnectionPool(hostAndPort, clientConfig, csCache, 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 5058f07179..e335803b62 100644 --- a/src/main/java/redis/clients/jedis/providers/SentineledConnectionProvider.java +++ b/src/main/java/redis/clients/jedis/providers/SentineledConnectionProvider.java @@ -10,6 +10,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import redis.clients.jedis.ClientSideCache; import redis.clients.jedis.CommandArguments; import redis.clients.jedis.Connection; import redis.clients.jedis.ConnectionPool; @@ -35,6 +36,8 @@ public class SentineledConnectionProvider implements ConnectionProvider { private final JedisClientConfig masterClientConfig; + private final ClientSideCache clientSideCache; + private final GenericObjectPoolConfig masterPoolConfig; protected final Collection sentinelListeners = new ArrayList<>(); @@ -47,7 +50,12 @@ public class SentineledConnectionProvider implements ConnectionProvider { public SentineledConnectionProvider(String masterName, final JedisClientConfig masterClientConfig, Set sentinels, final JedisClientConfig sentinelClientConfig) { - this(masterName, masterClientConfig, /*poolConfig*/ null, sentinels, sentinelClientConfig); + this(masterName, masterClientConfig, null, null, sentinels, sentinelClientConfig); + } + + public SentineledConnectionProvider(String masterName, final JedisClientConfig masterClientConfig, + ClientSideCache clientSideCache, Set sentinels, final JedisClientConfig sentinelClientConfig) { + this(masterName, masterClientConfig, clientSideCache, null, sentinels, sentinelClientConfig); } public SentineledConnectionProvider(String masterName, final JedisClientConfig masterClientConfig, @@ -57,13 +65,28 @@ public SentineledConnectionProvider(String masterName, final JedisClientConfig m DEFAULT_SUBSCRIBE_RETRY_WAIT_TIME_MILLIS); } + public SentineledConnectionProvider(String masterName, final JedisClientConfig masterClientConfig, + ClientSideCache clientSideCache, final GenericObjectPoolConfig poolConfig, + Set sentinels, final JedisClientConfig sentinelClientConfig) { + this(masterName, masterClientConfig, clientSideCache, poolConfig, sentinels, sentinelClientConfig, + DEFAULT_SUBSCRIBE_RETRY_WAIT_TIME_MILLIS); + } + public SentineledConnectionProvider(String masterName, final JedisClientConfig masterClientConfig, final GenericObjectPoolConfig poolConfig, Set sentinels, final JedisClientConfig sentinelClientConfig, final long subscribeRetryWaitTimeMillis) { + this(masterName, masterClientConfig, null, poolConfig, sentinels, sentinelClientConfig, subscribeRetryWaitTimeMillis); + } + + public SentineledConnectionProvider(String masterName, final JedisClientConfig masterClientConfig, + ClientSideCache clientSideCache, final GenericObjectPoolConfig poolConfig, + Set sentinels, final JedisClientConfig sentinelClientConfig, + final long subscribeRetryWaitTimeMillis) { this.masterName = masterName; this.masterClientConfig = masterClientConfig; + this.clientSideCache = clientSideCache; this.masterPoolConfig = poolConfig; this.sentinelClientConfig = sentinelClientConfig; @@ -99,13 +122,14 @@ private void initMaster(HostAndPort master) { if (!master.equals(currentMaster)) { currentMaster = master; - ConnectionPool newPool = masterPoolConfig != null - ? new ConnectionPool(currentMaster, masterClientConfig, masterPoolConfig) - : new ConnectionPool(currentMaster, masterClientConfig); + ConnectionPool newPool = createNodePool(currentMaster); ConnectionPool existingPool = pool; pool = newPool; LOG.info("Created connection pool to master at {}.", master); + if (clientSideCache != null) { + clientSideCache.clear(); + } if (existingPool != null) { // although we clear the pool, we still have to check the returned object in getResource, @@ -117,6 +141,22 @@ private void initMaster(HostAndPort master) { } } + private ConnectionPool createNodePool(HostAndPort master) { + if (masterPoolConfig == null) { + if (clientSideCache == null) { + return new ConnectionPool(master, masterClientConfig); + } else { + return new ConnectionPool(master, masterClientConfig, clientSideCache); + } + } else { + if (clientSideCache == null) { + return new ConnectionPool(master, masterClientConfig, masterPoolConfig); + } else { + return new ConnectionPool(master, masterClientConfig, clientSideCache, masterPoolConfig); + } + } + } + private HostAndPort initSentinels(Set sentinels) { HostAndPort master = null; diff --git a/src/test/java/redis/clients/jedis/JedisClientSideCacheTest.java b/src/test/java/redis/clients/jedis/JedisClientSideCacheTest.java deleted file mode 100644 index 5b9f8b2319..0000000000 --- a/src/test/java/redis/clients/jedis/JedisClientSideCacheTest.java +++ /dev/null @@ -1,110 +0,0 @@ -package redis.clients.jedis; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import org.hamcrest.Matchers; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.Mockito; - -public class JedisClientSideCacheTest { - - protected static final HostAndPort hnp = HostAndPorts.getRedisServers().get(1); - - protected Jedis jedis; - - @Before - public void setUp() throws Exception { - jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().password("foobared").build()); - jedis.flushAll(); - } - - @After - public void tearDown() throws Exception { - jedis.close(); - } - - private static final JedisClientConfig clientConfig = DefaultJedisClientConfig.builder().resp3().password("foobared").build(); - - @Test - public void simple() { - try (JedisClientSideCache jCache = new JedisClientSideCache(hnp, clientConfig)) { - jedis.set("foo", "bar"); - assertEquals("bar", jCache.get("foo")); - jedis.del("foo"); - assertThat(jCache.get("foo"), Matchers.oneOf("bar", null)); // ? - } - } - - @Test - public void simpleMoreAndMock() { - ClientSideCache cache = Mockito.mock(ClientSideCache.class); - Mockito.when(cache.getValue("foo")).thenReturn(null, "bar", null); - - try (JedisClientSideCache jCache = new JedisClientSideCache(hnp, clientConfig, cache)) { - jedis.set("foo", "bar"); - - assertEquals("bar", jCache.get("foo")); - - jedis.del("foo"); - - assertEquals("bar", jCache.get("foo")); - - // there should be an invalid pending; any connection command will make it read - jCache.ping(); - - assertNull(jCache.get("foo")); - } - - InOrder inOrder = Mockito.inOrder(cache); - inOrder.verify(cache).getValue("foo"); - inOrder.verify(cache).setKey("foo", "bar"); - inOrder.verify(cache).getValue("foo"); - inOrder.verify(cache).invalidateKeys(Mockito.notNull()); - inOrder.verify(cache).getValue("foo"); - inOrder.verifyNoMoreInteractions(); - } - - @Test - public void flushAll() { - try (JedisClientSideCache jCache = new JedisClientSideCache(hnp, clientConfig)) { - jedis.set("foo", "bar"); - assertEquals("bar", jCache.get("foo")); - jedis.flushAll(); - assertThat(jCache.get("foo"), Matchers.oneOf("bar", null)); // ? - } - } - - @Test - public void flushAllMoreAndMock() { - ClientSideCache cache = Mockito.mock(ClientSideCache.class); - Mockito.when(cache.getValue("foo")).thenReturn(null, "bar", null); - - try (JedisClientSideCache jCache = new JedisClientSideCache(hnp, clientConfig, cache)) { - jedis.set("foo", "bar"); - - assertEquals("bar", jCache.get("foo")); - - jedis.flushAll(); - - assertEquals("bar", jCache.get("foo")); - - // there should be an invalid pending; any connection command will make it read - jCache.ping(); - - assertNull(jCache.get("foo")); - } - - InOrder inOrder = Mockito.inOrder(cache); - inOrder.verify(cache).getValue("foo"); - inOrder.verify(cache).setKey("foo", "bar"); - inOrder.verify(cache).getValue("foo"); - inOrder.verify(cache).invalidateKeys(Mockito.isNull()); - inOrder.verify(cache).getValue("foo"); - inOrder.verifyNoMoreInteractions(); - } -} diff --git a/src/test/java/redis/clients/jedis/JedisClusterClientSideCacheTest.java b/src/test/java/redis/clients/jedis/JedisClusterClientSideCacheTest.java new file mode 100644 index 0000000000..3c8bc18c5c --- /dev/null +++ b/src/test/java/redis/clients/jedis/JedisClusterClientSideCacheTest.java @@ -0,0 +1,89 @@ +package redis.clients.jedis; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.hamcrest.Matchers; +import org.junit.Test; + +public class JedisClusterClientSideCacheTest extends JedisClusterTestBase { + + private static final Set hnp = Arrays.asList(nodeInfo1, nodeInfo2, nodeInfo3).stream().collect(Collectors.toSet()); + + private static final Supplier clientConfig + = () -> DefaultJedisClientConfig.builder().resp3().password("cluster").build(); + + private static final Supplier> singleConnectionPoolConfig + = () -> { + ConnectionPoolConfig poolConfig = new ConnectionPoolConfig(); + poolConfig.setMaxTotal(1); + return poolConfig; + }; + + @Test + public void simple() { + try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new ClientSideCache())) { + jedis.set("foo", "bar"); + assertEquals("bar", jedis.get("foo")); + jedis.del("foo"); + assertThat(jedis.get("foo"), Matchers.oneOf("bar", null)); // ? + } + } + + @Test + public void simpleWithSimpleMap() { + HashMap map = new HashMap<>(); + try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new ClientSideCache(map), singleConnectionPoolConfig.get())) { + jedis.set("foo", "bar"); + assertThat(map, Matchers.aMapWithSize(0)); + assertEquals("bar", jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(1)); + jedis.del("foo"); + assertThat(map, Matchers.aMapWithSize(1)); + assertEquals("bar", jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(1)); + jedis.ping(); + assertThat(map, Matchers.aMapWithSize(0)); + assertNull(jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(0)); + } + } + + @Test + public void flushAll() { + try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new ClientSideCache())) { + jedis.set("foo", "bar"); + assertEquals("bar", jedis.get("foo")); + jedis.flushAll(); + assertThat(jedis.get("foo"), Matchers.oneOf("bar", null)); // ? + } + } + + @Test + public void flushAllWithSimpleMap() { + HashMap map = new HashMap<>(); + try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new ClientSideCache(map), singleConnectionPoolConfig.get())) { + jedis.set("foo", "bar"); + assertThat(map, Matchers.aMapWithSize(0)); + assertEquals("bar", jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(1)); + jedis.flushAll(); + assertThat(map, Matchers.aMapWithSize(1)); + assertEquals("bar", jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(1)); + jedis.ping(); + assertThat(map, Matchers.aMapWithSize(0)); + assertNull(jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(0)); + } + } +} diff --git a/src/test/java/redis/clients/jedis/JedisClusterTest.java b/src/test/java/redis/clients/jedis/JedisClusterTest.java index 8297eb90c6..f12175728c 100644 --- a/src/test/java/redis/clients/jedis/JedisClusterTest.java +++ b/src/test/java/redis/clients/jedis/JedisClusterTest.java @@ -108,16 +108,6 @@ public void testSetClientName() { try (JedisCluster jc = new JedisCluster(jedisClusterNode, DEFAULT_TIMEOUT, DEFAULT_TIMEOUT, DEFAULT_REDIRECTIONS, "cluster", clientName, DEFAULT_POOL_CONFIG)) { -// Map clusterNodes = jc.getClusterNodes(); -// Collection values = clusterNodes.values(); -// for (JedisPool jedisPool : values) { -// Jedis jedis = jedisPool.getResource(); -// try { -// assertEquals(clientName, jedis.clientGetname()); -// } finally { -// jedis.close(); -// } -// } for (Pool pool : jc.getClusterNodes().values()) { try (Jedis jedis = new Jedis(pool.getResource())) { assertEquals(clientName, jedis.clientGetname()); @@ -133,11 +123,6 @@ public void testSetClientNameWithConfig() { try (JedisCluster jc = new JedisCluster(Collections.singleton(hp), DefaultJedisClientConfig.builder().password("cluster").clientName(clientName).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { -// jc.getClusterNodes().values().forEach(jedisPool -> { -// try (Jedis jedis = jedisPool.getResource()) { -// assertEquals(clientName, jedis.clientGetname()); -// } -// }); jc.getClusterNodes().values().forEach(pool -> { try (Jedis jedis = new Jedis(pool.getResource())) { assertEquals(clientName, jedis.clientGetname()); @@ -486,7 +471,6 @@ public void testStableSlotWhenMigratingNodeOrImportingNodeIsNotSpecified() } } -// @Test(expected = JedisExhaustedPoolException.class) @Test(expected = JedisException.class) public void testIfPoolConfigAppliesToClusterPools() { GenericObjectPoolConfig config = new GenericObjectPoolConfig<>(); @@ -533,12 +517,6 @@ public void testJedisClusterTimeout() { try (JedisCluster jc = new JedisCluster(jedisClusterNode, 4000, 4000, DEFAULT_REDIRECTIONS, "cluster", DEFAULT_POOL_CONFIG)) { -// for (JedisPool pool : jc.getClusterNodes().values()) { -// Jedis jedis = pool.getResource(); -// assertEquals(4000, jedis.getClient().getConnectionTimeout()); -// assertEquals(4000, jedis.getClient().getSoTimeout()); -// jedis.close(); -// } for (Pool pool : jc.getClusterNodes().values()) { try (Connection conn = pool.getResource()) { assertEquals(4000, conn.getSoTimeout()); @@ -555,10 +533,6 @@ public void testJedisClusterTimeoutWithConfig() { DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { jc.getClusterNodes().values().forEach(pool -> { -// try (Jedis jedis = pool.getResource()) { -// assertEquals(4000, jedis.getClient().getConnectionTimeout()); -// assertEquals(4000, jedis.getClient().getSoTimeout()); -// } try (Connection conn = pool.getResource()) { assertEquals(4000, conn.getSoTimeout()); } @@ -606,10 +580,6 @@ public void testReturnConnectionOnJedisConnectionException() throws InterruptedE try (JedisCluster jc = new JedisCluster(jedisClusterNode, DEFAULT_TIMEOUT, DEFAULT_TIMEOUT, DEFAULT_REDIRECTIONS, "cluster", config)) { -// try (Jedis j = jc.getClusterNodes().get("127.0.0.1:7380").getResource()) { -// ClientKillerUtil.tagClient(j, "DEAD"); -// ClientKillerUtil.killClient(j, "DEAD"); -// } try (Connection c = jc.getClusterNodes().get("127.0.0.1:7380").getResource()) { Jedis j = new Jedis(c); ClientKillerUtil.tagClient(j, "DEAD"); @@ -647,7 +617,6 @@ public void testLocalhostNodeNotAddedWhen127Present() { try (JedisCluster jc = new JedisCluster(jedisClusterNode, DEFAULT_TIMEOUT, DEFAULT_TIMEOUT, DEFAULT_REDIRECTIONS, "cluster", config)) { -// Map clusterNodes = jc.getClusterNodes(); Map clusterNodes = jc.getClusterNodes(); assertEquals(3, clusterNodes.size()); assertFalse(clusterNodes.containsKey(JedisClusterInfoCache.getNodeKey(localhost))); @@ -664,7 +633,6 @@ public void testInvalidStartNodeNotAdded() { config.setMaxTotal(1); try (JedisCluster jc = new JedisCluster(jedisClusterNode, DEFAULT_TIMEOUT, DEFAULT_TIMEOUT, DEFAULT_REDIRECTIONS, "cluster", config)) { -// Map clusterNodes = jc.getClusterNodes(); Map clusterNodes = jc.getClusterNodes(); assertEquals(3, clusterNodes.size()); assertFalse(clusterNodes.containsKey(JedisClusterInfoCache.getNodeKey(invalidHost))); diff --git a/src/test/java/redis/clients/jedis/JedisClusterTestBase.java b/src/test/java/redis/clients/jedis/JedisClusterTestBase.java index 0746c2d37c..bb6656a812 100644 --- a/src/test/java/redis/clients/jedis/JedisClusterTestBase.java +++ b/src/test/java/redis/clients/jedis/JedisClusterTestBase.java @@ -15,11 +15,11 @@ public abstract class JedisClusterTestBase { protected static Jedis node4; protected static Jedis nodeSlave2; - protected HostAndPort nodeInfo1 = HostAndPorts.getClusterServers().get(0); - protected HostAndPort nodeInfo2 = HostAndPorts.getClusterServers().get(1); - protected HostAndPort nodeInfo3 = HostAndPorts.getClusterServers().get(2); - protected HostAndPort nodeInfo4 = HostAndPorts.getClusterServers().get(3); - protected HostAndPort nodeInfoSlave2 = HostAndPorts.getClusterServers().get(4); + protected static HostAndPort nodeInfo1 = HostAndPorts.getClusterServers().get(0); + protected static HostAndPort nodeInfo2 = HostAndPorts.getClusterServers().get(1); + protected static HostAndPort nodeInfo3 = HostAndPorts.getClusterServers().get(2); + protected static HostAndPort nodeInfo4 = HostAndPorts.getClusterServers().get(3); + protected static HostAndPort nodeInfoSlave2 = HostAndPorts.getClusterServers().get(4); protected static final String LOCAL_IP = "127.0.0.1"; diff --git a/src/test/java/redis/clients/jedis/JedisPooledClientSideCacheTest.java b/src/test/java/redis/clients/jedis/JedisPooledClientSideCacheTest.java new file mode 100644 index 0000000000..ad4313a4b7 --- /dev/null +++ b/src/test/java/redis/clients/jedis/JedisPooledClientSideCacheTest.java @@ -0,0 +1,100 @@ +package redis.clients.jedis; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.nio.ByteBuffer; +import java.util.HashMap; +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.Test; + +public class JedisPooledClientSideCacheTest { + + protected static final HostAndPort hnp = HostAndPorts.getRedisServers().get(1); + + protected Jedis control; + + @Before + public void setUp() throws Exception { + control = new Jedis(hnp, DefaultJedisClientConfig.builder().password("foobared").build()); + control.flushAll(); + } + + @After + public void tearDown() throws Exception { + control.close(); + } + + private static final Supplier clientConfig + = () -> DefaultJedisClientConfig.builder().resp3().password("foobared").build(); + + private static final Supplier> singleConnectionPoolConfig + = () -> { + ConnectionPoolConfig poolConfig = new ConnectionPoolConfig(); + poolConfig.setMaxTotal(1); + return poolConfig; + }; + + @Test + public void simple() { + try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new ClientSideCache())) { + control.set("foo", "bar"); + assertEquals("bar", jedis.get("foo")); + control.del("foo"); + assertThat(jedis.get("foo"), Matchers.oneOf("bar", null)); // ? + } + } + + @Test + public void simpleWithSimpleMap() { + HashMap map = new HashMap<>(); + try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new ClientSideCache(map), singleConnectionPoolConfig.get())) { + control.set("foo", "bar"); + assertThat(map, Matchers.aMapWithSize(0)); + assertEquals("bar", jedis.get("foo")); + 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(); + assertThat(map, Matchers.aMapWithSize(0)); + assertNull(jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(0)); + } + } + + @Test + public void flushAll() { + try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new ClientSideCache())) { + control.set("foo", "bar"); + assertEquals("bar", jedis.get("foo")); + control.flushAll(); + assertThat(jedis.get("foo"), Matchers.oneOf("bar", null)); // ? + } + } + + @Test + public void flushAllWithSimpleMap() { + HashMap map = new HashMap<>(); + try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new ClientSideCache(map), singleConnectionPoolConfig.get())) { + control.set("foo", "bar"); + assertThat(map, Matchers.aMapWithSize(0)); + assertEquals("bar", jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(1)); + control.flushAll(); + assertThat(map, Matchers.aMapWithSize(1)); + assertEquals("bar", jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(1)); + jedis.ping(); + assertThat(map, Matchers.aMapWithSize(0)); + assertNull(jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(0)); + } + } +} diff --git a/src/test/java/redis/clients/jedis/JedisSentineledClientSideCacheTest.java b/src/test/java/redis/clients/jedis/JedisSentineledClientSideCacheTest.java new file mode 100644 index 0000000000..9af243ffc7 --- /dev/null +++ b/src/test/java/redis/clients/jedis/JedisSentineledClientSideCacheTest.java @@ -0,0 +1,95 @@ +package redis.clients.jedis; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.hamcrest.Matchers; +import org.junit.Test; + +public class JedisSentineledClientSideCacheTest { + + private static final String MASTER_NAME = "mymaster"; + + protected static final HostAndPort sentinel1 = HostAndPorts.getSentinelServers().get(1); + protected static final HostAndPort sentinel2 = HostAndPorts.getSentinelServers().get(3); + + private static final Set sentinels = Arrays.asList(sentinel1, sentinel2).stream().collect(Collectors.toSet()); + + private static final JedisClientConfig masterClientConfig = DefaultJedisClientConfig.builder().resp3().password("foobared").build(); + + private static final JedisClientConfig sentinelClientConfig = DefaultJedisClientConfig.builder().resp3().build(); + + private static final Supplier> singleConnectionPoolConfig + = () -> { + ConnectionPoolConfig poolConfig = new ConnectionPoolConfig(); + poolConfig.setMaxTotal(1); + return poolConfig; + }; + + @Test + public void simple() { + try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new ClientSideCache(), sentinels, sentinelClientConfig)) { + jedis.set("foo", "bar"); + assertEquals("bar", jedis.get("foo")); + jedis.del("foo"); + assertThat(jedis.get("foo"), Matchers.oneOf("bar", null)); // ? + } + } + + @Test + public void simpleWithSimpleMap() { + HashMap map = new HashMap<>(); + try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new ClientSideCache(map), sentinels, sentinelClientConfig)) { + jedis.set("foo", "bar"); + assertThat(map, Matchers.aMapWithSize(0)); + assertEquals("bar", jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(1)); + jedis.del("foo"); + assertThat(map, Matchers.aMapWithSize(1)); + assertEquals("bar", jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(1)); + jedis.ping(); + assertThat(map, Matchers.aMapWithSize(0)); + assertNull(jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(0)); + } + } + + @Test + public void flushAll() { + try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new ClientSideCache(), sentinels, sentinelClientConfig)) { + jedis.set("foo", "bar"); + assertEquals("bar", jedis.get("foo")); + jedis.flushAll(); + assertThat(jedis.get("foo"), Matchers.oneOf("bar", null)); // ? + } + } + + @Test + public void flushAllWithSimpleMap() { + HashMap map = new HashMap<>(); + try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new ClientSideCache(map), sentinels, sentinelClientConfig)) { + jedis.set("foo", "bar"); + assertThat(map, Matchers.aMapWithSize(0)); + assertEquals("bar", jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(1)); + jedis.flushAll(); + assertThat(map, Matchers.aMapWithSize(1)); + assertEquals("bar", jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(1)); + jedis.ping(); + assertThat(map, Matchers.aMapWithSize(0)); + assertNull(jedis.get("foo")); + assertThat(map, Matchers.aMapWithSize(0)); + } + } +} diff --git a/src/test/java/redis/clients/jedis/SentineledConnectionProviderTest.java b/src/test/java/redis/clients/jedis/SentineledConnectionProviderTest.java index 593875710b..746c50bc43 100644 --- a/src/test/java/redis/clients/jedis/SentineledConnectionProviderTest.java +++ b/src/test/java/redis/clients/jedis/SentineledConnectionProviderTest.java @@ -22,9 +22,6 @@ public class SentineledConnectionProviderTest { private static final String MASTER_NAME = "mymaster"; - //protected static HostAndPort master = HostAndPorts.getRedisServers().get(2); - //protected static HostAndPort slave1 = HostAndPorts.getRedisServers().get(3); - protected static final HostAndPort sentinel1 = HostAndPorts.getSentinelServers().get(1); protected static final HostAndPort sentinel2 = HostAndPorts.getSentinelServers().get(3);