Jelajahi Sumber

add redis bitmap command (#490)

Co-authored-by: zhoudeyu <zhoudeyu@xiaoheiban.cn>
Zcc、 3 tahun lalu
induk
melakukan
fdeacfc89f
2 mengubah file dengan 172 tambahan dan 0 penghapusan
  1. 75 0
      core/stores/redis/redis.go
  2. 97 0
      core/stores/redis/redis_test.go

+ 75 - 0
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) {

+ 97 - 0
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")