diff --git a/.gitignore b/.gitignore index d77754e..982e6b6 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ target/ build/ bin/ +tags diff --git a/src/main/java/redis/clients/jedis/BinaryClient.java b/src/main/java/redis/clients/jedis/BinaryClient.java index 778e97e..34fe202 100644 --- a/src/main/java/redis/clients/jedis/BinaryClient.java +++ b/src/main/java/redis/clients/jedis/BinaryClient.java @@ -819,4 +819,41 @@ public class BinaryClient extends Connection { public void objectEncoding(byte[] key) { sendCommand(OBJECT, ENCODING.raw, key); } + + public void bitcount(byte[] key) { + sendCommand(BITCOUNT, key); + } + + public void bitcount(byte[] key, long start, long end) { + sendCommand(BITCOUNT, key, toByteArray(start), toByteArray(end)); + } + + public void bitop(BitOP op, byte[] destKey, byte[]... srcKeys) { + Keyword kw = Keyword.AND; + int len = srcKeys.length; + switch (op) { + case AND: + kw = Keyword.AND; + break; + case OR: + kw = Keyword.OR; + break; + case XOR: + kw = Keyword.XOR; + break; + case NOT: + kw = Keyword.NOT; + len = Math.min(1, len); + break; + } + + byte[][] bargs = new byte[len + 2][]; + bargs[0] = kw.raw; + bargs[1] = destKey; + for (int i = 0; i < len; ++i) { + bargs[i + 2] = srcKeys[i]; + } + + sendCommand(BITOP, bargs); + } } diff --git a/src/main/java/redis/clients/jedis/BinaryJedis.java b/src/main/java/redis/clients/jedis/BinaryJedis.java index d26043d..06a83de 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryJedis.java @@ -3218,4 +3218,19 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey client.objectIdletime(key); return client.getIntegerReply(); } + + public Long bitcount(final byte[] key) { + client.bitcount(key); + return client.getIntegerReply(); + } + + public Long bitcount(final byte[] key, long start, long end) { + client.bitcount(key, start, end); + return client.getIntegerReply(); + } + + public Long bitop(BitOP op, final byte[] destKey, byte[]... srcKeys) { + client.bitop(op, destKey, srcKeys); + return client.getIntegerReply(); + } } diff --git a/src/main/java/redis/clients/jedis/BinaryJedisCommands.java b/src/main/java/redis/clients/jedis/BinaryJedisCommands.java index 71b630e..a6da912 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedisCommands.java +++ b/src/main/java/redis/clients/jedis/BinaryJedisCommands.java @@ -209,4 +209,8 @@ public interface BinaryJedisCommands { byte[] echo(byte[] arg); Long move(byte[] key, int dbIndex); + + Long bitcount(final byte[] key); + + Long bitcount(final byte[] key, long start, long end); } diff --git a/src/main/java/redis/clients/jedis/BinaryRedisPipeline.java b/src/main/java/redis/clients/jedis/BinaryRedisPipeline.java index af57473..3722351 100644 --- a/src/main/java/redis/clients/jedis/BinaryRedisPipeline.java +++ b/src/main/java/redis/clients/jedis/BinaryRedisPipeline.java @@ -212,4 +212,8 @@ public interface BinaryRedisPipeline { Response zrevrank(byte[] key, byte[] member); Response zscore(byte[] key, byte[] member); + + Response bitcount(byte[] key); + + Response bitcount(byte[] key, long start, long end); } diff --git a/src/main/java/redis/clients/jedis/BinaryShardedJedis.java b/src/main/java/redis/clients/jedis/BinaryShardedJedis.java index e8a5dc5..20065d7 100644 --- a/src/main/java/redis/clients/jedis/BinaryShardedJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryShardedJedis.java @@ -554,5 +554,13 @@ public class BinaryShardedJedis extends Sharded return j.blpop(arg); } + public Long bitcount(byte[] key) { + Jedis j = getShard(key); + return j.bitcount(key); + } + public Long bitcount(byte[] key, long start, long end) { + Jedis j = getShard(key); + return j.bitcount(key, start, end); + } } \ No newline at end of file diff --git a/src/main/java/redis/clients/jedis/BitOP.java b/src/main/java/redis/clients/jedis/BitOP.java new file mode 100644 index 0000000..5e3ee89 --- /dev/null +++ b/src/main/java/redis/clients/jedis/BitOP.java @@ -0,0 +1,8 @@ +package redis.clients.jedis; + +public enum BitOP { + AND, + OR, + XOR, + NOT; +} diff --git a/src/main/java/redis/clients/jedis/Client.java b/src/main/java/redis/clients/jedis/Client.java index dd1b12b..9e17202 100644 --- a/src/main/java/redis/clients/jedis/Client.java +++ b/src/main/java/redis/clients/jedis/Client.java @@ -707,4 +707,16 @@ public class Client extends BinaryClient implements Commands { public void objectEncoding(String key) { objectEncoding(SafeEncoder.encode(key)); } + + public void bitcount(final String key) { + bitcount(SafeEncoder.encode(key)); + } + + public void bitcount(final String key, long start, long end) { + bitcount(SafeEncoder.encode(key), start, end); + } + + public void bitop(BitOP op, final String destKey, String... srcKeys) { + bitop(op, SafeEncoder.encode(destKey), getByteParams(srcKeys)); + } } diff --git a/src/main/java/redis/clients/jedis/Commands.java b/src/main/java/redis/clients/jedis/Commands.java index 0023158..a5df878 100644 --- a/src/main/java/redis/clients/jedis/Commands.java +++ b/src/main/java/redis/clients/jedis/Commands.java @@ -287,4 +287,10 @@ public interface Commands { public void objectIdletime(String key); public void objectEncoding(String key); -} \ No newline at end of file + + public void bitcount(final String key); + + public void bitcount(final String key, long start, long end); + + public void bitop(BitOP op, final String destKey, String... srcKeys); +} diff --git a/src/main/java/redis/clients/jedis/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index e2c2c72..d8dbb56 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -814,8 +814,6 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand *

* Time complexity: O(1) * - * @see Jedis#lpush(String, String) - * * @param key * @param strings * @return Integer reply, specifically, the number of elements inside the @@ -835,8 +833,6 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand *

* Time complexity: O(1) * - * @see Jedis#rpush(String, String) - * * @param key * @param strings * @return Integer reply, specifically, the number of elements inside the @@ -2844,4 +2840,19 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand client.objectIdletime(string); return client.getIntegerReply(); } + + public Long bitcount(final String key) { + client.bitcount(key); + return client.getIntegerReply(); + } + + public Long bitcount(final String key, long start, long end) { + client.bitcount(key, start, end); + return client.getIntegerReply(); + } + + public Long bitop(BitOP op, final String destKey, String... srcKeys) { + client.bitop(op, destKey, srcKeys); + return client.getIntegerReply(); + } } diff --git a/src/main/java/redis/clients/jedis/JedisCommands.java b/src/main/java/redis/clients/jedis/JedisCommands.java index 54fdb77..2dab095 100644 --- a/src/main/java/redis/clients/jedis/JedisCommands.java +++ b/src/main/java/redis/clients/jedis/JedisCommands.java @@ -206,4 +206,8 @@ public interface JedisCommands { String echo(String string); Long move(String key, int dbIndex); + + Long bitcount(final String key); + + Long bitcount(final String key, long start, long end); } diff --git a/src/main/java/redis/clients/jedis/MultiKeyBinaryCommands.java b/src/main/java/redis/clients/jedis/MultiKeyBinaryCommands.java index 277b70e..1b3c158 100644 --- a/src/main/java/redis/clients/jedis/MultiKeyBinaryCommands.java +++ b/src/main/java/redis/clients/jedis/MultiKeyBinaryCommands.java @@ -68,4 +68,6 @@ public interface MultiKeyBinaryCommands { void psubscribe(BinaryJedisPubSub jedisPubSub, byte[]... patterns); byte[] randomBinaryKey(); + + Long bitop(BitOP op, final byte[] destKey, byte[]... srcKeys); } diff --git a/src/main/java/redis/clients/jedis/MultiKeyBinaryRedisPipeline.java b/src/main/java/redis/clients/jedis/MultiKeyBinaryRedisPipeline.java index 1413774..74f0e3d 100644 --- a/src/main/java/redis/clients/jedis/MultiKeyBinaryRedisPipeline.java +++ b/src/main/java/redis/clients/jedis/MultiKeyBinaryRedisPipeline.java @@ -62,4 +62,6 @@ public interface MultiKeyBinaryRedisPipeline { Response publish(byte[] channel, byte[] message); Response randomKeyBinary(); + + Response bitop(BitOP op, final byte[] destKey, byte[]... srcKeys); } diff --git a/src/main/java/redis/clients/jedis/MultiKeyCommands.java b/src/main/java/redis/clients/jedis/MultiKeyCommands.java index d2386a6..c98017f 100644 --- a/src/main/java/redis/clients/jedis/MultiKeyCommands.java +++ b/src/main/java/redis/clients/jedis/MultiKeyCommands.java @@ -68,4 +68,6 @@ public interface MultiKeyCommands { void psubscribe(JedisPubSub jedisPubSub, String... patterns); String randomKey(); + + Long bitop(BitOP op, final String destKey, String... srcKeys); } diff --git a/src/main/java/redis/clients/jedis/MultiKeyCommandsPipeline.java b/src/main/java/redis/clients/jedis/MultiKeyCommandsPipeline.java index 9960537..1478e81 100644 --- a/src/main/java/redis/clients/jedis/MultiKeyCommandsPipeline.java +++ b/src/main/java/redis/clients/jedis/MultiKeyCommandsPipeline.java @@ -62,4 +62,6 @@ public interface MultiKeyCommandsPipeline { Response publish(String channel, String message); Response randomKey(); + + Response bitop(BitOP op, final String destKey, String... srcKeys); } diff --git a/src/main/java/redis/clients/jedis/Pipeline.java b/src/main/java/redis/clients/jedis/Pipeline.java index ae8518c..afd98f5 100755 --- a/src/main/java/redis/clients/jedis/Pipeline.java +++ b/src/main/java/redis/clients/jedis/Pipeline.java @@ -1388,5 +1388,35 @@ public class Pipeline extends Queable implements public Response select(int index){ client.select(index); return getResponse(BuilderFactory.STRING); - } + } + + public Response bitcount(String key) { + client.bitcount(key); + return getResponse(BuilderFactory.LONG); + } + + public Response bitcount(String key, long start, long end) { + client.bitcount(key, start, end); + return getResponse(BuilderFactory.LONG); + } + + public Response bitcount(byte[] key) { + client.bitcount(key); + return getResponse(BuilderFactory.LONG); + } + + public Response bitcount(byte[] key, long start, long end) { + client.bitcount(key, start, end); + return getResponse(BuilderFactory.LONG); + } + + public Response bitop(BitOP op, byte[] destKey, byte[]... srcKeys) { + client.bitop(op, destKey, srcKeys); + return getResponse(BuilderFactory.LONG); + } + + public Response bitop(BitOP op, String destKey, String... srcKeys) { + client.bitop(op, destKey, srcKeys); + return getResponse(BuilderFactory.LONG); + } } diff --git a/src/main/java/redis/clients/jedis/Protocol.java b/src/main/java/redis/clients/jedis/Protocol.java index e3126db..cc40fe4 100644 --- a/src/main/java/redis/clients/jedis/Protocol.java +++ b/src/main/java/redis/clients/jedis/Protocol.java @@ -148,7 +148,7 @@ public final class Protocol { } public static enum Command { - PING, SET, GET, QUIT, EXISTS, DEL, TYPE, FLUSHDB, KEYS, RANDOMKEY, RENAME, RENAMENX, RENAMEX, DBSIZE, EXPIRE, EXPIREAT, TTL, SELECT, MOVE, FLUSHALL, GETSET, MGET, SETNX, SETEX, MSET, MSETNX, DECRBY, DECR, INCRBY, INCR, APPEND, SUBSTR, HSET, HGET, HSETNX, HMSET, HMGET, HINCRBY, HEXISTS, HDEL, HLEN, HKEYS, HVALS, HGETALL, RPUSH, LPUSH, LLEN, LRANGE, LTRIM, LINDEX, LSET, LREM, LPOP, RPOP, RPOPLPUSH, SADD, SMEMBERS, SREM, SPOP, SMOVE, SCARD, SISMEMBER, SINTER, SINTERSTORE, SUNION, SUNIONSTORE, SDIFF, SDIFFSTORE, SRANDMEMBER, ZADD, ZRANGE, ZREM, ZINCRBY, ZRANK, ZREVRANK, ZREVRANGE, ZCARD, ZSCORE, MULTI, DISCARD, EXEC, WATCH, UNWATCH, SORT, BLPOP, BRPOP, AUTH, SUBSCRIBE, PUBLISH, UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, ZCOUNT, ZRANGEBYSCORE, ZREVRANGEBYSCORE, ZREMRANGEBYRANK, ZREMRANGEBYSCORE, ZUNIONSTORE, ZINTERSTORE, SAVE, BGSAVE, BGREWRITEAOF, LASTSAVE, SHUTDOWN, INFO, MONITOR, SLAVEOF, CONFIG, STRLEN, SYNC, LPUSHX, PERSIST, RPUSHX, ECHO, LINSERT, DEBUG, BRPOPLPUSH, SETBIT, GETBIT, SETRANGE, GETRANGE, EVAL, EVALSHA, SCRIPT, SLOWLOG, OBJECT; + PING, SET, GET, QUIT, EXISTS, DEL, TYPE, FLUSHDB, KEYS, RANDOMKEY, RENAME, RENAMENX, RENAMEX, DBSIZE, EXPIRE, EXPIREAT, TTL, SELECT, MOVE, FLUSHALL, GETSET, MGET, SETNX, SETEX, MSET, MSETNX, DECRBY, DECR, INCRBY, INCR, APPEND, SUBSTR, HSET, HGET, HSETNX, HMSET, HMGET, HINCRBY, HEXISTS, HDEL, HLEN, HKEYS, HVALS, HGETALL, RPUSH, LPUSH, LLEN, LRANGE, LTRIM, LINDEX, LSET, LREM, LPOP, RPOP, RPOPLPUSH, SADD, SMEMBERS, SREM, SPOP, SMOVE, SCARD, SISMEMBER, SINTER, SINTERSTORE, SUNION, SUNIONSTORE, SDIFF, SDIFFSTORE, SRANDMEMBER, ZADD, ZRANGE, ZREM, ZINCRBY, ZRANK, ZREVRANK, ZREVRANGE, ZCARD, ZSCORE, MULTI, DISCARD, EXEC, WATCH, UNWATCH, SORT, BLPOP, BRPOP, AUTH, SUBSCRIBE, PUBLISH, UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, ZCOUNT, ZRANGEBYSCORE, ZREVRANGEBYSCORE, ZREMRANGEBYRANK, ZREMRANGEBYSCORE, ZUNIONSTORE, ZINTERSTORE, SAVE, BGSAVE, BGREWRITEAOF, LASTSAVE, SHUTDOWN, INFO, MONITOR, SLAVEOF, CONFIG, STRLEN, SYNC, LPUSHX, PERSIST, RPUSHX, ECHO, LINSERT, DEBUG, BRPOPLPUSH, SETBIT, GETBIT, SETRANGE, GETRANGE, EVAL, EVALSHA, SCRIPT, SLOWLOG, OBJECT, BITCOUNT, BITOP; public final byte[] raw; @@ -158,7 +158,7 @@ public final class Protocol { } public static enum Keyword { - AGGREGATE, ALPHA, ASC, BY, DESC, GET, LIMIT, MESSAGE, NO, NOSORT, PMESSAGE, PSUBSCRIBE, PUNSUBSCRIBE, OK, ONE, QUEUED, SET, STORE, SUBSCRIBE, UNSUBSCRIBE, WEIGHTS, WITHSCORES, RESETSTAT, RESET, FLUSH, EXISTS, LOAD, KILL, LEN, REFCOUNT, ENCODING, IDLETIME; + AGGREGATE, ALPHA, ASC, BY, DESC, GET, LIMIT, MESSAGE, NO, NOSORT, PMESSAGE, PSUBSCRIBE, PUNSUBSCRIBE, OK, ONE, QUEUED, SET, STORE, SUBSCRIBE, UNSUBSCRIBE, WEIGHTS, WITHSCORES, RESETSTAT, RESET, FLUSH, EXISTS, LOAD, KILL, LEN, REFCOUNT, ENCODING, IDLETIME, AND, OR, XOR, NOT; public final byte[] raw; Keyword() { diff --git a/src/main/java/redis/clients/jedis/RedisPipeline.java b/src/main/java/redis/clients/jedis/RedisPipeline.java index 3d79393..8d42aa2 100644 --- a/src/main/java/redis/clients/jedis/RedisPipeline.java +++ b/src/main/java/redis/clients/jedis/RedisPipeline.java @@ -193,4 +193,8 @@ public interface RedisPipeline { Response zrevrank(String key, String member); Response zscore(String key, String member); + + Response bitcount(String key); + + Response bitcount(String key, long start, long end); } diff --git a/src/main/java/redis/clients/jedis/ShardedJedis.java b/src/main/java/redis/clients/jedis/ShardedJedis.java index 142e754..948718c 100644 --- a/src/main/java/redis/clients/jedis/ShardedJedis.java +++ b/src/main/java/redis/clients/jedis/ShardedJedis.java @@ -511,4 +511,16 @@ public class ShardedJedis extends BinaryShardedJedis implements JedisCommands { Jedis j = getShard(key); return j.linsert(key, where, pivot, value); } + + public Long bitcount(final String key) { + Jedis j = getShard(key); + return j.bitcount(key); + } + + public Long bitcount(final String key, long start, long end) { + Jedis j = getShard(key); + return j.bitcount(key, start, end); + } + + } diff --git a/src/main/java/redis/clients/jedis/ShardedJedisPipeline.java b/src/main/java/redis/clients/jedis/ShardedJedisPipeline.java index 8725bf3..1234b44 100644 --- a/src/main/java/redis/clients/jedis/ShardedJedisPipeline.java +++ b/src/main/java/redis/clients/jedis/ShardedJedisPipeline.java @@ -1282,6 +1282,34 @@ public class ShardedJedisPipeline extends Queable implements BinaryRedisPipeline return getResponse(BuilderFactory.LONG); } + public Response bitcount(String key) { + Client c = getClient(key); + c.bitcount(key); + results.add(new FutureResult(c)); + return getResponse(BuilderFactory.LONG); + } + + public Response bitcount(String key, long start, long end) { + Client c = getClient(key); + c.bitcount(key, start, end); + results.add(new FutureResult(c)); + return getResponse(BuilderFactory.LONG); + } + + public Response bitcount(byte[] key) { + Client c = getClient(key); + c.bitcount(key); + results.add(new FutureResult(c)); + return getResponse(BuilderFactory.LONG); + } + + public Response bitcount(byte[] key, long start, long end) { + Client c = getClient(key); + c.bitcount(key, start, end); + results.add(new FutureResult(c)); + return getResponse(BuilderFactory.LONG); + } + public List getResults() { List r = new ArrayList(); for (FutureResult fr : results) { diff --git a/src/test/java/redis/clients/jedis/tests/commands/BitCommandsTest.java b/src/test/java/redis/clients/jedis/tests/commands/BitCommandsTest.java index 047ca20..87b044f 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/BitCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/BitCommandsTest.java @@ -2,6 +2,8 @@ package redis.clients.jedis.tests.commands; import org.junit.Test; +import redis.clients.jedis.BitOP; + public class BitCommandsTest extends JedisCommandTestBase { @Test public void setAndgetbit() { @@ -29,4 +31,63 @@ public class BitCommandsTest extends JedisCommandTestBase { assertEquals("Hello", jedis.getrange("key1", 0, 4)); assertEquals("Jedis", jedis.getrange("key1", 6, 11)); } -} \ No newline at end of file + + @Test + public void bitCount() { + jedis.del("foo"); + + jedis.setbit("foo", 16, true); + jedis.setbit("foo", 24, true); + jedis.setbit("foo", 40, true); + jedis.setbit("foo", 56, true); + + long c4 = jedis.bitcount("foo"); + assertEquals(4, c4); + + long c3 = jedis.bitcount("foo", 2L, 5L); + assertEquals(3, c3); + + jedis.del("foo"); + } + + @Test + public void bitOp() + { + jedis.set("key1", "\u0060"); + jedis.set("key2", "\u0044"); + + jedis.bitop(BitOP.AND, "resultAnd", "key1", "key2"); + String resultAnd = jedis.get("resultAnd"); + assertEquals("\u0040", resultAnd); + + jedis.bitop(BitOP.OR, "resultOr", "key1", "key2"); + String resultOr = jedis.get("resultOr"); + assertEquals("\u0064", resultOr); + + jedis.bitop(BitOP.XOR, "resultXor", "key1", "key2"); + String resultXor = jedis.get("resultXor"); + assertEquals("\u0024", resultXor); + + jedis.del("resultAnd"); + jedis.del("resultOr"); + jedis.del("resultXor"); + jedis.del("key1"); + jedis.del("key2"); + } + + @Test + public void bitOpNot() + { + jedis.del("key"); + jedis.setbit("key", 0, true); + jedis.setbit("key", 4, true); + + jedis.bitop(BitOP.NOT, "resultNot", "key"); + + String resultNot = jedis.get("resultNot"); + assertEquals("\u0077", resultNot); + + jedis.del("key"); + jedis.del("resultNot"); + } +}