From fdeacfc89f19943fe5f9dcc235099186c7f77ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zcc=E3=80=81?= <1104503035@qq.com> Date: Sat, 20 Feb 2021 16:26:49 +0800 Subject: [PATCH] add redis bitmap command (#490) Co-authored-by: zhoudeyu --- core/stores/redis/redis.go | 75 +++++++++++++++++++++++++ core/stores/redis/redis_test.go | 97 +++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) diff --git a/core/stores/redis/redis.go b/core/stores/redis/redis.go index 7fd02ea3..7b9eac1d 100644 --- a/core/stores/redis/redis.go +++ b/core/stores/redis/redis.go @@ -90,6 +90,81 @@ func (s *Redis) BitCount(key string, start, end int64) (val int64, err error) { return } +// BitOpAnd is redis bit operation (and) command implementation. +func (s *Redis) BitOpAnd(destKey string, keys ...string) (val int64, err error) { + err = s.brk.DoWithAcceptable(func() error { + conn, err := getRedis(s) + if err != nil { + return err + } + + val, err = conn.BitOpAnd(destKey, keys...).Result() + return err + }, acceptable) + + return +} + +// BitOpNot is redis bit operation (not) command implementation. +func (s *Redis) BitOpNot(destKey, key string) (val int64, err error) { + err = s.brk.DoWithAcceptable(func() error { + conn, err := getRedis(s) + if err != nil { + return err + } + + val, err = conn.BitOpNot(destKey, key).Result() + return err + }, acceptable) + + return +} + +// BitOpOr is redis bit operation (or) command implementation. +func (s *Redis) BitOpOr(destKey string, keys ...string) (val int64, err error) { + err = s.brk.DoWithAcceptable(func() error { + conn, err := getRedis(s) + if err != nil { + return err + } + + val, err = conn.BitOpOr(destKey, keys...).Result() + return err + }, acceptable) + + return +} + +// BitOpXor is redis bit operation (xor) command implementation. +func (s *Redis) BitOpXor(destKey string, keys ...string) (val int64, err error) { + err = s.brk.DoWithAcceptable(func() error { + conn, err := getRedis(s) + if err != nil { + return err + } + + val, err = conn.BitOpXor(destKey, keys...).Result() + return err + }, acceptable) + + return +} + +// BitPos is redis bitpos command implementation. +func (s *Redis) BitPos(key string, bit int64, start, end int64) (val int64, err error) { + err = s.brk.DoWithAcceptable(func() error { + conn, err := getRedis(s) + if err != nil { + return err + } + + val, err = conn.BitPos(key, bit, start, end).Result() + return err + }, acceptable) + + return +} + // Blpop uses passed in redis connection to execute blocking queries. // Doesn't benefit from pooling redis connections of blocking queries func (s *Redis) Blpop(redisNode RedisNode, key string) (string, error) { diff --git a/core/stores/redis/redis_test.go b/core/stores/redis/redis_test.go index c76e0fc0..790e68b5 100644 --- a/core/stores/redis/redis_test.go +++ b/core/stores/redis/redis_test.go @@ -373,6 +373,103 @@ func TestRedis_BitCount(t *testing.T) { }) } +func TestRedis_BitOpAnd(t *testing.T) { + runOnRedis(t, func(client *Redis) { + err := client.Set("key1", "0") + assert.Nil(t, err) + err = client.Set("key2", "1") + assert.Nil(t, err) + _, err = NewRedis(client.Addr, "").BitOpAnd("destKey", "key1", "key2") + assert.NotNil(t, err) + val, err := client.BitOpAnd("destKey", "key1", "key2") + assert.Nil(t, err) + assert.Equal(t, int64(1), val) + valStr, err := client.Get("destKey") + assert.Nil(t, err) + //destKey binary 110000 ascii 0 + assert.Equal(t, "0", valStr) + }) +} + +func TestRedis_BitOpNot(t *testing.T) { + runOnRedis(t, func(client *Redis) { + err := client.Set("key1", "\u0000") + assert.Nil(t, err) + _, err = NewRedis(client.Addr, "").BitOpNot("destKey", "key1") + assert.NotNil(t, err) + val, err := client.BitOpNot("destKey", "key1") + assert.Nil(t, err) + assert.Equal(t, int64(1), val) + valStr, err := client.Get("destKey") + assert.Nil(t, err) + assert.Equal(t, "\xff", valStr) + }) +} + +func TestRedis_BitOpOr(t *testing.T) { + runOnRedis(t, func(client *Redis) { + err := client.Set("key1", "1") + assert.Nil(t, err) + err = client.Set("key2", "0") + assert.Nil(t, err) + _, err = NewRedis(client.Addr, "").BitOpOr("destKey", "key1", "key2") + assert.NotNil(t, err) + val, err := client.BitOpOr("destKey", "key1", "key2") + assert.Nil(t, err) + assert.Equal(t, int64(1), val) + valStr, err := client.Get("destKey") + assert.Nil(t, err) + assert.Equal(t, "1", valStr) + }) +} + +func TestRedis_BitOpXor(t *testing.T) { + runOnRedis(t, func(client *Redis) { + err := client.Set("key1", "\xff") + assert.Nil(t, err) + err = client.Set("key2", "\x0f") + assert.Nil(t, err) + _, err = NewRedis(client.Addr, "").BitOpXor("destKey", "key1", "key2") + assert.NotNil(t, err) + val, err := client.BitOpXor("destKey", "key1", "key2") + assert.Nil(t, err) + assert.Equal(t, int64(1), val) + valStr, err := client.Get("destKey") + assert.Nil(t, err) + assert.Equal(t, "\xf0", valStr) + }) +} +func TestRedis_BitPos(t *testing.T) { + runOnRedis(t, func(client *Redis) { + //11111111 11110000 00000000 + err := client.Set("key", "\xff\xf0\x00") + assert.Nil(t, err) + + _, err = NewRedis(client.Addr, "").BitPos("key", 0, 0, -1) + assert.NotNil(t, err) + val, err := client.BitPos("key", 0, 0, 2) + assert.Nil(t, err) + assert.Equal(t, int64(12), val) + + val, err = client.BitPos("key", 1, 0, 2) + assert.Nil(t, err) + assert.Equal(t, int64(0), val) + + val, err = client.BitPos("key", 0, 1, 2) + assert.Nil(t, err) + assert.Equal(t, int64(12), val) + + val, err = client.BitPos("key", 1, 1, 2) + assert.Nil(t, err) + assert.Equal(t, int64(8), val) + + val, err = client.BitPos("key", 1, 2, 2) + assert.Nil(t, err) + assert.Equal(t, int64(-1), val) + + }) +} + func TestRedis_Persist(t *testing.T) { runOnRedis(t, func(client *Redis) { _, err := NewRedis(client.Addr, "").Persist("key")