DATAREDIS-267 - Add support for 'CLIENT KILL'.

Killing a client connection can be done via 'RedisConnection' and 'RedisOperations' using 'jedis', 'lettuce' and 'srp'.

We use dedicated parameters for host and port building up the redis format (host:port) for connection identification.

Original Pull Request: #56
This commit is contained in:
Christoph Strobl
2014-03-24 15:03:14 +01:00
committed by Thomas Darimont
parent 1c47330ec9
commit 6a6d03eb4c
12 changed files with 147 additions and 3 deletions

View File

@@ -2191,6 +2191,15 @@ public class DefaultStringRedisConnection implements StringRedisConnection {
return this.delegate.time();
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#killClient(byte[])
*/
@Override
public void killClient(String host, int port) {
this.delegate.killClient(host, port);
}
/**
* 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

View File

@@ -161,4 +161,14 @@ public interface RedisServerCommands {
* @since 1.1
*/
Long time();
/**
* Closes a given client connection identified by {@literal ip:port}.
*
* @param host of connection to close.
* @param port of connection to close
* @since 1.3
*/
void killClient(String host, int port);
}

View File

@@ -2808,6 +2808,26 @@ public class JedisConnection implements RedisConnection {
return Converters.toTimeMillis(serverTimeInformation.get(0), serverTimeInformation.get(1));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#killClient(byte[])
*/
@Override
public void killClient(String host, int port) {
Assert.hasText(host, "Host for 'CLIENT KILL' must not be 'null' or 'empty'.");
if (isQueueing() || isPipelined()) {
throw new UnsupportedOperationException("'CLIENT KILL' is not supported in transaction / pipline mode.");
}
try {
this.jedis.clientKill(String.format("%s:%s", host, port));
} 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

View File

@@ -1185,4 +1185,9 @@ public class JredisConnection implements RedisConnection {
public Long time() {
throw new UnsupportedOperationException("The 'TIME' command is not supported by the JRedis driver.");
}
@Override
public void killClient(String host, int port) {
throw new UnsupportedOperationException("The 'CLIENT KILL' command is not supported by the JRedis driver.");
}
}

View File

@@ -2903,6 +2903,23 @@ public class LettuceConnection implements RedisConnection {
return Converters.toTimeMillis(new String(result.get(0)), new String(result.get(1)));
}
@Override
public void killClient(String host, int port) {
Assert.hasText(host, "Host for 'CLIENT KILL' must not be 'null' or 'empty'.");
String client = String.format("%s:%s", host, port);
try {
if (isPipelined()) {
pipeline(new LettuceStatusResult(getAsyncConnection().clientKill(client)));
return;
}
getConnection().clientKill(client);
} catch (Exception e) {
convertLettuceAccessException(e);
}
}
/**
* 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

View File

@@ -2222,6 +2222,24 @@ public class SrpConnection implements RedisConnection {
return SrpConverters.toTimeAsLong(reply.data());
}
@Override
public void killClient(String host, int port) {
Assert.hasText(host, "Host for 'CLIENT KILL' must not be 'null' or 'empty'.");
String client = String.format("%s:%s", host, port);
try {
if (isPipelined()) {
pipeline(new SrpStatusResult(pipeline.client_kill(client)));
return;
}
this.client.client_kill(client);
} catch (Exception e) {
throw convertSrpAccessException(e);
}
}
private List<Object> closeTransaction() {
List<Object> results = Collections.emptyList();
if (txTracker != null) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 the original author or authors.
* Copyright 2011-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.
@@ -31,6 +31,7 @@ import org.springframework.data.redis.serializer.RedisSerializer;
* useful option for extensibility and testability (as it can be easily mocked or stubbed).
*
* @author Costin Leau
* @author Christoph Strobl
*/
public interface RedisOperations<K, V> {
@@ -284,4 +285,13 @@ public interface RedisOperations<K, V> {
RedisSerializer<?> getHashKeySerializer();
RedisSerializer<?> getHashValueSerializer();
/**
* Closes a given client connection identified by {@literal ip:port} given in {@code client}.
*
* @param host of connection to close.
* @param port of connection to close
* @since 1.3
*/
void killClient(String host, int port);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 the original author or authors.
* Copyright 2011-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.
@@ -69,6 +69,7 @@ import org.springframework.util.CollectionUtils;
* <b>This is the central class in Redis support</b>.
*
* @author Costin Leau
* @author Christoph Strobl
* @param <K> the Redis key type against which the template works (usually a String)
* @param <V> the Redis value type against which the template works
* @see StringRedisTemplate
@@ -989,4 +990,21 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
public <HK, HV> HashOperations<K, HK, HV> opsForHash() {
return new DefaultHashOperations<K, HK, HV>(this);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.RedisOperations#killClient(java.lang.Object)
*/
@Override
public void killClient(final String host, final int port) {
execute(new RedisCallback<Void>() {
@Override
public Void doInRedis(RedisConnection connection) throws DataAccessException {
connection.killClient(host, port);
return null;
}
});
}
}