1
0
mirror of https://github.com/charlienet/go-mixed.git synced 2025-07-18 00:22:41 +08:00
Files
go-mixed/bloom/redis_store.go

101 lines
1.9 KiB
Go

package bloom
import (
"context"
"errors"
"strconv"
"sync"
"time"
_ "embed"
"github.com/charlienet/go-mixed/redis"
)
//go:embed bloom.lua
var redis_bloom_function string
var once sync.Once
var ErrTooLargeOffset = errors.New("超出最大偏移量")
var _ bitStore = &redisBitSet{}
// 使用Redis存储位图
type redisBitSet struct {
store redis.Client
key string
bits uint
}
func newRedisStore(store redis.Client, key string, bits uint) *redisBitSet {
once.Do(func() { store.LoadFunction(redis_bloom_function) })
return &redisBitSet{
store: store,
key: key,
bits: bits,
}
}
func (s *redisBitSet) Set(ctx context.Context, offsets ...uint) error {
args, err := s.buildOffsetArgs(offsets)
if err != nil {
return err
}
_, err = s.store.FCall(ctx, "set_bit", []string{s.key}, args...).Result()
//底层使用的是go-redis,redis.Nil表示操作的key不存在
//需要针对key不存在的情况特殊判断
if err == redis.Nil {
return nil
} else if err != nil {
return err
}
return nil
}
func (s *redisBitSet) Test(offsets ...uint) (bool, error) {
args, err := s.buildOffsetArgs(offsets)
if err != nil {
return false, err
}
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*500)
defer cancel()
resp, err := s.store.FCall(ctx, "test_bit", []string{s.key}, args...).Result()
// key 不存在,表示还未存放任何数据
if err == redis.Nil {
return false, nil
} else if err != nil {
return false, err
}
exists, ok := resp.(int64)
if !ok {
return false, nil
}
return exists == 1, nil
}
func (s *redisBitSet) Clear() {
}
func (r *redisBitSet) buildOffsetArgs(offsets []uint) ([]any, error) {
args := make([]any, 0, len(offsets))
for _, offset := range offsets {
if offset >= r.bits {
return nil, ErrTooLargeOffset
}
args = append(args, strconv.FormatUint(uint64(offset), 10))
}
return args, nil
}