diff --git a/docs/src/reference/docbook/appendix/appendix-command-reference.xml b/docs/src/reference/docbook/appendix/appendix-command-reference.xml index 1e793f6823..4b52a67b7d 100644 --- a/docs/src/reference/docbook/appendix/appendix-command-reference.xml +++ b/docs/src/reference/docbook/appendix/appendix-command-reference.xml @@ -138,7 +138,7 @@ SINTERX SINTERSTOREX SISMEMBERX - SLAVEOF- + SLAVEOFX SLOWLOG- SMEMBERSX SMOVEX diff --git a/gradle.properties b/gradle.properties index f09fb8eb53..27bc1d40a7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ jredisVersion=06052013 jedisVersion=2.4.1 springVersion=3.2.8.RELEASE log4jVersion=1.2.17 -version=1.3.0.BUILD-SNAPSHOT +version=1.3.0.DATAREDIS-277-SNAPSHOT srpVersion=0.7 jacksonVersion=1.8.8 fasterXmlJacksonVersion=2.2.0 diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java index 1cb5928530..0e3c471bf4 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java @@ -2197,6 +2197,24 @@ public List getClientList() { return this.delegate.getClientList(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#slaveOf(java.lang.String, int) + */ + @Override + public void slaveOf(String host, int port) { + this.delegate.slaveOf(host, port); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#slaveOfNoOne() + */ + @Override + public void slaveOfNoOne() { + this.delegate.slaveOfNoOne(); + } + /** * Specifies if pipelined and tx results should be deserialized to Strings. If false, results of * {@link #closePipeline()} and {@link #exec()} will be of the type returned by the underlying connection diff --git a/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java index 999d273724..2416bc49b7 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java @@ -165,7 +165,7 @@ public enum ShutdownOption { Long time(); /** - * Closes a given client connection identified by {@literal ip:port}. + * <<<<<<< HEAD Closes a given client connection identified by {@literal ip:port}. * * @param host of connection to close. * @param port of connection to close @@ -197,4 +197,22 @@ public enum ShutdownOption { * @see http://redis.io/commands/client-list */ List getClientList(); + + /** + * Change redis replication setting to new master. + * + * @param host + * @param port + * @since 1.3 + * @see http://redis.io/commands/slaveof + */ + void slaveOf(String host, int port); + + /** + * Change server into master. + * + * @since 1.3 + * @see http://redis.io/commands/slaveof + */ + void slaveOfNoOne(); } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java index 116db8e134..a69f0daeb2 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java @@ -2051,8 +2051,7 @@ public Double zIncrBy(byte[] key, double increment, byte[] value) { public Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { try { - ZParams zparams = new ZParams().weights(weights).aggregate( - redis.clients.jedis.ZParams.Aggregate.valueOf(aggregate.name())); + ZParams zparams = new ZParams().weights(weights).aggregate(ZParams.Aggregate.valueOf(aggregate.name())); if (isPipelined()) { pipeline(new JedisResult(pipeline.zinterstore(destKey, zparams, sets))); @@ -2382,8 +2381,7 @@ public Double zScore(byte[] key, byte[] value) { public Long zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { try { - ZParams zparams = new ZParams().weights(weights).aggregate( - redis.clients.jedis.ZParams.Aggregate.valueOf(aggregate.name())); + ZParams zparams = new ZParams().weights(weights).aggregate(ZParams.Aggregate.valueOf(aggregate.name())); if (isPipelined()) { pipeline(new JedisResult(pipeline.zunionstore(destKey, zparams, sets))); @@ -2830,6 +2828,23 @@ public void killClient(String host, int port) { } } + /* + * @see org.springframework.data.redis.connection.RedisServerCommands#slaveOf(java.lang.String, int) + */ + @Override + public void slaveOf(String host, int port) { + + Assert.hasText(host, "Host must not be null for 'SLAVEOF' command."); + if (isQueueing() || isPipelined()) { + throw new UnsupportedOperationException("'SLAVEOF' cannot be called in pipline / transaction mode."); + } + try { + this.jedis.slaveof(host, port); + } catch (Exception e) { + throw convertJedisAccessException(e); + } + } + /* * @see org.springframework.data.redis.connection.RedisServerCommands#setClientName(java.lang.String) */ @@ -2868,6 +2883,23 @@ public List getClientList() { return JedisConverters.toListOfRedisClientInformation(this.jedis.clientList()); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#slaveOfNoOne() + */ + @Override + public void slaveOfNoOne() { + + if (isQueueing() || isPipelined()) { + throw new UnsupportedOperationException("'SLAVEOF' cannot be called in pipline / transaction mode."); + } + try { + this.jedis.slaveofNoOne(); + } catch (Exception e) { + throw convertJedisAccessException(e); + } + } + /** * Specifies if pipelined results should be converted to the expected data type. If false, results of * {@link #closePipeline()} and {@link #exec()} will be of the type returned by the Jedis driver diff --git a/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java b/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java index 8bc46345ad..194a07e0a6 100644 --- a/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java @@ -1197,6 +1197,20 @@ public void setClientName(byte[] name) { throw new UnsupportedOperationException("'CLIENT SETNAME' is not supported by the JRedis driver."); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#slaveOf(java.lang.String, int) + */ + @Override + public void slaveOf(String host, int port) { + + try { + this.jredis.slaveof(host, port); + } catch (Exception e) { + throw convertJredisAccessException(e); + } + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisServerCommands#getClientName() @@ -1209,4 +1223,17 @@ public String getClientName() { public List getClientList() { throw new UnsupportedOperationException(); } + + /* + * @see org.springframework.data.redis.connection.RedisServerCommands#slaveOfNoOne() + */ + @Override + public void slaveOfNoOne() { + + try { + this.jredis.slaveofnone(); + } catch (Exception e) { + throw convertJredisAccessException(e); + } + } } 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 6815aeeeee..046b5cff28 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 @@ -2939,6 +2939,29 @@ public void setClientName(byte[] name) { getAsyncConnection().clientSetname(name); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#slaveOf(java.lang.String, int) + */ + @Override + public void slaveOf(String host, int port) { + + Assert.hasText(host, "Host must not be null for 'SLAVEOF' command."); + try { + if (isPipelined()) { + pipeline(new LettuceStatusResult(getAsyncConnection().slaveof(host, port))); + return; + } + if (isQueueing()) { + transaction(new LettuceTxResult(getConnection().slaveof(host, port))); + return; + } + getConnection().slaveof(host, port); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisServerCommands#getClientName() @@ -2978,6 +3001,27 @@ public List getClientList() { return LettuceConverters.toListOfRedisClientInformation(getConnection().clientList()); } + /* + * @see org.springframework.data.redis.connection.RedisServerCommands#slaveOfNoOne() + */ + @Override + public void slaveOfNoOne() { + + try { + if (isPipelined()) { + pipeline(new LettuceStatusResult(getAsyncConnection().slaveofNoOne())); + return; + } + if (isQueueing()) { + transaction(new LettuceTxResult(getConnection().slaveofNoOne())); + return; + } + getConnection().slaveofNoOne(); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + /** * Specifies if pipelined and transaction results should be converted to the expected data type. If false, results of * {@link #closePipeline()} and {@link #exec()} will be of the type returned by the Lettuce driver diff --git a/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java b/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java index 9a93da1f7d..be9aa3af51 100644 --- a/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java @@ -2262,6 +2262,25 @@ public void setClientName(byte[] name) { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#slaveOf(java.lang.String, int) + */ + @Override + public void slaveOf(String host, int port) { + + Assert.hasText(host, "Host must not be null for 'SLAVEOF' command."); + try { + if (isPipelined()) { + pipeline(new SrpStatusResult(pipeline.slaveof(host, port))); + return; + } + client.slaveof(host, port); + } catch (Exception e) { + throw convertSrpAccessException(e); + } + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisServerCommands#getClientName() @@ -2295,6 +2314,23 @@ public List getClientList() { return SrpConverters.toListOfRedisClientInformation(this.client.client_list()); } + /* + * @see org.springframework.data.redis.connection.RedisServerCommands#slaveOfNoOne() + */ + @Override + public void slaveOfNoOne() { + + try { + if (isPipelined()) { + pipeline(new SrpStatusResult(pipeline.slaveof("NO", "ONE"))); + return; + } + client.slaveof("NO", "ONE"); + } catch (Exception e) { + throw convertSrpAccessException(e); + } + } + private List closeTransaction() { List results = Collections.emptyList(); if (txTracker != null) { diff --git a/src/main/java/org/springframework/data/redis/core/RedisOperations.java b/src/main/java/org/springframework/data/redis/core/RedisOperations.java index edb3ac3577..ab49a65640 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisOperations.java +++ b/src/main/java/org/springframework/data/redis/core/RedisOperations.java @@ -303,4 +303,20 @@ T execute(RedisScript script, RedisSerializer argsSerializer, RedisSer * @since 1.3 */ void killClient(String host, int port); + + /** + * Change redis replication setting to new master. + * + * @param host + * @param port + * @since 1.3 + */ + void slaveOf(String host, int port); + + /** + * Change server into master. + * + * @since 1.3 + */ + void slaveOfNoOne(); } diff --git a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java index 374354c643..b96c14a95a 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java +++ b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java @@ -1019,4 +1019,38 @@ public List doInRedis(RedisConnection connection) throws DataAc } }); } + + /* + * @see org.springframework.data.redis.core.RedisOperations#slaveOf(java.lang.String, int) + */ + @Override + public void slaveOf(final String host, final int port) { + + execute(new RedisCallback() { + @Override + public Void doInRedis(RedisConnection connection) throws DataAccessException { + + connection.slaveOf(host, port); + return null; + } + + }); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.RedisOperations#slaveOfNoOne() + */ + @Override + public void slaveOfNoOne() { + + execute(new RedisCallback() { + + @Override + public Void doInRedis(RedisConnection connection) throws DataAccessException { + connection.slaveOfNoOne(); + return null; + } + }); + } } diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionUnitTestSuite.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionUnitTestSuite.java index 1effabe571..2648a6a91c 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionUnitTestSuite.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionUnitTestSuite.java @@ -115,6 +115,8 @@ public void pExpireHavingIntOverflowShouldUseRedisServerTimeAsReferenceForPExpir } /** + * <<<<<<< HEAD + * * @see DATAREDIS-267 */ @Test @@ -134,6 +136,33 @@ public void getClientNameShouldSendRequestCorrectly() { verifyNativeConnectionInvocation().clientGetname(); } + /** + * @see DATAREDIS-277 + */ + @Test(expected = IllegalArgumentException.class) + public void slaveOfShouldThrowExectpionWhenCalledForNullHost() { + connection.slaveOf(null, 0); + } + + /** + * @see DATAREDIS-277 + */ + @Test + public void slaveOfShouldBeSentCorrectly() { + + connection.slaveOf("127.0.0.1", 1001); + verifyNativeConnectionInvocation().slaveof(eq("127.0.0.1"), eq(1001)); + } + + /** + * @see DATAREDIS-277 + */ + @Test + public void slaveOfNoOneShouldBeSentCorrectly() { + + connection.slaveOfNoOne(); + verifyNativeConnectionInvocation().slaveofNoOne(); + } } public static class JedisConnectionPipelineUnitTests extends JedisConnectionUnitTests { @@ -179,6 +208,23 @@ public void getClientNameShouldSendRequestCorrectly() { super.getClientNameShouldSendRequestCorrectly(); } + /** + * @see DATAREDIS-277 + */ + @Override + @Test(expected = UnsupportedOperationException.class) + public void slaveOfShouldBeSentCorrectly() { + super.slaveOfShouldBeSentCorrectly(); + } + + /** + * @see DATAREDIS-277 + */ + @Test(expected = UnsupportedOperationException.class) + public void slaveOfNoOneShouldBeSentCorrectly() { + super.slaveOfNoOneShouldBeSentCorrectly(); + } + } /** 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 a22a2b346e..ec0f1f9349 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 @@ -83,6 +83,8 @@ public void shutdownWithSaveOptionIsCalledCorrectly() { } /** + * <<<<<<< HEAD + * * @see DATAREDIS-267 */ @Test @@ -103,6 +105,33 @@ public void getClientNameShouldSendRequestCorrectly() { verifyNativeConnectionInvocation().clientGetname(); } + /** + * @see DATAREDIS-277 + */ + @Test(expected = IllegalArgumentException.class) + public void slaveOfShouldThrowExectpionWhenCalledForNullHost() { + connection.slaveOf(null, 0); + } + + /** + * @see DATAREDIS-277 + */ + @Test + public void slaveOfShouldBeSentCorrectly() { + + connection.slaveOf("127.0.0.1", 1001); + verifyNativeConnectionInvocation().slaveof(eq("127.0.0.1"), eq(1001)); + } + + /** + * @see DATAREDIS-277 + */ + @Test + public void slaveOfNoOneShouldBeSentCorrectly() { + + connection.slaveOfNoOne(); + verifyNativeConnectionInvocation().slaveofNoOne(); + } } public static class LettucePipelineConnectionUnitTests extends LettuceConnectionUnitTests { diff --git a/src/test/java/org/springframework/data/redis/connection/srp/SrpConnectionUnitTestSuite.java b/src/test/java/org/springframework/data/redis/connection/srp/SrpConnectionUnitTestSuite.java index 72542b657e..cca6a600c0 100644 --- a/src/test/java/org/springframework/data/redis/connection/srp/SrpConnectionUnitTestSuite.java +++ b/src/test/java/org/springframework/data/redis/connection/srp/SrpConnectionUnitTestSuite.java @@ -79,6 +79,8 @@ public void shutdownWithNosaveIsCalledCorrectly() { } /** + * <<<<<<< HEAD + * * @see DATAREDIS-267 */ @Test @@ -99,6 +101,33 @@ public void getClientNameShouldSendRequestCorrectly() { verifyNativeConnectionInvocation().client_getname(); } + /** + * @see DATAREDIS-277 + */ + @Test(expected = IllegalArgumentException.class) + public void slaveOfShouldThrowExectpionWhenCalledForNullHost() { + connection.slaveOf(null, 0); + } + + /** + * @see DATAREDIS-277 + */ + @Test + public void slaveOfShouldBeSentCorrectly() { + + connection.slaveOf("127.0.0.1", 1001); + verifyNativeConnectionInvocation().slaveof(eq("127.0.0.1"), eq(1001)); + } + + /** + * @see DATAREDIS-277 + */ + @Test + public void slaveOfNoOneShouldBeSentCorrectly() { + + connection.slaveOfNoOne(); + verifyNativeConnectionInvocation().slaveof(eq("NO"), eq("ONE")); + } } public static class SrpConnectionPiplineUnitTests extends AbstractConnectionUnitTestBase { diff --git a/src/test/java/org/springframework/data/redis/core/RedisTemplateUnitTests.java b/src/test/java/org/springframework/data/redis/core/RedisTemplateUnitTests.java new file mode 100644 index 0000000000..9102f6ef42 --- /dev/null +++ b/src/test/java/org/springframework/data/redis/core/RedisTemplateUnitTests.java @@ -0,0 +1,69 @@ +/* + * Copyright 2014 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.redis.core; + +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.*; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.data.redis.connection.RedisConnectionFactory; + +/** + * @author Christoph Strobl + */ +@RunWith(MockitoJUnitRunner.class) +public class RedisTemplateUnitTests { + + private RedisTemplate template; + private @Mock RedisConnectionFactory connectionFactoryMock; + private @Mock RedisConnection redisConnectionMock; + + @Before + public void setUp() { + + template = new RedisTemplate(); + template.setConnectionFactory(connectionFactoryMock); + when(connectionFactoryMock.getConnection()).thenReturn(redisConnectionMock); + + template.afterPropertiesSet(); + } + + /** + * @see DATAREDIS-277 + */ + @Test + public void slaveOfIsDelegatedToConnectionCorrectly() { + + template.slaveOf("127.0.0.1", 1001); + verify(redisConnectionMock, times(1)).slaveOf(eq("127.0.0.1"), eq(1001)); + } + + /** + * @see DATAREDIS-277 + */ + @Test + public void slaveOfNoOneIsDelegatedToConnectionCorrectly() { + + template.slaveOfNoOne(); + verify(redisConnectionMock, times(1)).slaveOfNoOne(); + } + +}