initial import
This commit is contained in:
5
core/stores/kv/config.go
Normal file
5
core/stores/kv/config.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package kv
|
||||
|
||||
import "zero/core/stores/internal"
|
||||
|
||||
type KvConf = internal.ClusterConf
|
||||
653
core/stores/kv/store.go
Normal file
653
core/stores/kv/store.go
Normal file
@@ -0,0 +1,653 @@
|
||||
package kv
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
|
||||
"zero/core/errorx"
|
||||
"zero/core/hash"
|
||||
"zero/core/stores/internal"
|
||||
"zero/core/stores/redis"
|
||||
)
|
||||
|
||||
var ErrNoRedisNode = errors.New("no redis node")
|
||||
|
||||
type (
|
||||
Store interface {
|
||||
Del(keys ...string) (int, error)
|
||||
Eval(script string, key string, args ...interface{}) (interface{}, error)
|
||||
Exists(key string) (bool, error)
|
||||
Expire(key string, seconds int) error
|
||||
Expireat(key string, expireTime int64) error
|
||||
Get(key string) (string, error)
|
||||
Hdel(key, field string) (bool, error)
|
||||
Hexists(key, field string) (bool, error)
|
||||
Hget(key, field string) (string, error)
|
||||
Hgetall(key string) (map[string]string, error)
|
||||
Hincrby(key, field string, increment int) (int, error)
|
||||
Hkeys(key string) ([]string, error)
|
||||
Hlen(key string) (int, error)
|
||||
Hmget(key string, fields ...string) ([]string, error)
|
||||
Hset(key, field, value string) error
|
||||
Hsetnx(key, field, value string) (bool, error)
|
||||
Hmset(key string, fieldsAndValues map[string]string) error
|
||||
Hvals(key string) ([]string, error)
|
||||
Incr(key string) (int64, error)
|
||||
Incrby(key string, increment int64) (int64, error)
|
||||
Llen(key string) (int, error)
|
||||
Lpop(key string) (string, error)
|
||||
Lpush(key string, values ...interface{}) (int, error)
|
||||
Lrange(key string, start int, stop int) ([]string, error)
|
||||
Lrem(key string, count int, value string) (int, error)
|
||||
Persist(key string) (bool, error)
|
||||
Pfadd(key string, values ...interface{}) (bool, error)
|
||||
Pfcount(key string) (int64, error)
|
||||
Rpush(key string, values ...interface{}) (int, error)
|
||||
Sadd(key string, values ...interface{}) (int, error)
|
||||
Scard(key string) (int64, error)
|
||||
Set(key string, value string) error
|
||||
Setex(key, value string, seconds int) error
|
||||
Setnx(key, value string) (bool, error)
|
||||
SetnxEx(key, value string, seconds int) (bool, error)
|
||||
Sismember(key string, value interface{}) (bool, error)
|
||||
Smembers(key string) ([]string, error)
|
||||
Spop(key string) (string, error)
|
||||
Srandmember(key string, count int) ([]string, error)
|
||||
Srem(key string, values ...interface{}) (int, error)
|
||||
Sscan(key string, cursor uint64, match string, count int64) (keys []string, cur uint64, err error)
|
||||
Ttl(key string) (int, error)
|
||||
Zadd(key string, score int64, value string) (bool, error)
|
||||
Zadds(key string, ps ...redis.Pair) (int64, error)
|
||||
Zcard(key string) (int, error)
|
||||
Zcount(key string, start, stop int64) (int, error)
|
||||
Zincrby(key string, increment int64, field string) (int64, error)
|
||||
Zrange(key string, start, stop int64) ([]string, error)
|
||||
ZrangeWithScores(key string, start, stop int64) ([]redis.Pair, error)
|
||||
ZrangebyscoreWithScores(key string, start, stop int64) ([]redis.Pair, error)
|
||||
ZrangebyscoreWithScoresAndLimit(key string, start, stop int64, page, size int) ([]redis.Pair, error)
|
||||
Zrank(key, field string) (int64, error)
|
||||
Zrem(key string, values ...interface{}) (int, error)
|
||||
Zremrangebyrank(key string, start, stop int64) (int, error)
|
||||
Zremrangebyscore(key string, start, stop int64) (int, error)
|
||||
Zrevrange(key string, start, stop int64) ([]string, error)
|
||||
ZrevrangebyscoreWithScores(key string, start, stop int64) ([]redis.Pair, error)
|
||||
ZrevrangebyscoreWithScoresAndLimit(key string, start, stop int64, page, size int) ([]redis.Pair, error)
|
||||
Zscore(key string, value string) (int64, error)
|
||||
}
|
||||
|
||||
clusterStore struct {
|
||||
dispatcher *hash.ConsistentHash
|
||||
}
|
||||
)
|
||||
|
||||
func NewStore(c KvConf) Store {
|
||||
if len(c) == 0 || internal.TotalWeights(c) <= 0 {
|
||||
log.Fatal("no cache nodes")
|
||||
}
|
||||
|
||||
// even if only one node, we chose to use consistent hash,
|
||||
// because Store and redis.Redis has different methods.
|
||||
dispatcher := hash.NewConsistentHash()
|
||||
for _, node := range c {
|
||||
cn := node.NewRedis()
|
||||
dispatcher.AddWithWeight(cn, node.Weight)
|
||||
}
|
||||
|
||||
return clusterStore{
|
||||
dispatcher: dispatcher,
|
||||
}
|
||||
}
|
||||
|
||||
func (cs clusterStore) Del(keys ...string) (int, error) {
|
||||
var val int
|
||||
var be errorx.BatchError
|
||||
|
||||
for _, key := range keys {
|
||||
node, e := cs.getRedis(key)
|
||||
if e != nil {
|
||||
be.Add(e)
|
||||
continue
|
||||
}
|
||||
|
||||
if v, e := node.Del(key); e != nil {
|
||||
be.Add(e)
|
||||
} else {
|
||||
val += v
|
||||
}
|
||||
}
|
||||
|
||||
return val, be.Err()
|
||||
}
|
||||
|
||||
func (cs clusterStore) Eval(script string, key string, args ...interface{}) (interface{}, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node.Eval(script, []string{key}, args...)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Exists(key string) (bool, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return node.Exists(key)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Expire(key string, seconds int) error {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return node.Expire(key, seconds)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Expireat(key string, expireTime int64) error {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return node.Expireat(key, expireTime)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Get(key string) (string, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return node.Get(key)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Hdel(key, field string) (bool, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return node.Hdel(key, field)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Hexists(key, field string) (bool, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return node.Hexists(key, field)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Hget(key, field string) (string, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return node.Hget(key, field)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Hgetall(key string) (map[string]string, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node.Hgetall(key)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Hincrby(key, field string, increment int) (int, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Hincrby(key, field, increment)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Hkeys(key string) ([]string, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node.Hkeys(key)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Hlen(key string) (int, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Hlen(key)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Hmget(key string, fields ...string) ([]string, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node.Hmget(key, fields...)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Hset(key, field, value string) error {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return node.Hset(key, field, value)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Hsetnx(key, field, value string) (bool, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return node.Hsetnx(key, field, value)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Hmset(key string, fieldsAndValues map[string]string) error {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return node.Hmset(key, fieldsAndValues)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Hvals(key string) ([]string, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node.Hvals(key)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Incr(key string) (int64, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Incr(key)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Incrby(key string, increment int64) (int64, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Incrby(key, increment)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Llen(key string) (int, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Llen(key)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Lpop(key string) (string, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return node.Lpop(key)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Lpush(key string, values ...interface{}) (int, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Lpush(key, values...)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Lrange(key string, start int, stop int) ([]string, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node.Lrange(key, start, stop)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Lrem(key string, count int, value string) (int, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Lrem(key, count, value)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Persist(key string) (bool, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return node.Persist(key)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Pfadd(key string, values ...interface{}) (bool, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return node.Pfadd(key, values...)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Pfcount(key string) (int64, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Pfcount(key)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Rpush(key string, values ...interface{}) (int, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Rpush(key, values...)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Sadd(key string, values ...interface{}) (int, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Sadd(key, values...)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Scard(key string) (int64, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Scard(key)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Set(key string, value string) error {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return node.Set(key, value)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Setex(key, value string, seconds int) error {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return node.Setex(key, value, seconds)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Setnx(key, value string) (bool, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return node.Setnx(key, value)
|
||||
}
|
||||
|
||||
func (cs clusterStore) SetnxEx(key, value string, seconds int) (bool, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return node.SetnxEx(key, value, seconds)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Sismember(key string, value interface{}) (bool, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return node.Sismember(key, value)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Smembers(key string) ([]string, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node.Smembers(key)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Spop(key string) (string, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return node.Spop(key)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Srandmember(key string, count int) ([]string, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node.Srandmember(key, count)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Srem(key string, values ...interface{}) (int, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Srem(key, values...)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Sscan(key string, cursor uint64, match string, count int64) (
|
||||
keys []string, cur uint64, err error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return node.Sscan(key, cursor, match, count)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Ttl(key string) (int, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Ttl(key)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Zadd(key string, score int64, value string) (bool, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return node.Zadd(key, score, value)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Zadds(key string, ps ...redis.Pair) (int64, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Zadds(key, ps...)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Zcard(key string) (int, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Zcard(key)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Zcount(key string, start, stop int64) (int, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Zcount(key, start, stop)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Zincrby(key string, increment int64, field string) (int64, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Zincrby(key, increment, field)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Zrank(key, field string) (int64, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Zrank(key, field)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Zrange(key string, start, stop int64) ([]string, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node.Zrange(key, start, stop)
|
||||
}
|
||||
|
||||
func (cs clusterStore) ZrangeWithScores(key string, start, stop int64) ([]redis.Pair, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node.ZrangeWithScores(key, start, stop)
|
||||
}
|
||||
|
||||
func (cs clusterStore) ZrangebyscoreWithScores(key string, start, stop int64) ([]redis.Pair, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node.ZrangebyscoreWithScores(key, start, stop)
|
||||
}
|
||||
|
||||
func (cs clusterStore) ZrangebyscoreWithScoresAndLimit(key string, start, stop int64, page, size int) (
|
||||
[]redis.Pair, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node.ZrangebyscoreWithScoresAndLimit(key, start, stop, page, size)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Zrem(key string, values ...interface{}) (int, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Zrem(key, values...)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Zremrangebyrank(key string, start, stop int64) (int, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Zremrangebyrank(key, start, stop)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Zremrangebyscore(key string, start, stop int64) (int, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Zremrangebyscore(key, start, stop)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Zrevrange(key string, start, stop int64) ([]string, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node.Zrevrange(key, start, stop)
|
||||
}
|
||||
|
||||
func (cs clusterStore) ZrevrangebyscoreWithScores(key string, start, stop int64) ([]redis.Pair, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node.ZrevrangebyscoreWithScores(key, start, stop)
|
||||
}
|
||||
|
||||
func (cs clusterStore) ZrevrangebyscoreWithScoresAndLimit(key string, start, stop int64, page, size int) (
|
||||
[]redis.Pair, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node.ZrevrangebyscoreWithScoresAndLimit(key, start, stop, page, size)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Zscore(key string, value string) (int64, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return node.Zscore(key, value)
|
||||
}
|
||||
|
||||
func (cs clusterStore) getRedis(key string) (*redis.Redis, error) {
|
||||
if val, ok := cs.dispatcher.Get(key); !ok {
|
||||
return nil, ErrNoRedisNode
|
||||
} else {
|
||||
return val.(*redis.Redis), nil
|
||||
}
|
||||
}
|
||||
498
core/stores/kv/store_test.go
Normal file
498
core/stores/kv/store_test.go
Normal file
@@ -0,0 +1,498 @@
|
||||
package kv
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"zero/core/stores/internal"
|
||||
"zero/core/stores/redis"
|
||||
"zero/core/stringx"
|
||||
|
||||
"github.com/alicebob/miniredis"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var s1, _ = miniredis.Run()
|
||||
var s2, _ = miniredis.Run()
|
||||
|
||||
func TestRedis_Exists(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
ok, err := client.Exists("a")
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, ok)
|
||||
assert.Nil(t, client.Set("a", "b"))
|
||||
ok, err = client.Exists("a")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_Eval(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
_, err := client.Eval(`redis.call("EXISTS", KEYS[1])`, "notexist")
|
||||
assert.Equal(t, redis.Nil, err)
|
||||
err = client.Set("key1", "value1")
|
||||
assert.Nil(t, err)
|
||||
_, err = client.Eval(`redis.call("EXISTS", KEYS[1])`, "key1")
|
||||
assert.Equal(t, redis.Nil, err)
|
||||
val, err := client.Eval(`return redis.call("EXISTS", KEYS[1])`, "key1")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(1), val)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_Hgetall(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
assert.Nil(t, client.Hset("a", "aa", "aaa"))
|
||||
assert.Nil(t, client.Hset("a", "bb", "bbb"))
|
||||
vals, err := client.Hgetall("a")
|
||||
assert.Nil(t, err)
|
||||
assert.EqualValues(t, map[string]string{
|
||||
"aa": "aaa",
|
||||
"bb": "bbb",
|
||||
}, vals)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_Hvals(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
assert.Nil(t, client.Hset("a", "aa", "aaa"))
|
||||
assert.Nil(t, client.Hset("a", "bb", "bbb"))
|
||||
vals, err := client.Hvals("a")
|
||||
assert.Nil(t, err)
|
||||
assert.ElementsMatch(t, []string{"aaa", "bbb"}, vals)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_Hsetnx(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
assert.Nil(t, client.Hset("a", "aa", "aaa"))
|
||||
assert.Nil(t, client.Hset("a", "bb", "bbb"))
|
||||
ok, err := client.Hsetnx("a", "bb", "ccc")
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, ok)
|
||||
ok, err = client.Hsetnx("a", "dd", "ddd")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
vals, err := client.Hvals("a")
|
||||
assert.Nil(t, err)
|
||||
assert.ElementsMatch(t, []string{"aaa", "bbb", "ddd"}, vals)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_HdelHlen(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
assert.Nil(t, client.Hset("a", "aa", "aaa"))
|
||||
assert.Nil(t, client.Hset("a", "bb", "bbb"))
|
||||
num, err := client.Hlen("a")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, num)
|
||||
val, err := client.Hdel("a", "aa")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, val)
|
||||
vals, err := client.Hvals("a")
|
||||
assert.Nil(t, err)
|
||||
assert.ElementsMatch(t, []string{"bbb"}, vals)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_HIncrBy(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
val, err := client.Hincrby("key", "field", 2)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, val)
|
||||
val, err = client.Hincrby("key", "field", 3)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 5, val)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_Hkeys(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
assert.Nil(t, client.Hset("a", "aa", "aaa"))
|
||||
assert.Nil(t, client.Hset("a", "bb", "bbb"))
|
||||
vals, err := client.Hkeys("a")
|
||||
assert.Nil(t, err)
|
||||
assert.ElementsMatch(t, []string{"aa", "bb"}, vals)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_Hmget(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
assert.Nil(t, client.Hset("a", "aa", "aaa"))
|
||||
assert.Nil(t, client.Hset("a", "bb", "bbb"))
|
||||
vals, err := client.Hmget("a", "aa", "bb")
|
||||
assert.Nil(t, err)
|
||||
assert.EqualValues(t, []string{"aaa", "bbb"}, vals)
|
||||
vals, err = client.Hmget("a", "aa", "no", "bb")
|
||||
assert.Nil(t, err)
|
||||
assert.EqualValues(t, []string{"aaa", "", "bbb"}, vals)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_Hmset(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
assert.Nil(t, client.Hmset("a", map[string]string{
|
||||
"aa": "aaa",
|
||||
"bb": "bbb",
|
||||
}))
|
||||
vals, err := client.Hmget("a", "aa", "bb")
|
||||
assert.Nil(t, err)
|
||||
assert.EqualValues(t, []string{"aaa", "bbb"}, vals)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_Incr(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
val, err := client.Incr("a")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(1), val)
|
||||
val, err = client.Incr("a")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(2), val)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_IncrBy(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
val, err := client.Incrby("a", 2)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(2), val)
|
||||
val, err = client.Incrby("a", 3)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(5), val)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_List(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
val, err := client.Lpush("key", "value1", "value2")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, val)
|
||||
val, err = client.Rpush("key", "value3", "value4")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 4, val)
|
||||
val, err = client.Llen("key")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 4, val)
|
||||
vals, err := client.Lrange("key", 0, 10)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualValues(t, []string{"value2", "value1", "value3", "value4"}, vals)
|
||||
v, err := client.Lpop("key")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "value2", v)
|
||||
val, err = client.Lpush("key", "value1", "value2")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 5, val)
|
||||
val, err = client.Rpush("key", "value3", "value3")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 7, val)
|
||||
n, err := client.Lrem("key", 2, "value1")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, n)
|
||||
vals, err = client.Lrange("key", 0, 10)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualValues(t, []string{"value2", "value3", "value4", "value3", "value3"}, vals)
|
||||
n, err = client.Lrem("key", -2, "value3")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, n)
|
||||
vals, err = client.Lrange("key", 0, 10)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualValues(t, []string{"value2", "value3", "value4"}, vals)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_Persist(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
ok, err := client.Persist("key")
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, ok)
|
||||
err = client.Set("key", "value")
|
||||
assert.Nil(t, err)
|
||||
ok, err = client.Persist("key")
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, ok)
|
||||
err = client.Expire("key", 5)
|
||||
ok, err = client.Persist("key")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
err = client.Expireat("key", time.Now().Unix()+5)
|
||||
ok, err = client.Persist("key")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_Sscan(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
key := "list"
|
||||
var list []string
|
||||
for i := 0; i < 1550; i++ {
|
||||
list = append(list, stringx.Randn(i))
|
||||
}
|
||||
lens, err := client.Sadd(key, list)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, lens, 1550)
|
||||
|
||||
var cursor uint64 = 0
|
||||
sum := 0
|
||||
for {
|
||||
keys, next, err := client.Sscan(key, cursor, "", 100)
|
||||
assert.Nil(t, err)
|
||||
sum += len(keys)
|
||||
if next == 0 {
|
||||
break
|
||||
}
|
||||
cursor = next
|
||||
}
|
||||
|
||||
assert.Equal(t, sum, 1550)
|
||||
_, err = client.Del(key)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_Set(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
num, err := client.Sadd("key", 1, 2, 3, 4)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 4, num)
|
||||
val, err := client.Scard("key")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(4), val)
|
||||
ok, err := client.Sismember("key", 2)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
num, err = client.Srem("key", 3, 4)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, num)
|
||||
vals, err := client.Smembers("key")
|
||||
assert.Nil(t, err)
|
||||
assert.ElementsMatch(t, []string{"1", "2"}, vals)
|
||||
members, err := client.Srandmember("key", 1)
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, members, 1)
|
||||
assert.Contains(t, []string{"1", "2"}, members[0])
|
||||
member, err := client.Spop("key")
|
||||
assert.Nil(t, err)
|
||||
assert.Contains(t, []string{"1", "2"}, member)
|
||||
vals, err = client.Smembers("key")
|
||||
assert.Nil(t, err)
|
||||
assert.NotContains(t, vals, member)
|
||||
num, err = client.Sadd("key1", 1, 2, 3, 4)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 4, num)
|
||||
num, err = client.Sadd("key2", 2, 3, 4, 5)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 4, num)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_SetGetDel(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
err := client.Set("hello", "world")
|
||||
assert.Nil(t, err)
|
||||
val, err := client.Get("hello")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "world", val)
|
||||
ret, err := client.Del("hello")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 1, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_SetExNx(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
err := client.Setex("hello", "world", 5)
|
||||
assert.Nil(t, err)
|
||||
ok, err := client.Setnx("hello", "newworld")
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, ok)
|
||||
ok, err = client.Setnx("newhello", "newworld")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
val, err := client.Get("hello")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "world", val)
|
||||
val, err = client.Get("newhello")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "newworld", val)
|
||||
ttl, err := client.Ttl("hello")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ttl > 0)
|
||||
ok, err = client.SetnxEx("newhello", "newworld", 5)
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, ok)
|
||||
num, err := client.Del("newhello")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 1, num)
|
||||
ok, err = client.SetnxEx("newhello", "newworld", 5)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
val, err = client.Get("newhello")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "newworld", val)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_SetGetDelHashField(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
err := client.Hset("key", "field", "value")
|
||||
assert.Nil(t, err)
|
||||
val, err := client.Hget("key", "field")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "value", val)
|
||||
ok, err := client.Hexists("key", "field")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
ret, err := client.Hdel("key", "field")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ret)
|
||||
ok, err = client.Hexists("key", "field")
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, ok)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis_SortedSet(t *testing.T) {
|
||||
runOnCluster(t, func(client Store) {
|
||||
ok, err := client.Zadd("key", 1, "value1")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
ok, err = client.Zadd("key", 2, "value1")
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, ok)
|
||||
val, err := client.Zscore("key", "value1")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(2), val)
|
||||
val, err = client.Zincrby("key", 3, "value1")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(5), val)
|
||||
val, err = client.Zscore("key", "value1")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(5), val)
|
||||
ok, err = client.Zadd("key", 6, "value2")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
ok, err = client.Zadd("key", 7, "value3")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
rank, err := client.Zrank("key", "value2")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(1), rank)
|
||||
rank, err = client.Zrank("key", "value4")
|
||||
assert.Equal(t, redis.Nil, err)
|
||||
num, err := client.Zrem("key", "value2", "value3")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, num)
|
||||
ok, err = client.Zadd("key", 6, "value2")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
ok, err = client.Zadd("key", 7, "value3")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
ok, err = client.Zadd("key", 8, "value4")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
num, err = client.Zremrangebyscore("key", 6, 7)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, num)
|
||||
ok, err = client.Zadd("key", 6, "value2")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
ok, err = client.Zadd("key", 7, "value3")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
num, err = client.Zcount("key", 6, 7)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, num)
|
||||
num, err = client.Zremrangebyrank("key", 1, 2)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, num)
|
||||
card, err := client.Zcard("key")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, card)
|
||||
vals, err := client.Zrange("key", 0, -1)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualValues(t, []string{"value1", "value4"}, vals)
|
||||
vals, err = client.Zrevrange("key", 0, -1)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualValues(t, []string{"value4", "value1"}, vals)
|
||||
pairs, err := client.ZrangeWithScores("key", 0, -1)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualValues(t, []redis.Pair{
|
||||
{
|
||||
Key: "value1",
|
||||
Score: 5,
|
||||
},
|
||||
{
|
||||
Key: "value4",
|
||||
Score: 8,
|
||||
},
|
||||
}, pairs)
|
||||
pairs, err = client.ZrangebyscoreWithScores("key", 5, 8)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualValues(t, []redis.Pair{
|
||||
{
|
||||
Key: "value1",
|
||||
Score: 5,
|
||||
},
|
||||
{
|
||||
Key: "value4",
|
||||
Score: 8,
|
||||
},
|
||||
}, pairs)
|
||||
pairs, err = client.ZrangebyscoreWithScoresAndLimit("key", 5, 8, 1, 1)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualValues(t, []redis.Pair{
|
||||
{
|
||||
Key: "value4",
|
||||
Score: 8,
|
||||
},
|
||||
}, pairs)
|
||||
pairs, err = client.ZrevrangebyscoreWithScores("key", 5, 8)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualValues(t, []redis.Pair{
|
||||
{
|
||||
Key: "value4",
|
||||
Score: 8,
|
||||
},
|
||||
{
|
||||
Key: "value1",
|
||||
Score: 5,
|
||||
},
|
||||
}, pairs)
|
||||
pairs, err = client.ZrevrangebyscoreWithScoresAndLimit("key", 5, 8, 1, 1)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualValues(t, []redis.Pair{
|
||||
{
|
||||
Key: "value1",
|
||||
Score: 5,
|
||||
},
|
||||
}, pairs)
|
||||
})
|
||||
}
|
||||
|
||||
func runOnCluster(t *testing.T, fn func(cluster Store)) {
|
||||
s1.FlushAll()
|
||||
s2.FlushAll()
|
||||
|
||||
store := NewStore([]internal.NodeConf{
|
||||
{
|
||||
RedisConf: redis.RedisConf{
|
||||
Host: s1.Addr(),
|
||||
Type: redis.NodeType,
|
||||
},
|
||||
Weight: 100,
|
||||
},
|
||||
{
|
||||
RedisConf: redis.RedisConf{
|
||||
Host: s2.Addr(),
|
||||
Type: redis.NodeType,
|
||||
},
|
||||
Weight: 100,
|
||||
},
|
||||
})
|
||||
|
||||
fn(store)
|
||||
}
|
||||
Reference in New Issue
Block a user