Add Redis 2.6 bitop and bitcount commands to Connections

DATAREDIS-179
This commit is contained in:
Jennifer Hickey
2013-06-17 13:39:47 -07:00
parent 47cf07b09f
commit 45627760aa
17 changed files with 443 additions and 5 deletions

View File

@@ -452,6 +452,18 @@ public class DefaultStringRedisConnection implements StringRedisConnection {
return delegate.strLen(key);
}
public Long bitCount(byte[] key) {
return delegate.bitCount(key);
}
public Long bitCount(byte[] key, long begin, long end) {
return delegate.bitCount(key, begin, end);
}
public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) {
return delegate.bitOp(op, destination, keys);
}
public void subscribe(MessageListener listener, byte[]... channels) {
delegate.subscribe(listener, channels);
}
@@ -1023,8 +1035,19 @@ public class DefaultStringRedisConnection implements StringRedisConnection {
public Long strLen(String key) {
return delegate.strLen(serialize(key));
}
public Long bitCount(String key) {
return delegate.bitCount(serialize(key));
}
public Long bitCount(String key, long begin, long end) {
return delegate.bitCount(serialize(key));
}
public Long bitOp(BitOperation op, String destination, String... keys) {
return delegate.bitOp(op, serialize(destination), serializeMulti(keys));
}
public void subscribe(MessageListener listener, String... channels) {
delegate.subscribe(listener, serializeMulti(channels));
}

View File

@@ -26,6 +26,10 @@ import java.util.Map;
*/
public interface RedisStringCommands {
public enum BitOperation {
AND, OR, XOR, NOT;
}
byte[] get(byte[] key);
byte[] getSet(byte[] key, byte[] value);
@@ -60,5 +64,11 @@ public interface RedisStringCommands {
void setBit(byte[] key, long offset, boolean value);
Long bitCount(byte[] key);
Long bitCount(byte[] key, long begin, long end);
Long bitOp(BitOperation op, byte[] destination, byte[]... keys);
Long strLen(byte[] key);
}

View File

@@ -115,6 +115,12 @@ public interface StringRedisConnection extends RedisConnection {
void setBit(String key, long offset, boolean value);
Long bitCount(String key);
Long bitCount(String key, long begin, long end);
Long bitOp(BitOperation op, String destination, String... keys);
Long strLen(String key);
Long rPush(String key, String value);

View File

@@ -1188,11 +1188,25 @@ public class JedisConnection implements RedisConnection {
}
}
public Long bitCount(byte[] key) {
throw new UnsupportedOperationException();
}
public Long bitCount(byte[] key, long begin, long end) {
throw new UnsupportedOperationException();
}
public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) {
throw new UnsupportedOperationException();
}
//
// List commands
//
public Long lPush(byte[] key, byte[] value) {
try {
if (isQueueing()) {

View File

@@ -609,6 +609,21 @@ public class JredisConnection implements RedisConnection {
throw new UnsupportedOperationException();
}
public Long bitCount(byte[] key) {
throw new UnsupportedOperationException();
}
public Long bitCount(byte[] key, long begin, long end) {
throw new UnsupportedOperationException();
}
public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) {
throw new UnsupportedOperationException();
}
//
// List commands
//

View File

@@ -999,6 +999,47 @@ public class LettuceConnection implements RedisConnection {
}
}
public Long bitCount(byte[] key) {
try {
if (isPipelined()) {
pipeline(getAsyncConnection().bitcount(key));
return null;
}
return getConnection().bitcount(key);
} catch (Exception ex) {
throw convertLettuceAccessException(ex);
}
}
public Long bitCount(byte[] key, long begin, long end) {
try {
if (isPipelined()) {
pipeline(getAsyncConnection().bitcount(key, begin, end));
return null;
}
return getConnection().bitcount(key, begin, end);
} catch (Exception ex) {
throw convertLettuceAccessException(ex);
}
}
public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) {
try {
if (isPipelined()) {
pipeline(asyncBitOp(op, destination, keys));
return null;
}
return syncBitOp(op, destination, keys);
} catch (UnsupportedOperationException ex) {
throw ex;
} catch (Exception ex) {
throw convertLettuceAccessException(ex);
}
}
//
// List commands
//
@@ -2024,4 +2065,40 @@ public class LettuceConnection implements RedisConnection {
}
return txConn;
}
private Future<Long> asyncBitOp(BitOperation op, byte[] destination, byte[]... keys) {
switch (op) {
case AND:
return getAsyncConnection().bitopAnd(destination, keys);
case OR:
return getAsyncConnection().bitopOr(destination, keys);
case XOR:
return getAsyncConnection().bitopXor(destination, keys);
case NOT:
if (keys.length != 1) {
throw new UnsupportedOperationException("Bitop NOT should only be performed against one key");
}
return getAsyncConnection().bitopNot(destination, keys[0]);
default:
throw new UnsupportedOperationException("Bit operation " + op + " is not supported");
}
}
private Long syncBitOp(BitOperation op, byte[] destination, byte[]... keys) {
switch (op) {
case AND:
return getConnection().bitopAnd(destination, keys);
case OR:
return getConnection().bitopOr(destination, keys);
case XOR:
return getConnection().bitopXor(destination, keys);
case NOT:
if (keys.length != 1) {
throw new UnsupportedOperationException("Bitop NOT should only be performed against one key");
}
return getConnection().bitopNot(destination, keys[0]);
default:
throw new UnsupportedOperationException("Bit operation " + op + " is not supported");
}
}
}

View File

@@ -68,6 +68,7 @@ public class SrpConnection implements RedisConnection {
private PipelineTracker callback;
private volatile SrpSubscription subscription;
@SuppressWarnings("rawtypes")
private static class PipelineTracker implements FutureCallback<Reply> {
private final List<Object> results = Collections.synchronizedList(new ArrayList<Object>());
@@ -954,11 +955,49 @@ public class SrpConnection implements RedisConnection {
}
}
public Long bitCount(byte[] key) {
try {
if (isPipelined()) {
pipeline(pipeline.bitcount(key, 0, -1));
return null;
}
return client.bitcount(key, 0, -1).data();
} catch (Exception ex) {
throw convertSrpAccessException(ex);
}
}
public Long bitCount(byte[] key, long begin, long end) {
try {
if (isPipelined()) {
pipeline(pipeline.bitcount(key, begin, end));
return null;
}
return client.bitcount(key, begin, end).data();
} catch (Exception ex) {
throw convertSrpAccessException(ex);
}
}
public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) {
try {
if (isPipelined()) {
pipeline(pipeline.bitop(SrpUtils.bitOp(op), destination, (Object[]) keys));
return null;
}
return client.bitop(SrpUtils.bitOp(op), destination, (Object[])keys).data();
} catch (Exception ex) {
throw convertSrpAccessException(ex);
}
}
//
// List commands
//
public Long lPush(byte[] key, byte[] value) {
try {
if (isPipelined()) {
@@ -1932,6 +1971,7 @@ public class SrpConnection implements RedisConnection {
}
// processing method that adds a listener to the future in order to track down the results and close the pipeline
@SuppressWarnings("rawtypes")
private void pipeline(ListenableFuture<? extends Reply> future) {
callback.addCommand(future);
}

View File

@@ -30,6 +30,7 @@ import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.RedisSystemException;
import org.springframework.data.redis.connection.DefaultTuple;
import org.springframework.data.redis.connection.RedisListCommands.Position;
import org.springframework.data.redis.connection.RedisStringCommands.BitOperation;
import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
import org.springframework.data.redis.connection.SortParameters;
import org.springframework.util.Assert;
@@ -83,6 +84,7 @@ abstract class SrpUtils {
return info;
}
@SuppressWarnings("rawtypes")
static List<byte[]> toBytesList(Reply[] replies) {
if(replies == null) {
return null;
@@ -106,6 +108,7 @@ abstract class SrpUtils {
return Arrays.asList(byteArrays);
}
@SuppressWarnings("rawtypes")
static Set<byte[]> toSet(Reply[] byteArrays) {
return new LinkedHashSet<byte[]>(toBytesList(byteArrays));
}
@@ -142,6 +145,7 @@ abstract class SrpUtils {
return convertTuple(zrange.data());
}
@SuppressWarnings("rawtypes")
static Set<Tuple> convertTuple(Reply[] byteArrays) {
Set<Tuple> tuples = new LinkedHashSet<Tuple>(byteArrays.length / 2 + 1);
@@ -168,6 +172,7 @@ abstract class SrpUtils {
return args;
}
@SuppressWarnings("rawtypes")
static Map<byte[], byte[]> toMap(Reply[] byteArrays) {
Map<byte[], byte[]> map = new LinkedHashMap<byte[], byte[]>(byteArrays.length / 2);
for (int i = 0; i < byteArrays.length; i++) {
@@ -263,4 +268,9 @@ abstract class SrpUtils {
return arrays.toArray();
}
static byte[] bitOp(BitOperation op) {
Assert.notNull(op, "The bit operation is required");
return op.name().toUpperCase().getBytes(Charsets.UTF_8);
}
}