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 a5323d2..91f75b3 100644 --- a/src/main/java/redis/clients/jedis/BinaryClient.java +++ b/src/main/java/redis/clients/jedis/BinaryClient.java @@ -807,4 +807,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, String... 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] = SafeEncoder.encode(srcKeys[i]); + } + + sendCommand(BITOP, bargs); + } } 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 39aae12..648d3ed 100644 --- a/src/main/java/redis/clients/jedis/Client.java +++ b/src/main/java/redis/clients/jedis/Client.java @@ -703,4 +703,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), srcKeys); + } } diff --git a/src/main/java/redis/clients/jedis/Commands.java b/src/main/java/redis/clients/jedis/Commands.java index 7881909..6227492 100644 --- a/src/main/java/redis/clients/jedis/Commands.java +++ b/src/main/java/redis/clients/jedis/Commands.java @@ -285,4 +285,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 f27c2bc..1f1ca8c 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -2873,4 +2873,20 @@ public class Jedis extends BinaryJedis implements JedisCommands { 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 d4c07f3..ee87aa2 100644 --- a/src/main/java/redis/clients/jedis/JedisCommands.java +++ b/src/main/java/redis/clients/jedis/JedisCommands.java @@ -190,4 +190,11 @@ public interface JedisCommands { Long lpushx(String key, String string); Long rpushx(String key, String string); + + Long bitcount(final String key); + + Long bitcount(final String key, long start, long end); + + Long bitop(BitOP op, final String destKey, String... srcKeys); + } diff --git a/src/main/java/redis/clients/jedis/Protocol.java b/src/main/java/redis/clients/jedis/Protocol.java index b1e391d..9c8f381 100644 --- a/src/main/java/redis/clients/jedis/Protocol.java +++ b/src/main/java/redis/clients/jedis/Protocol.java @@ -144,7 +144,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; @@ -154,7 +154,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/ShardedJedis.java b/src/main/java/redis/clients/jedis/ShardedJedis.java index ea2f11e..f4f5341 100644 --- a/src/main/java/redis/clients/jedis/ShardedJedis.java +++ b/src/main/java/redis/clients/jedis/ShardedJedis.java @@ -483,4 +483,19 @@ 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); + } + + public Long bitop(BitOP op, final String destKey, String... srcKeys) { + Jedis j = getShard(destKey); + return j.bitop(op, destKey, srcKeys); + } } 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"); + } +}