Skip to content

Commit d116d38

Browse files
christophstroblThomas Darimont
authored and
Thomas Darimont
committed
DATAREDIS-184 - Add support for 'SAVE/NOSAVE' to shutdown.
Created and added 'ShutdownOptions' to 'RedisServerCommands'. The full implementation is available for 'lettuce' and 'srp'. When using 'jedis' the command is emulated using lua script via 'eval'. For 'jredis' the method is not available and will throw 'UnsupportedOperationException'. Original Pull Request: #47
1 parent 4b2ccbe commit d116d38

File tree

12 files changed

+602
-1
lines changed

12 files changed

+602
-1
lines changed

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,15 @@ public void shutdown() {
760760
delegate.shutdown();
761761
}
762762

763+
/*
764+
* (non-Javadoc)
765+
* @see org.springframework.data.redis.connection.RedisServerCommands#shutdown(org.springframework.data.redis.connection.RedisServerCommands.ShutdownOption)
766+
*/
767+
@Override
768+
public void shutdown(ShutdownOption option) {
769+
delegate.shutdown(option);
770+
}
771+
763772
public Set<byte[]> sInter(byte[]... keys) {
764773
Set<byte[]> results = delegate.sInter(keys);
765774
if (isFutureConversion()) {

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
*/
2828
public interface RedisServerCommands {
2929

30+
public enum ShutdownOption {
31+
SAVE, NOSAVE;
32+
}
33+
3034
/**
3135
* Start an {@literal Append Only File} rewrite process on server.
3236
*
@@ -116,6 +120,14 @@ public interface RedisServerCommands {
116120
*/
117121
void shutdown();
118122

123+
/**
124+
* Shutdown server.
125+
*
126+
* @see http://redis.io/commands/shutdown
127+
* @since 1.3
128+
*/
129+
void shutdown(ShutdownOption option);
130+
119131
/**
120132
* Load configuration parameters for given {@code pattern} from server.
121133
*

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ public class JedisConnection implements RedisConnection {
7676
private static final Method SEND_COMMAND;
7777
private static final Method GET_RESPONSE;
7878

79+
private static final String SHUTDOWN_SCRIPT = "return redis.call('SHUTDOWN','%s')";
80+
7981
static {
8082
CLIENT_FIELD = ReflectionUtils.findField(BinaryJedis.class, "client", Client.class);
8183
ReflectionUtils.makeAccessible(CLIENT_FIELD);
@@ -624,6 +626,21 @@ public void shutdown() {
624626
}
625627
}
626628

629+
/*
630+
* (non-Javadoc)
631+
* @see org.springframework.data.redis.connection.RedisServerCommands#shutdown(org.springframework.data.redis.connection.RedisServerCommands.ShutdownOption)
632+
*/
633+
@Override
634+
public void shutdown(ShutdownOption option) {
635+
636+
if (option == null) {
637+
shutdown();
638+
return;
639+
}
640+
641+
eval(String.format(SHUTDOWN_SCRIPT, option.name()).getBytes(), ReturnType.STATUS, 0);
642+
}
643+
627644
public byte[] echo(byte[] message) {
628645
try {
629646
if (isPipelined()) {

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,15 @@ public void shutdown() {
291291
throw new UnsupportedOperationException();
292292
}
293293

294+
/*
295+
* (non-Javadoc)
296+
* @see org.springframework.data.redis.connection.RedisServerCommands#shutdown(org.springframework.data.redis.connection.RedisServerCommands.ShutdownOption)
297+
*/
298+
@Override
299+
public void shutdown(ShutdownOption option) {
300+
throw new UnsupportedOperationException();
301+
}
302+
294303
public Long del(byte[]... keys) {
295304
try {
296305
return jredis.del(keys);

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,30 @@ public void shutdown() {
662662
}
663663
}
664664

665+
/*
666+
* (non-Javadoc)
667+
* @see org.springframework.data.redis.connection.RedisServerCommands#shutdown(org.springframework.data.redis.connection.RedisServerCommands.ShutdownOption)
668+
*/
669+
@Override
670+
public void shutdown(ShutdownOption option) {
671+
672+
if (option == null) {
673+
shutdown();
674+
return;
675+
}
676+
677+
boolean save = ShutdownOption.SAVE.equals(option);
678+
try {
679+
if (isPipelined()) {
680+
getAsyncConnection().shutdown(save);
681+
return;
682+
}
683+
getConnection().shutdown(save);
684+
} catch (Exception ex) {
685+
throw convertLettuceAccessException(ex);
686+
}
687+
}
688+
665689
public byte[] echo(byte[] message) {
666690
try {
667691
if (isPipelined()) {

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

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.Properties;
2525
import java.util.Queue;
2626
import java.util.Set;
27+
import java.util.concurrent.ArrayBlockingQueue;
2728
import java.util.concurrent.BlockingQueue;
2829
import java.util.concurrent.Future;
2930

@@ -149,7 +150,7 @@ public List<Object> complete() {
149150

150151
public void addCommand(FutureResult result) {
151152
futureResults.add(result);
152-
if (!(result instanceof SrpTxResult)) {
153+
if (!(result instanceof SrpTxResult) && result.getResultHolder() != null) {
153154
Futures.addCallback(((SrpGenericResult) result).getResultHolder(), this);
154155
}
155156
}
@@ -208,6 +209,13 @@ public List<Object> get() {
208209
}
209210
}
210211

212+
SrpConnection(RedisClient client) {
213+
214+
Assert.notNull(client);
215+
this.client = client;
216+
this.queue = new ArrayBlockingQueue<SrpConnection>(50);
217+
}
218+
211219
public SrpConnection(String host, int port, BlockingQueue<SrpConnection> queue) {
212220
try {
213221
this.client = new RedisClient(host, port);
@@ -481,6 +489,31 @@ public void shutdown() {
481489
}
482490
}
483491

492+
/*
493+
* (non-Javadoc)
494+
* @see org.springframework.data.redis.connection.RedisServerCommands#shutdown(org.springframework.data.redis.connection.RedisServerCommands.ShutdownOption)
495+
*/
496+
@Override
497+
public void shutdown(ShutdownOption option) {
498+
499+
if (option == null) {
500+
shutdown();
501+
return;
502+
}
503+
504+
byte[] save = option.name().getBytes(Charsets.UTF_8);
505+
try {
506+
if (isPipelined()) {
507+
pipeline(new SrpStatusResult(pipeline.shutdown(save, null)));
508+
return;
509+
}
510+
client.shutdown(save, null);
511+
} catch (Exception ex) {
512+
throw convertSrpAccessException(ex);
513+
}
514+
515+
}
516+
484517
public byte[] echo(byte[] message) {
485518
try {
486519
if (isPipelined()) {
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright 2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.redis.connection;
17+
18+
import java.lang.reflect.ParameterizedType;
19+
import java.lang.reflect.Type;
20+
21+
import org.mockito.Mockito;
22+
23+
/**
24+
* @author Christoph Strobl
25+
*/
26+
public abstract class AbstractConnectionUnitTestBase<T> {
27+
28+
private T nativeRedisConnectionMock;
29+
30+
protected T getNativeRedisConnectionMock() {
31+
32+
if (this.nativeRedisConnectionMock == null) {
33+
Class<T> type = resolveReturnedClassFromGernericType();
34+
this.nativeRedisConnectionMock = Mockito.mock(type);
35+
}
36+
37+
return this.nativeRedisConnectionMock;
38+
}
39+
40+
protected T verifyNativeConnectionInvocation() {
41+
return Mockito.verify(getNativeRedisConnectionMock(), Mockito.times(1));
42+
}
43+
44+
protected void setNativeRedisConnectionMock(T nativeRedisConnectionMock) {
45+
this.nativeRedisConnectionMock = nativeRedisConnectionMock;
46+
}
47+
48+
@SuppressWarnings("unchecked")
49+
private Class<T> resolveReturnedClassFromGernericType() {
50+
51+
ParameterizedType parameterizedType = resolveReturnedClassFromGernericType(getClass());
52+
return (Class<T>) parameterizedType.getActualTypeArguments()[0];
53+
}
54+
55+
private ParameterizedType resolveReturnedClassFromGernericType(Class<?> clazz) {
56+
57+
Object genericSuperclass = clazz.getGenericSuperclass();
58+
if (genericSuperclass instanceof ParameterizedType) {
59+
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
60+
Type rawtype = parameterizedType.getRawType();
61+
if (AbstractConnectionUnitTestBase.class.equals(rawtype)) {
62+
return parameterizedType;
63+
}
64+
}
65+
66+
return resolveReturnedClassFromGernericType(clazz.getSuperclass());
67+
}
68+
69+
}

src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTests.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.mockito.Mock;
3636
import org.mockito.MockitoAnnotations;
3737
import org.springframework.data.redis.connection.RedisListCommands.Position;
38+
import org.springframework.data.redis.connection.RedisServerCommands.ShutdownOption;
3839
import org.springframework.data.redis.connection.RedisStringCommands.BitOperation;
3940
import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate;
4041
import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
@@ -1699,6 +1700,16 @@ public void testTimeIsDelegatedCorrectlyToNativeConnection() {
16991700
verifyResults(Arrays.asList(1L));
17001701
}
17011702

1703+
/**
1704+
* @see DATAREDIS-184
1705+
*/
1706+
@Test
1707+
public void testShutdownInDelegatedCorrectlyToNativeConnection() {
1708+
1709+
connection.shutdown(ShutdownOption.NOSAVE);
1710+
verify(nativeConnection, times(1)).shutdown(eq(ShutdownOption.NOSAVE));
1711+
}
1712+
17021713
protected List<Object> getResults() {
17031714
return actual;
17041715
}

0 commit comments

Comments
 (0)