Skip to content

feat(bitop): add support for the new bitop operations #3409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actions/run-tests/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ runs:

# Mapping of redis version to redis testing containers
declare -A redis_version_mapping=(
["8.2.x"]="8.2-M01-pre"
["8.0.x"]="8.0.2"
["7.4.x"]="rs-7.4.0-v5"
["7.2.x"]="rs-7.2.0-v17"
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ jobs:
fail-fast: false
matrix:
redis-version:
- "8.2.x" # Redis CE 8.2
- "8.0.x" # Redis CE 8.0
- "7.4.x" # Redis stack 7.4
go-version:
Expand All @@ -43,6 +44,7 @@ jobs:

# Mapping of redis version to redis testing containers
declare -A redis_version_mapping=(
["8.2.x"]="8.2-M01-pre"
["8.0.x"]="8.0.2"
["7.4.x"]="rs-7.4.0-v5"
)
Expand Down Expand Up @@ -72,6 +74,7 @@ jobs:
fail-fast: false
matrix:
redis-version:
- "8.2.x" # Redis CE 8.2
- "8.0.x" # Redis CE 8.0
- "7.4.x" # Redis stack 7.4
- "7.2.x" # Redis stack 7.2
Expand Down
32 changes: 32 additions & 0 deletions bitmap_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ type BitMapCmdable interface {
BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd
BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd
BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd
BitOpDiff(ctx context.Context, destKey string, keys ...string) *IntCmd
BitOpDiff1(ctx context.Context, destKey string, keys ...string) *IntCmd
BitOpAndOr(ctx context.Context, destKey string, keys ...string) *IntCmd
BitOpOne(ctx context.Context, destKey string, keys ...string) *IntCmd
BitOpNot(ctx context.Context, destKey string, key string) *IntCmd
BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd
BitPosSpan(ctx context.Context, key string, bit int8, start, end int64, span string) *IntCmd
Expand Down Expand Up @@ -78,22 +82,50 @@ func (c cmdable) bitOp(ctx context.Context, op, destKey string, keys ...string)
return cmd
}

// BitOpAnd creates a new bitmap in which users are members of all given bitmaps
func (c cmdable) BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd {
return c.bitOp(ctx, "and", destKey, keys...)
}

// BitOpOr creates a new bitmap in which users are member of at least one given bitmap
func (c cmdable) BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd {
return c.bitOp(ctx, "or", destKey, keys...)
}

// BitOpXor creates a new bitmap in which users are the result of XORing all given bitmaps
func (c cmdable) BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd {
return c.bitOp(ctx, "xor", destKey, keys...)
}

// BitOpNot creates a new bitmap in which users are not members of a given bitmap
func (c cmdable) BitOpNot(ctx context.Context, destKey string, key string) *IntCmd {
return c.bitOp(ctx, "not", destKey, key)
}

// BitOpDiff creates a new bitmap in which users are members of bitmap X but not of any of bitmaps Y1, Y2, …
// Introduced with Redis 8.2
func (c cmdable) BitOpDiff(ctx context.Context, destKey string, keys ...string) *IntCmd {
return c.bitOp(ctx, "diff", destKey, keys...)
}

// BitOpDiff1 creates a new bitmap in which users are members of one or more of bitmaps Y1, Y2, … but not members of bitmap X
// Introduced with Redis 8.2
func (c cmdable) BitOpDiff1(ctx context.Context, destKey string, keys ...string) *IntCmd {
return c.bitOp(ctx, "diff1", destKey, keys...)
}

// BitOpAndOr creates a new bitmap in which users are members of bitmap X and also members of one or more of bitmaps Y1, Y2, …
// Introduced with Redis 8.2
func (c cmdable) BitOpAndOr(ctx context.Context, destKey string, keys ...string) *IntCmd {
return c.bitOp(ctx, "andor", destKey, keys...)
}

// BitOpOne creates a new bitmap in which users are members of exactly one of the given bitmaps
// Introduced with Redis 8.2
func (c cmdable) BitOpOne(ctx context.Context, destKey string, keys ...string) *IntCmd {
return c.bitOp(ctx, "one", destKey, keys...)
}

// BitPos is an API before Redis version 7.0, cmd: bitpos key bit start end
// if you need the `byte | bit` parameter, please use `BitPosSpan`.
func (c cmdable) BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd {
Expand Down
9 changes: 9 additions & 0 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -5138,6 +5138,9 @@ type ClientInfo struct {
OutputListLength int // oll, output list length (replies are queued in this list when the buffer is full)
OutputMemory int // omem, output buffer memory usage
TotalMemory int // tot-mem, total memory consumed by this client in its various buffers
TotalNetIn int // tot-net-in, total network input
TotalNetOut int // tot-net-out, total network output
TotalCmds int // tot-cmds, total number of commands processed
IoThread int // io-thread id
Events string // file descriptor events (see below)
LastCmd string // cmd, last command played
Expand Down Expand Up @@ -5303,6 +5306,12 @@ func parseClientInfo(txt string) (info *ClientInfo, err error) {
info.OutputMemory, err = strconv.Atoi(val)
case "tot-mem":
info.TotalMemory, err = strconv.Atoi(val)
case "tot-net-in":
info.TotalNetIn, err = strconv.Atoi(val)
case "tot-net-out":
info.TotalNetOut, err = strconv.Atoi(val)
case "tot-cmds":
info.TotalCmds, err = strconv.Atoi(val)
case "events":
info.Events = val
case "cmd":
Expand Down
76 changes: 76 additions & 0 deletions commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1469,6 +1469,82 @@ var _ = Describe("Commands", func() {
Expect(get.Val()).To(Equal("\xf0"))
})

It("should BitOpDiff", Label("NonRedisEnterprise"), func() {
SkipBeforeRedisVersion(8.2, "BITOP DIFF is available since Redis 8.2")
set := client.Set(ctx, "key1", "\xff", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expect(set.Val()).To(Equal("OK"))

set = client.Set(ctx, "key2", "\x0f", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expect(set.Val()).To(Equal("OK"))

bitOpDiff := client.BitOpDiff(ctx, "dest", "key1", "key2")
Expect(bitOpDiff.Err()).NotTo(HaveOccurred())
Expect(bitOpDiff.Val()).To(Equal(int64(1)))

get := client.Get(ctx, "dest")
Expect(get.Err()).NotTo(HaveOccurred())
Expect(get.Val()).To(Equal("\xf0"))
})

It("should BitOpDiff1", Label("NonRedisEnterprise"), func() {
SkipBeforeRedisVersion(8.2, "BITOP DIFF is available since Redis 8.2")
set := client.Set(ctx, "key1", "\xff", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expect(set.Val()).To(Equal("OK"))

set = client.Set(ctx, "key2", "\x0f", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expect(set.Val()).To(Equal("OK"))

bitOpDiff1 := client.BitOpDiff1(ctx, "dest", "key1", "key2")
Expect(bitOpDiff1.Err()).NotTo(HaveOccurred())
Expect(bitOpDiff1.Val()).To(Equal(int64(1)))

get := client.Get(ctx, "dest")
Expect(get.Err()).NotTo(HaveOccurred())
Expect(get.Val()).To(Equal("\x00"))
})

It("should BitOpAndOr", Label("NonRedisEnterprise"), func() {
SkipBeforeRedisVersion(8.2, "BITOP ANDOR is available since Redis 8.2")
set := client.Set(ctx, "key1", "\xff", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expect(set.Val()).To(Equal("OK"))

set = client.Set(ctx, "key2", "\x0f", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expect(set.Val()).To(Equal("OK"))

bitOpAndOr := client.BitOpAndOr(ctx, "dest", "key1", "key2")
Expect(bitOpAndOr.Err()).NotTo(HaveOccurred())
Expect(bitOpAndOr.Val()).To(Equal(int64(1)))

get := client.Get(ctx, "dest")
Expect(get.Err()).NotTo(HaveOccurred())
Expect(get.Val()).To(Equal("\x0f"))
})

It("should BitOpOne", Label("NonRedisEnterprise"), func() {
SkipBeforeRedisVersion(8.2, "BITOP ONE is available since Redis 8.2")
set := client.Set(ctx, "key1", "\xff", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expect(set.Val()).To(Equal("OK"))

set = client.Set(ctx, "key2", "\x0f", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expect(set.Val()).To(Equal("OK"))

bitOpOne := client.BitOpOne(ctx, "dest", "key1", "key2")
Expect(bitOpOne.Err()).NotTo(HaveOccurred())
Expect(bitOpOne.Val()).To(Equal(int64(1)))

get := client.Get(ctx, "dest")
Expect(get.Err()).NotTo(HaveOccurred())
Expect(get.Val()).To(Equal("\xf0"))
})

It("should BitOpNot", Label("NonRedisEnterprise"), func() {
set := client.Set(ctx, "key1", "\x00", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expand Down
Loading