diff --git a/docs/src/reference/docbook/appendix/appendix-command-reference.xml b/docs/src/reference/docbook/appendix/appendix-command-reference.xml index 1e793f682..4b52a67b7 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/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java index 1cb592853..0e3c471bf 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 class DefaultStringRedisConnection implements StringRedisConnection { 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 999d27372..2416bc49b 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 interface RedisServerCommands { 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 interface RedisServerCommands { * @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 116db8e13..a69f0daeb 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 class JedisConnection implements RedisConnection { 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 class JedisConnection implements RedisConnection { 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 class JedisConnection implements RedisConnection { } } + /* + * @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 class JedisConnection implements RedisConnection { 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 8bc46345a..194a07e0a 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 class JredisConnection implements RedisConnection { 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 class JredisConnection implements RedisConnection { 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 6815aeeee..046b5cff2 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 class LettuceConnection implements RedisConnection { 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 class LettuceConnection implements RedisConnection { 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 9a93da1f7..be9aa3af5 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 class SrpConnection implements RedisConnection { } } + /* + * (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 class SrpConnection implements RedisConnection { 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 edb3ac357..ab49a6564 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 @@ public interface RedisOperations { * @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 374354c64..b96c14a95 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 class RedisTemplate extends RedisAccessor implements RedisOperation } }); } + + /* + * @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 1effabe57..2648a6a91 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 class JedisConnectionUnitTestSuite { } /** + * <<<<<<< HEAD + * * @see DATAREDIS-267 */ @Test @@ -134,6 +136,33 @@ public class JedisConnectionUnitTestSuite { 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 class JedisConnectionUnitTestSuite { 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 a22a2b346..ec0f1f934 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 class LettuceConnectionUnitTestSuite { } /** + * <<<<<<< HEAD + * * @see DATAREDIS-267 */ @Test @@ -103,6 +105,33 @@ public class LettuceConnectionUnitTestSuite { 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 72542b657..cca6a600c 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 class SrpConnectionUnitTestSuite { } /** + * <<<<<<< HEAD + * * @see DATAREDIS-267 */ @Test @@ -99,6 +101,33 @@ public class SrpConnectionUnitTestSuite { 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 000000000..9102f6ef4 --- /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(); + } + +}