feat(bloom): bloom support Ctx API (#3089)
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package bloom
|
package bloom
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@@ -8,16 +9,15 @@ import (
|
|||||||
"github.com/zeromicro/go-zero/core/stores/redis"
|
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
// for detailed error rate table, see http://pages.cs.wisc.edu/~cao/papers/summary-cache/node8.html
|
||||||
// for detailed error rate table, see http://pages.cs.wisc.edu/~cao/papers/summary-cache/node8.html
|
// maps as k in the error rate table
|
||||||
// maps as k in the error rate table
|
const maps = 14
|
||||||
maps = 14
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrTooLargeOffset indicates the offset is too large in bitset.
|
// ErrTooLargeOffset indicates the offset is too large in bitset.
|
||||||
ErrTooLargeOffset = errors.New("too large offset")
|
ErrTooLargeOffset = errors.New("too large offset")
|
||||||
setScript = redis.NewScript(`
|
|
||||||
|
setScript = redis.NewScript(`
|
||||||
for _, offset in ipairs(ARGV) do
|
for _, offset in ipairs(ARGV) do
|
||||||
redis.call("setbit", KEYS[1], offset, 1)
|
redis.call("setbit", KEYS[1], offset, 1)
|
||||||
end
|
end
|
||||||
@@ -40,8 +40,8 @@ type (
|
|||||||
}
|
}
|
||||||
|
|
||||||
bitSetProvider interface {
|
bitSetProvider interface {
|
||||||
check([]uint) (bool, error)
|
check(ctx context.Context, offsets []uint) (bool, error)
|
||||||
set([]uint) error
|
set(ctx context.Context, offsets []uint) error
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -60,14 +60,24 @@ func New(store *redis.Redis, key string, bits uint) *Filter {
|
|||||||
|
|
||||||
// Add adds data into f.
|
// Add adds data into f.
|
||||||
func (f *Filter) Add(data []byte) error {
|
func (f *Filter) Add(data []byte) error {
|
||||||
|
return f.AddCtx(context.Background(), data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCtx adds data into f with context.
|
||||||
|
func (f *Filter) AddCtx(ctx context.Context, data []byte) error {
|
||||||
locations := f.getLocations(data)
|
locations := f.getLocations(data)
|
||||||
return f.bitSet.set(locations)
|
return f.bitSet.set(ctx, locations)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exists checks if data is in f.
|
// Exists checks if data is in f.
|
||||||
func (f *Filter) Exists(data []byte) (bool, error) {
|
func (f *Filter) Exists(data []byte) (bool, error) {
|
||||||
|
return f.ExistsCtx(context.Background(), data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExistsCtx checks if data is in f with context.
|
||||||
|
func (f *Filter) ExistsCtx(ctx context.Context, data []byte) (bool, error) {
|
||||||
locations := f.getLocations(data)
|
locations := f.getLocations(data)
|
||||||
isSet, err := f.bitSet.check(locations)
|
isSet, err := f.bitSet.check(ctx, locations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@@ -113,13 +123,13 @@ func (r *redisBitSet) buildOffsetArgs(offsets []uint) ([]string, error) {
|
|||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *redisBitSet) check(offsets []uint) (bool, error) {
|
func (r *redisBitSet) check(ctx context.Context, offsets []uint) (bool, error) {
|
||||||
args, err := r.buildOffsetArgs(offsets)
|
args, err := r.buildOffsetArgs(offsets)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := r.store.ScriptRun(testScript, []string{r.key}, args)
|
resp, err := r.store.ScriptRunCtx(ctx, testScript, []string{r.key}, args)
|
||||||
if err == redis.Nil {
|
if err == redis.Nil {
|
||||||
return false, nil
|
return false, nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@@ -134,22 +144,24 @@ func (r *redisBitSet) check(offsets []uint) (bool, error) {
|
|||||||
return exists == 1, nil
|
return exists == 1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// del only use for testing.
|
||||||
func (r *redisBitSet) del() error {
|
func (r *redisBitSet) del() error {
|
||||||
_, err := r.store.Del(r.key)
|
_, err := r.store.Del(r.key)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// expire only use for testing.
|
||||||
func (r *redisBitSet) expire(seconds int) error {
|
func (r *redisBitSet) expire(seconds int) error {
|
||||||
return r.store.Expire(r.key, seconds)
|
return r.store.Expire(r.key, seconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *redisBitSet) set(offsets []uint) error {
|
func (r *redisBitSet) set(ctx context.Context, offsets []uint) error {
|
||||||
args, err := r.buildOffsetArgs(offsets)
|
args, err := r.buildOffsetArgs(offsets)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = r.store.ScriptRun(setScript, []string{r.key}, args)
|
_, err = r.store.ScriptRunCtx(ctx, setScript, []string{r.key}, args)
|
||||||
if err == redis.Nil {
|
if err == redis.Nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package bloom
|
package bloom
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -10,20 +11,21 @@ import (
|
|||||||
|
|
||||||
func TestRedisBitSet_New_Set_Test(t *testing.T) {
|
func TestRedisBitSet_New_Set_Test(t *testing.T) {
|
||||||
store := redistest.CreateRedis(t)
|
store := redistest.CreateRedis(t)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
bitSet := newRedisBitSet(store, "test_key", 1024)
|
bitSet := newRedisBitSet(store, "test_key", 1024)
|
||||||
isSetBefore, err := bitSet.check([]uint{0})
|
isSetBefore, err := bitSet.check(ctx, []uint{0})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if isSetBefore {
|
if isSetBefore {
|
||||||
t.Fatal("Bit should not be set")
|
t.Fatal("Bit should not be set")
|
||||||
}
|
}
|
||||||
err = bitSet.set([]uint{512})
|
err = bitSet.set(ctx, []uint{512})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
isSetAfter, err := bitSet.check([]uint{512})
|
isSetAfter, err := bitSet.check(ctx, []uint{512})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -66,33 +68,35 @@ func TestFilter_Exists(t *testing.T) {
|
|||||||
|
|
||||||
func TestRedisBitSet_check(t *testing.T) {
|
func TestRedisBitSet_check(t *testing.T) {
|
||||||
store, clean := redistest.CreateRedisWithClean(t)
|
store, clean := redistest.CreateRedisWithClean(t)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
rbs := newRedisBitSet(store, "test", 0)
|
rbs := newRedisBitSet(store, "test", 0)
|
||||||
assert.Error(t, rbs.set([]uint{0, 1, 2}))
|
assert.Error(t, rbs.set(ctx, []uint{0, 1, 2}))
|
||||||
_, err := rbs.check([]uint{0, 1, 2})
|
_, err := rbs.check(ctx, []uint{0, 1, 2})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
rbs = newRedisBitSet(store, "test", 64)
|
rbs = newRedisBitSet(store, "test", 64)
|
||||||
_, err = rbs.check([]uint{0, 1, 2})
|
_, err = rbs.check(ctx, []uint{0, 1, 2})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
clean()
|
clean()
|
||||||
rbs = newRedisBitSet(store, "test", 64)
|
rbs = newRedisBitSet(store, "test", 64)
|
||||||
_, err = rbs.check([]uint{0, 1, 2})
|
_, err = rbs.check(ctx, []uint{0, 1, 2})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRedisBitSet_set(t *testing.T) {
|
func TestRedisBitSet_set(t *testing.T) {
|
||||||
logx.Disable()
|
logx.Disable()
|
||||||
store, clean := redistest.CreateRedisWithClean(t)
|
store, clean := redistest.CreateRedisWithClean(t)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
rbs := newRedisBitSet(store, "test", 0)
|
rbs := newRedisBitSet(store, "test", 0)
|
||||||
assert.Error(t, rbs.set([]uint{0, 1, 2}))
|
assert.Error(t, rbs.set(ctx, []uint{0, 1, 2}))
|
||||||
|
|
||||||
rbs = newRedisBitSet(store, "test", 64)
|
rbs = newRedisBitSet(store, "test", 64)
|
||||||
assert.NoError(t, rbs.set([]uint{0, 1, 2}))
|
assert.NoError(t, rbs.set(ctx, []uint{0, 1, 2}))
|
||||||
|
|
||||||
clean()
|
clean()
|
||||||
rbs = newRedisBitSet(store, "test", 64)
|
rbs = newRedisBitSet(store, "test", 64)
|
||||||
assert.Error(t, rbs.set([]uint{0, 1, 2}))
|
assert.Error(t, rbs.set(ctx, []uint{0, 1, 2}))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user