diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc index 3829e5bca..94b019f4c 100644 --- a/src/main/asciidoc/new-features.adoc +++ b/src/main/asciidoc/new-features.adoc @@ -8,6 +8,7 @@ New and noteworthy in the latest releases. * Support for Redis http://redis.io/commands#geo[GEO] commands. * Support for Geospatial Indexes using Spring Data Repository abstractions (see <>). +* Upgrade to `Lettuce` 4.2. Lettuce 4.2 requires Java 8. [[new-in-1.7.0]] == New in Spring Data Redis 1.7 diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClient.java b/src/main/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClient.java index 1853d6da4..ffb2dd3ef 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClient.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,16 +41,28 @@ public class AuthenticatingRedisClient extends RedisClient { super(null, RedisURI.builder().withHost(host).withPassword(password).build()); } + /* + * (non-Javadoc) + * @see com.lambdaworks.redis.RedisClient#connect(com.lambdaworks.redis.codec.RedisCodec) + */ @Override public StatefulRedisConnection connect(RedisCodec codec) { return super.connect(codec); } + /* + * (non-Javadoc) + * @see com.lambdaworks.redis.RedisClient#connectAsync(com.lambdaworks.redis.codec.RedisCodec) + */ @Override public RedisAsyncCommands connectAsync(RedisCodec codec) { return super.connectAsync(codec); } + /* + * (non-Javadoc) + * @see com.lambdaworks.redis.RedisClient#connectPubSub(com.lambdaworks.redis.codec.RedisCodec) + */ @Override public StatefulRedisPubSubConnection connectPubSub(RedisCodec codec) { return super.connectPubSub(codec); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePool.java b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePool.java index eb2ef0085..79674327c 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePool.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePool.java @@ -103,6 +103,10 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { return sentinelConfiguration != null; } + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ @SuppressWarnings({ "rawtypes" }) public void afterPropertiesSet() { @@ -136,6 +140,11 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { return RedisURI.Builder.redis(hostName, port).withTimeout(timeout, TimeUnit.MILLISECONDS).build(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.Pool#getResource() + */ + @Override @SuppressWarnings("unchecked") public StatefulConnection getResource() { try { @@ -145,7 +154,13 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.Pool#returnBrokenResource(java.lang.Object) + */ + @Override public void returnBrokenResource(final StatefulConnection resource) { + try { internalPool.invalidateObject(resource); } catch (Exception e) { @@ -153,7 +168,13 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.Pool#returnResource(java.lang.Object) + */ + @Override public void returnResource(final StatefulConnection resource) { + try { internalPool.returnObject(resource); } catch (Exception e) { @@ -161,7 +182,13 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.Pool#destroy() + */ + @Override public void destroy() { + try { client.shutdown(); internalPool.close(); @@ -316,6 +343,10 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { this.dbIndex = dbIndex; } + /* + * (non-Javadoc) + * @see org.apache.commons.pool2.BasePooledObjectFactory#activateObject(org.apache.commons.pool2.PooledObject) + */ @Override public void activateObject(PooledObject> pooledObject) throws Exception { @@ -324,6 +355,11 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { } } + /* + * (non-Javadoc) + * @see org.apache.commons.pool2.BasePooledObjectFactory#destroyObject(org.apache.commons.pool2.PooledObject) + */ + @Override public void destroyObject(final PooledObject> obj) throws Exception { try { obj.getObject().close(); @@ -332,6 +368,11 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { } } + /* + * (non-Javadoc) + * @see org.apache.commons.pool2.BasePooledObjectFactory#validateObject(org.apache.commons.pool2.PooledObject) + */ + @Override public boolean validateObject(final PooledObject> obj) { try { if (obj.getObject() instanceof StatefulRedisConnection) { @@ -343,11 +384,19 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { } } + /* + * (non-Javadoc) + * @see org.apache.commons.pool2.BasePooledObjectFactory#create() + */ @Override public StatefulConnection create() throws Exception { return client.connect(LettuceConnection.CODEC); } + /* + * (non-Javadoc) + * @see org.apache.commons.pool2.BasePooledObjectFactory#wrap(java.lang.Object) + */ @Override public PooledObject> wrap(StatefulConnection obj) { return new DefaultPooledObject>(obj); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java index 107aed9ce..2c4664fce 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java @@ -298,7 +298,7 @@ public class LettuceClusterConnection extends LettuceConnection Assert.noNullElements(keys, "Keys must not be null or contain null key!"); - // Routing for mget is handled by lettuce itself. + // Routing for mget is handled by lettuce. return super.del(keys); } @@ -876,7 +876,7 @@ public class LettuceClusterConnection extends LettuceConnection Assert.notNull(keys, "Keys must not be null!"); - // Routing for mget is handled by lettuce itself. + // Routing for mget is handled by lettuce. return super.mGet(keys); } @@ -889,7 +889,7 @@ public class LettuceClusterConnection extends LettuceConnection Assert.notNull(tuples, "Tuples must not be null!"); - // Routing for msetnx is handled by lettuce itself. + // Routing for mset is handled by lettuce. super.mSet(tuples); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java index 453a50844..d02fb69ce 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java @@ -459,6 +459,7 @@ public class LettuceConnection extends AbstractRedisConnection { } public List closePipeline() { + if (isPipelined) { isPipelined = false; List> futures = new ArrayList>(); @@ -466,9 +467,6 @@ public class LettuceConnection extends AbstractRedisConnection { futures.add(result.getResultHolder()); } - // boolean done = LettuceFutures.awaitAll(timeout, TimeUnit.MILLISECONDS, - // futures.toArray(new Command[futures.size()])); - try { boolean done = LettuceFutures.awaitAll(timeout, TimeUnit.MILLISECONDS, futures.toArray(new RedisFuture[futures.size()])); @@ -479,7 +477,9 @@ public class LettuceConnection extends AbstractRedisConnection { if (done) { for (LettuceResult result : ppline) { + if (result.getResultHolder().getOutput().hasError()) { + Exception err = new InvalidDataAccessApiUsageException(result.getResultHolder().getOutput().getError()); // remember only the first error if (problem == null) { @@ -487,6 +487,7 @@ public class LettuceConnection extends AbstractRedisConnection { } results.add(err); } else if (!convertPipelineAndTxResults || !(result.isStatus())) { + try { results.add(result.get()); } catch (DataAccessException e) { @@ -3970,7 +3971,8 @@ public class LettuceConnection extends AbstractRedisConnection { return ((StatefulRedisClusterConnection) asyncDedicatedConn).async(); } - throw new IllegalStateException(String.format("%s is not a supported connection type.", asyncDedicatedConn.getClass().getName())); + throw new IllegalStateException( + String.format("%s is not a supported connection type.", asyncDedicatedConn.getClass().getName())); } protected StatefulConnection doGetAsyncDedicatedConnection() { @@ -4004,7 +4006,8 @@ public class LettuceConnection extends AbstractRedisConnection { return ((StatefulRedisClusterConnection) asyncDedicatedConn).sync(); } - throw new IllegalStateException(String.format("%s is not a supported connection type.", asyncDedicatedConn.getClass().getName())); + throw new IllegalStateException( + String.format("%s is not a supported connection type.", asyncDedicatedConn.getClass().getName())); } private Future asyncBitOp(BitOperation op, byte[] destination, byte[]... keys) { diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePool.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePool.java index e46ee6f17..c498e9579 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePool.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePool.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,19 +18,21 @@ package org.springframework.data.redis.connection.lettuce; import org.springframework.data.redis.connection.Pool; -import com.lambdaworks.redis.RedisClient; +import com.lambdaworks.redis.AbstractRedisClient; import com.lambdaworks.redis.api.StatefulConnection; /** * Pool of Lettuce {@link StatefulConnection}s * * @author Jennifer Hickey + * @author Christoph Strobl + * @author Mark Paluch */ public interface LettucePool extends Pool> { /** - * @return The {@link RedisClient} used to create pooled connections + * @return The {@link AbstractRedisClient} used to create pooled connections */ - RedisClient getClient(); + AbstractRedisClient getClient(); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java index 6295940c3..0d3252ce1 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java @@ -30,6 +30,7 @@ import com.lambdaworks.redis.RedisClient; import com.lambdaworks.redis.RedisURI.Builder; import com.lambdaworks.redis.resource.ClientResources; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; +import com.lambdaworks.redis.sentinel.api.sync.RedisSentinelCommands; /** * @author Christoph Strobl @@ -116,7 +117,7 @@ public class LettuceSentinelConnection implements RedisSentinelConnection { Assert.notNull(master, "Redis node master must not be 'null' for failover."); Assert.hasText(master.getName(), "Redis master name must not be 'null' or empty for failover."); - connection.sync().failover(master.getName()); + getSentinelCommands().failover(master.getName()); } /* @@ -126,7 +127,7 @@ public class LettuceSentinelConnection implements RedisSentinelConnection { @Override public List masters() { try { - return LettuceConverters.toListOfRedisServer(connection.sync().masters()); + return LettuceConverters.toListOfRedisServer(getSentinelCommands().masters()); } catch (Exception e) { throw EXCEPTION_TRANSLATION.translate(e); } @@ -152,7 +153,7 @@ public class LettuceSentinelConnection implements RedisSentinelConnection { Assert.hasText(masterName, "Name of redis master cannot be 'null' or empty when loading slaves."); try { - return LettuceConverters.toListOfRedisServer(connection.sync().slaves(masterName)); + return LettuceConverters.toListOfRedisServer(getSentinelCommands().slaves(masterName)); } catch (Exception e) { throw EXCEPTION_TRANSLATION.translate(e); } @@ -176,7 +177,7 @@ public class LettuceSentinelConnection implements RedisSentinelConnection { public void remove(String masterName) { Assert.hasText(masterName, "Name of redis master cannot be 'null' or empty when trying to remove."); - connection.sync().remove(masterName); + getSentinelCommands().remove(masterName); } /* @@ -191,7 +192,7 @@ public class LettuceSentinelConnection implements RedisSentinelConnection { Assert.hasText(server.getHost(), "Host must not be 'null' for server to monitor."); Assert.notNull(server.getPort(), "Port must not be 'null' for server to monitor."); Assert.notNull(server.getQuorum(), "Quorum must not be 'null' for server to monitor."); - connection.sync().monitor(server.getName(), server.getHost(), server.getPort().intValue(), + getSentinelCommands().monitor(server.getName(), server.getHost(), server.getPort().intValue(), server.getQuorum().intValue()); } @@ -215,6 +216,10 @@ public class LettuceSentinelConnection implements RedisSentinelConnection { } } + private RedisSentinelCommands getSentinelCommands() { + return connection.sync(); + } + private StatefulRedisSentinelConnection connectSentinel() { return redisClient.connectSentinel(); } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClientTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClientTests.java index 349b9a11c..c38700f8e 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClientTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClientTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,22 +15,23 @@ */ package org.springframework.data.redis.connection.lettuce; +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + import com.lambdaworks.redis.RedisAsyncConnection; import com.lambdaworks.redis.RedisClient; import com.lambdaworks.redis.RedisException; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - /** * Integration test of {@link AuthenticatingRedisClient}. Enable requirepass and comment out the @Ignore to run. * * @author Jennifer Hickey * @author Thomas Darimont + * @author Christoph Strobl */ @Ignore("Redis must have requirepass set to run this test") public class AuthenticatingRedisClientTests { diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java index 05a43cca8..e1510cd42 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java @@ -119,7 +119,7 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests { public void setUp() { client = RedisClusterClient.create(LettuceTestClientResources.getSharedClientResources(), - Builder.redis(CLUSTER_HOST, MASTER_NODE_1_PORT).withTimeout(100, TimeUnit.MILLISECONDS).build()); + Builder.redis(CLUSTER_HOST, MASTER_NODE_1_PORT).withTimeout(500, TimeUnit.MILLISECONDS).build()); nativeConnection = client.connect().sync(); clusterConnection = new LettuceClusterConnection(client); } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionUnitTests.java index 6be8da2d7..5907462de 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 the original author or authors. + * Copyright 2015-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionUnitTestSuite.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionUnitTestSuite.java index 14213372b..e8759340b 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionUnitTestSuite.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionUnitTestSuite.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2015 the original author or authors. + * Copyright 2014-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSubscriptionTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSubscriptionTests.java index d2856df84..043ce4f87 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSubscriptionTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSubscriptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 the original author or authors. + * Copyright 2011-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ import com.lambdaworks.redis.pubsub.api.sync.RedisPubSubCommands; * Unit test of {@link LettuceSubscription} * * @author Jennifer Hickey + * @author Christoph Strobl */ public class LettuceSubscriptionTests {