Skip to content

Commit 0869383

Browse files
DATAREDIS-277 - Add support for 'SLAVEOF'.
'SLAVEOF' and 'SLAVEOF NO ONE' are available via 'RedisConnection' and 'RedisOperations' for 'jedis', 'jredis', 'lettuce' and 'srp'. Original Pull Request: #57
1 parent 674660c commit 0869383

File tree

13 files changed

+408
-3
lines changed

13 files changed

+408
-3
lines changed

docs/src/reference/docbook/appendix/appendix-command-reference.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@
138138
<row><entry><code>SINTER</code></entry><entry>X</entry></row>
139139
<row><entry><code>SINTERSTORE</code></entry><entry>X</entry></row>
140140
<row><entry><code>SISMEMBER</code></entry><entry>X</entry></row>
141-
<row><entry><code>SLAVEOF</code></entry><entry>-</entry></row>
141+
<row><entry><code>SLAVEOF</code></entry><entry>X</entry></row>
142142
<row><entry><code>SLOWLOG</code></entry><entry>-</entry></row>
143143
<row><entry><code>SMEMBERS</code></entry><entry>X</entry></row>
144144
<row><entry><code>SMOVE</code></entry><entry>X</entry></row>

src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2191,6 +2191,24 @@ public Long time() {
21912191
return this.delegate.time();
21922192
}
21932193

2194+
/*
2195+
* (non-Javadoc)
2196+
* @see org.springframework.data.redis.connection.RedisServerCommands#slaveOf(java.lang.String, int)
2197+
*/
2198+
@Override
2199+
public void slaveOf(String host, int port) {
2200+
this.delegate.slaveOf(host, port);
2201+
}
2202+
2203+
/*
2204+
* (non-Javadoc)
2205+
* @see org.springframework.data.redis.connection.RedisServerCommands#slaveOfNoOne()
2206+
*/
2207+
@Override
2208+
public void slaveOfNoOne() {
2209+
this.delegate.slaveOfNoOne();
2210+
}
2211+
21942212
/**
21952213
* Specifies if pipelined and tx results should be deserialized to Strings. If false, results of
21962214
* {@link #closePipeline()} and {@link #exec()} will be of the type returned by the underlying connection

src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,4 +161,22 @@ public enum ShutdownOption {
161161
* @since 1.1
162162
*/
163163
Long time();
164+
165+
/**
166+
* Change redis replication setting to new master.
167+
*
168+
* @param host
169+
* @param port
170+
* @since 1.3
171+
* @see http://redis.io/commands/slaveof
172+
*/
173+
void slaveOf(String host, int port);
174+
175+
/**
176+
* Change server into master.
177+
*
178+
* @since 1.3
179+
* @see http://redis.io/commands/slaveof
180+
*/
181+
void slaveOfNoOne();
164182
}

src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2808,6 +2808,41 @@ public Long time() {
28082808
return Converters.toTimeMillis(serverTimeInformation.get(0), serverTimeInformation.get(1));
28092809
}
28102810

2811+
/*
2812+
* (non-Javadoc)
2813+
* @see org.springframework.data.redis.connection.RedisServerCommands#slaveOf(java.lang.String, int)
2814+
*/
2815+
@Override
2816+
public void slaveOf(String host, int port) {
2817+
2818+
Assert.hasText(host, "Host must not be null for 'SLAVEOF' command.");
2819+
if (isQueueing() || isPipelined()) {
2820+
throw new UnsupportedOperationException("'SLAVEOF' cannot be called in pipline / transaction mode.");
2821+
}
2822+
try {
2823+
this.jedis.slaveof(host, port);
2824+
} catch (Exception e) {
2825+
throw convertJedisAccessException(e);
2826+
}
2827+
}
2828+
2829+
/*
2830+
* (non-Javadoc)
2831+
* @see org.springframework.data.redis.connection.RedisServerCommands#slaveOfNoOne()
2832+
*/
2833+
@Override
2834+
public void slaveOfNoOne() {
2835+
2836+
if (isQueueing() || isPipelined()) {
2837+
throw new UnsupportedOperationException("'SLAVEOF' cannot be called in pipline / transaction mode.");
2838+
}
2839+
try {
2840+
this.jedis.slaveofNoOne();
2841+
} catch (Exception e) {
2842+
throw convertJedisAccessException(e);
2843+
}
2844+
}
2845+
28112846
/**
28122847
* Specifies if pipelined results should be converted to the expected data type. If false, results of
28132848
* {@link #closePipeline()} and {@link #exec()} will be of the type returned by the Jedis driver

src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,4 +1185,32 @@ public <T> T evalSha(String scriptSha1, ReturnType returnType, int numKeys, byte
11851185
public Long time() {
11861186
throw new UnsupportedOperationException("The 'TIME' command is not supported by the JRedis driver.");
11871187
}
1188+
1189+
/*
1190+
* (non-Javadoc)
1191+
* @see org.springframework.data.redis.connection.RedisServerCommands#slaveOf(java.lang.String, int)
1192+
*/
1193+
@Override
1194+
public void slaveOf(String host, int port) {
1195+
1196+
try {
1197+
this.jredis.slaveof(host, port);
1198+
} catch (Exception e) {
1199+
throw convertJredisAccessException(e);
1200+
}
1201+
}
1202+
1203+
/*
1204+
* (non-Javadoc)
1205+
* @see org.springframework.data.redis.connection.RedisServerCommands#slaveOfNoOne()
1206+
*/
1207+
@Override
1208+
public void slaveOfNoOne() {
1209+
1210+
try {
1211+
this.jredis.slaveofnone();
1212+
} catch (Exception e) {
1213+
throw convertJredisAccessException(e);
1214+
}
1215+
}
11881216
}

src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2903,6 +2903,52 @@ public Long time() {
29032903
return Converters.toTimeMillis(new String(result.get(0)), new String(result.get(1)));
29042904
}
29052905

2906+
/*
2907+
* (non-Javadoc)
2908+
* @see org.springframework.data.redis.connection.RedisServerCommands#slaveOf(java.lang.String, int)
2909+
*/
2910+
@Override
2911+
public void slaveOf(String host, int port) {
2912+
2913+
Assert.hasText(host, "Host must not be null for 'SLAVEOF' command.");
2914+
try {
2915+
if (isPipelined()) {
2916+
pipeline(new LettuceStatusResult(getAsyncConnection().slaveof(host, port)));
2917+
return;
2918+
}
2919+
if (isQueueing()) {
2920+
transaction(new LettuceTxResult(getConnection().slaveof(host, port)));
2921+
return;
2922+
}
2923+
getConnection().slaveof(host, port);
2924+
} catch (Exception ex) {
2925+
throw convertLettuceAccessException(ex);
2926+
}
2927+
}
2928+
2929+
/*
2930+
* (non-Javadoc)
2931+
* @see org.springframework.data.redis.connection.RedisServerCommands#slaveOfNoOne()
2932+
*/
2933+
@Override
2934+
public void slaveOfNoOne() {
2935+
2936+
try {
2937+
if (isPipelined()) {
2938+
pipeline(new LettuceStatusResult(getAsyncConnection().slaveofNoOne()));
2939+
return;
2940+
}
2941+
if (isQueueing()) {
2942+
transaction(new LettuceTxResult(getConnection().slaveofNoOne()));
2943+
return;
2944+
}
2945+
getConnection().slaveofNoOne();
2946+
} catch (Exception ex) {
2947+
throw convertLettuceAccessException(ex);
2948+
}
2949+
2950+
}
2951+
29062952
/**
29072953
* Specifies if pipelined and transaction results should be converted to the expected data type. If false, results of
29082954
* {@link #closePipeline()} and {@link #exec()} will be of the type returned by the Lettuce driver

src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2222,6 +2222,43 @@ public Long time() {
22222222
return SrpConverters.toTimeAsLong(reply.data());
22232223
}
22242224

2225+
/*
2226+
* (non-Javadoc)
2227+
* @see org.springframework.data.redis.connection.RedisServerCommands#slaveOf(java.lang.String, int)
2228+
*/
2229+
@Override
2230+
public void slaveOf(String host, int port) {
2231+
2232+
Assert.hasText(host, "Host must not be null for 'SLAVEOF' command.");
2233+
try {
2234+
if (isPipelined()) {
2235+
pipeline(new SrpStatusResult(pipeline.slaveof(host, port)));
2236+
return;
2237+
}
2238+
client.slaveof(host, port);
2239+
} catch (Exception e) {
2240+
throw convertSrpAccessException(e);
2241+
}
2242+
}
2243+
2244+
/*
2245+
* (non-Javadoc)
2246+
* @see org.springframework.data.redis.connection.RedisServerCommands#slaveOfNoOne()
2247+
*/
2248+
@Override
2249+
public void slaveOfNoOne() {
2250+
2251+
try {
2252+
if (isPipelined()) {
2253+
pipeline(new SrpStatusResult(pipeline.slaveof("NO", "ONE")));
2254+
return;
2255+
}
2256+
client.slaveof("NO", "ONE");
2257+
} catch (Exception e) {
2258+
throw convertSrpAccessException(e);
2259+
}
2260+
}
2261+
22252262
private List<Object> closeTransaction() {
22262263
List<Object> results = Collections.emptyList();
22272264
if (txTracker != null) {

src/main/java/org/springframework/data/redis/core/RedisOperations.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2011-2013 the original author or authors.
2+
* Copyright 2011-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
3131
* useful option for extensibility and testability (as it can be easily mocked or stubbed).
3232
*
3333
* @author Costin Leau
34+
* @author Christoph Strobl
3435
*/
3536
public interface RedisOperations<K, V> {
3637

@@ -284,4 +285,20 @@ <T> T execute(RedisScript<T> script, RedisSerializer<?> argsSerializer, RedisSer
284285
RedisSerializer<?> getHashKeySerializer();
285286

286287
RedisSerializer<?> getHashValueSerializer();
288+
289+
/**
290+
* Change redis replication setting to new master.
291+
*
292+
* @param host
293+
* @param port
294+
* @since 1.3
295+
*/
296+
void slaveOf(String host, int port);
297+
298+
/**
299+
* Change server into master.
300+
*
301+
* @since 1.3
302+
*/
303+
void slaveOfNoOne();
287304
}

src/main/java/org/springframework/data/redis/core/RedisTemplate.java

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2011-2013 the original author or authors.
2+
* Copyright 2011-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -69,6 +69,7 @@
6969
* <b>This is the central class in Redis support</b>.
7070
*
7171
* @author Costin Leau
72+
* @author Christoph Strobl
7273
* @param <K> the Redis key type against which the template works (usually a String)
7374
* @param <V> the Redis value type against which the template works
7475
* @see StringRedisTemplate
@@ -989,4 +990,38 @@ public <HK, HV> BoundHashOperations<K, HK, HV> boundHashOps(K key) {
989990
public <HK, HV> HashOperations<K, HK, HV> opsForHash() {
990991
return new DefaultHashOperations<K, HK, HV>(this);
991992
}
993+
994+
/*
995+
* (non-Javadoc)
996+
* @see org.springframework.data.redis.core.RedisOperations#slaveOf(java.lang.String, int)
997+
*/
998+
@Override
999+
public void slaveOf(final String host, final int port) {
1000+
execute(new RedisCallback<Void>() {
1001+
1002+
@Override
1003+
public Void doInRedis(RedisConnection connection) throws DataAccessException {
1004+
connection.slaveOf(host, port);
1005+
return null;
1006+
}
1007+
1008+
});
1009+
}
1010+
1011+
/*
1012+
* (non-Javadoc)
1013+
* @see org.springframework.data.redis.core.RedisOperations#slaveOfNoOne()
1014+
*/
1015+
@Override
1016+
public void slaveOfNoOne() {
1017+
execute(new RedisCallback<Void>() {
1018+
1019+
@Override
1020+
public Void doInRedis(RedisConnection connection) throws DataAccessException {
1021+
connection.slaveOfNoOne();
1022+
return null;
1023+
}
1024+
});
1025+
1026+
}
9921027
}

src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionUnitTestSuite.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,34 @@ public void pExpireHavingIntOverflowShouldUseRedisServerTimeAsReferenceForPExpir
113113
connection.pExpire("foo".getBytes(), msec);
114114
verifyNativeConnectionInvocation().pexpireAt(any(byte[].class), eq(expected));
115115
}
116+
117+
/**
118+
* @see DATAREDIS-277
119+
*/
120+
@Test(expected = IllegalArgumentException.class)
121+
public void slaveOfShouldThrowExectpionWhenCalledForNullHost() {
122+
connection.slaveOf(null, 0);
123+
}
124+
125+
/**
126+
* @see DATAREDIS-277
127+
*/
128+
@Test
129+
public void slaveOfShouldBeSentCorrectly() {
130+
131+
connection.slaveOf("127.0.0.1", 1001);
132+
verifyNativeConnectionInvocation().slaveof(eq("127.0.0.1"), eq(1001));
133+
}
134+
135+
/**
136+
* @see DATAREDIS-277
137+
*/
138+
@Test
139+
public void slaveOfNoOneShouldBeSentCorrectly() {
140+
141+
connection.slaveOfNoOne();
142+
verifyNativeConnectionInvocation().slaveofNoOne();
143+
}
116144
}
117145

118146
public static class JedisConnectionPipelineUnitTests extends JedisConnectionUnitTests {
@@ -141,6 +169,23 @@ public void shutdownSaveShouldBeSentCorrectlyUsingLuaScript() {
141169
super.shutdownSaveShouldBeSentCorrectlyUsingLuaScript();
142170
}
143171

172+
/**
173+
* @see DATAREDIS-277
174+
*/
175+
@Override
176+
@Test(expected = UnsupportedOperationException.class)
177+
public void slaveOfShouldBeSentCorrectly() {
178+
super.slaveOfShouldBeSentCorrectly();
179+
}
180+
181+
/**
182+
* @see DATAREDIS-277
183+
*/
184+
@Test(expected = UnsupportedOperationException.class)
185+
public void slaveOfNoOneShouldBeSentCorrectly() {
186+
super.slaveOfNoOneShouldBeSentCorrectly();
187+
}
188+
144189
}
145190

146191
/**

0 commit comments

Comments
 (0)