2023-04-16 00:50:36 +08:00
|
|
|
|
package api
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"context"
|
|
|
|
|
|
"mayfly-go/internal/redis/api/form"
|
|
|
|
|
|
"mayfly-go/internal/redis/api/vo"
|
2023-10-27 17:41:45 +08:00
|
|
|
|
"mayfly-go/internal/redis/rdm"
|
2023-04-16 00:50:36 +08:00
|
|
|
|
"mayfly-go/pkg/biz"
|
|
|
|
|
|
"mayfly-go/pkg/req"
|
2023-10-12 12:14:56 +08:00
|
|
|
|
"mayfly-go/pkg/utils/collx"
|
2023-04-16 00:50:36 +08:00
|
|
|
|
"strings"
|
|
|
|
|
|
"sync"
|
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// scan获取redis的key列表信息
|
2023-08-28 17:25:59 +08:00
|
|
|
|
func (r *Redis) ScanKeys(rc *req.Ctx) {
|
2023-10-27 17:41:45 +08:00
|
|
|
|
ri := r.getRedisConn(rc)
|
2023-04-16 00:50:36 +08:00
|
|
|
|
|
2024-02-24 16:30:29 +08:00
|
|
|
|
form := req.BindJsonAndValid(rc, new(form.RedisScanForm))
|
2023-04-16 00:50:36 +08:00
|
|
|
|
|
|
|
|
|
|
cmd := ri.GetCmdable()
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
2023-08-28 17:25:59 +08:00
|
|
|
|
keys := make([]string, 0)
|
2023-04-16 00:50:36 +08:00
|
|
|
|
var cursorRes map[string]uint64 = make(map[string]uint64)
|
|
|
|
|
|
|
2023-08-28 17:25:59 +08:00
|
|
|
|
size, _ := cmd.DBSize(ctx).Result()
|
|
|
|
|
|
|
|
|
|
|
|
if form.Match != "" && !strings.ContainsAny(form.Match, "*") {
|
|
|
|
|
|
// 精确匹配, 判断是否存在
|
|
|
|
|
|
res, err := cmd.Exists(ctx, form.Match).Result()
|
|
|
|
|
|
if err == nil && res != 0 {
|
|
|
|
|
|
keys = append(keys, form.Match)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
rc.ResData = &vo.Keys{Cursor: cursorRes, Keys: keys, DbSize: size}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 通配符或全匹配
|
2023-04-16 00:50:36 +08:00
|
|
|
|
mode := ri.Info.Mode
|
2023-10-27 17:41:45 +08:00
|
|
|
|
if mode == "" || mode == rdm.StandaloneMode || mode == rdm.SentinelMode {
|
2023-04-16 00:50:36 +08:00
|
|
|
|
redisAddr := ri.Cli.Options().Addr
|
2023-08-28 17:25:59 +08:00
|
|
|
|
cursorRes[redisAddr] = form.Cursor[redisAddr]
|
|
|
|
|
|
for {
|
2023-10-26 17:15:49 +08:00
|
|
|
|
ks, cursor, err := ri.Scan(cursorRes[redisAddr], form.Match, form.Count)
|
|
|
|
|
|
biz.ErrIsNil(err)
|
2023-08-28 17:25:59 +08:00
|
|
|
|
cursorRes[redisAddr] = cursor
|
|
|
|
|
|
if len(ks) > 0 {
|
|
|
|
|
|
// 返回了数据则追加总集合中
|
|
|
|
|
|
keys = append(keys, ks...)
|
|
|
|
|
|
}
|
|
|
|
|
|
// 匹配的数量满足用户需求退出
|
|
|
|
|
|
if int32(len(keys)) >= int32(form.Count) {
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
// 匹配到最后退出
|
|
|
|
|
|
if cursor == 0 {
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-10-27 17:41:45 +08:00
|
|
|
|
} else if mode == rdm.ClusterMode {
|
2023-08-28 17:25:59 +08:00
|
|
|
|
mu := &sync.Mutex{}
|
|
|
|
|
|
// 遍历所有master节点,并执行scan命令,合并keys
|
|
|
|
|
|
ri.ClusterCli.ForEachMaster(ctx, func(ctx context.Context, client *redis.Client) error {
|
|
|
|
|
|
redisAddr := client.Options().Addr
|
|
|
|
|
|
nowCursor := form.Cursor[redisAddr]
|
2023-04-16 00:50:36 +08:00
|
|
|
|
for {
|
2023-08-28 17:25:59 +08:00
|
|
|
|
ks, cursor, _ := client.Scan(ctx, nowCursor, form.Match, form.Count).Result()
|
|
|
|
|
|
// 遍历节点的内部回调函数使用异步调用,如不加锁会导致集合并发错误
|
|
|
|
|
|
mu.Lock()
|
2023-04-16 00:50:36 +08:00
|
|
|
|
cursorRes[redisAddr] = cursor
|
2023-08-28 17:25:59 +08:00
|
|
|
|
nowCursor = cursor
|
2023-04-16 00:50:36 +08:00
|
|
|
|
if len(ks) > 0 {
|
|
|
|
|
|
// 返回了数据则追加总集合中
|
|
|
|
|
|
keys = append(keys, ks...)
|
|
|
|
|
|
}
|
2023-08-28 17:25:59 +08:00
|
|
|
|
mu.Unlock()
|
2023-04-16 00:50:36 +08:00
|
|
|
|
// 匹配的数量满足用户需求退出
|
|
|
|
|
|
if int32(len(keys)) >= int32(form.Count) {
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
// 匹配到最后退出
|
|
|
|
|
|
if cursor == 0 {
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-08-28 17:25:59 +08:00
|
|
|
|
return nil
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2023-04-16 00:50:36 +08:00
|
|
|
|
|
2023-08-28 17:25:59 +08:00
|
|
|
|
rc.ResData = &vo.Keys{Cursor: cursorRes, Keys: keys, DbSize: size}
|
|
|
|
|
|
}
|
2023-04-16 00:50:36 +08:00
|
|
|
|
|
2023-08-28 17:25:59 +08:00
|
|
|
|
func (r *Redis) KeyInfo(rc *req.Ctx) {
|
2023-10-27 17:41:45 +08:00
|
|
|
|
ri, key := r.checkKeyAndGetRedisConn(rc)
|
2023-08-28 17:25:59 +08:00
|
|
|
|
cmd := ri.GetCmdable()
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
ttl, err := cmd.TTL(ctx, key).Result()
|
|
|
|
|
|
biz.ErrIsNilAppendErr(err, "ttl失败: %s")
|
2023-04-16 00:50:36 +08:00
|
|
|
|
|
2023-08-28 17:25:59 +08:00
|
|
|
|
ttlInt := -1
|
|
|
|
|
|
if ttl != -1 {
|
|
|
|
|
|
ttlInt = int(ttl.Seconds())
|
2023-04-16 00:50:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-08-28 17:25:59 +08:00
|
|
|
|
typeRes, err := cmd.Type(ctx, key).Result()
|
|
|
|
|
|
biz.ErrIsNilAppendErr(err, "获取key type失败: %s")
|
|
|
|
|
|
|
|
|
|
|
|
rc.ResData = &vo.KeyInfo{
|
|
|
|
|
|
Key: key,
|
|
|
|
|
|
Ttl: ttlInt,
|
|
|
|
|
|
Type: typeRes,
|
|
|
|
|
|
}
|
2023-04-16 00:50:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (r *Redis) TtlKey(rc *req.Ctx) {
|
2023-10-27 17:41:45 +08:00
|
|
|
|
ri, key := r.checkKeyAndGetRedisConn(rc)
|
2023-04-16 00:50:36 +08:00
|
|
|
|
ttl, err := ri.GetCmdable().TTL(context.Background(), key).Result()
|
2023-06-15 19:18:29 +08:00
|
|
|
|
biz.ErrIsNilAppendErr(err, "ttl失败: %s")
|
2023-04-16 00:50:36 +08:00
|
|
|
|
|
|
|
|
|
|
if ttl == -1 {
|
|
|
|
|
|
rc.ResData = -1
|
|
|
|
|
|
} else {
|
|
|
|
|
|
rc.ResData = ttl.Seconds()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-11-02 12:46:21 +08:00
|
|
|
|
func (r *Redis) MemoryUsage(rc *req.Ctx) {
|
|
|
|
|
|
ri, key := r.checkKeyAndGetRedisConn(rc)
|
|
|
|
|
|
rc.ResData = ri.GetCmdable().MemoryUsage(context.Background(), key).Val()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-04-16 00:50:36 +08:00
|
|
|
|
func (r *Redis) DeleteKey(rc *req.Ctx) {
|
2023-10-27 17:41:45 +08:00
|
|
|
|
ri, key := r.checkKeyAndGetRedisConn(rc)
|
2023-10-12 12:14:56 +08:00
|
|
|
|
rc.ReqParam = collx.Kvs("redis", ri.Info, "key", key)
|
2023-04-16 00:50:36 +08:00
|
|
|
|
ri.GetCmdable().Del(context.Background(), key)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (r *Redis) RenameKey(rc *req.Ctx) {
|
2024-02-24 16:30:29 +08:00
|
|
|
|
form := req.BindJsonAndValid(rc, new(form.Rename))
|
2023-04-16 00:50:36 +08:00
|
|
|
|
|
2023-10-27 17:41:45 +08:00
|
|
|
|
ri := r.getRedisConn(rc)
|
2023-10-12 12:14:56 +08:00
|
|
|
|
rc.ReqParam = collx.Kvs("redis", ri.Info, "rename", form)
|
2023-04-16 00:50:36 +08:00
|
|
|
|
ri.GetCmdable().Rename(context.Background(), form.Key, form.NewKey)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (r *Redis) ExpireKey(rc *req.Ctx) {
|
2024-02-24 16:30:29 +08:00
|
|
|
|
form := req.BindJsonAndValid(rc, new(form.Expire))
|
2023-04-16 00:50:36 +08:00
|
|
|
|
|
2023-10-27 17:41:45 +08:00
|
|
|
|
ri := r.getRedisConn(rc)
|
2023-10-12 12:14:56 +08:00
|
|
|
|
rc.ReqParam = collx.Kvs("redis", ri.Info, "expire", form)
|
2023-04-16 00:50:36 +08:00
|
|
|
|
ri.GetCmdable().Expire(context.Background(), form.Key, time.Duration(form.Seconds)*time.Second)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 移除过期时间
|
|
|
|
|
|
func (r *Redis) PersistKey(rc *req.Ctx) {
|
2023-10-27 17:41:45 +08:00
|
|
|
|
ri, key := r.checkKeyAndGetRedisConn(rc)
|
2023-10-12 12:14:56 +08:00
|
|
|
|
rc.ReqParam = collx.Kvs("redis", ri.Info, "key", key)
|
2023-04-16 00:50:36 +08:00
|
|
|
|
ri.GetCmdable().Persist(context.Background(), key)
|
|
|
|
|
|
}
|
2023-06-15 19:18:29 +08:00
|
|
|
|
|
|
|
|
|
|
// 清空库
|
|
|
|
|
|
func (r *Redis) FlushDb(rc *req.Ctx) {
|
2023-10-27 17:41:45 +08:00
|
|
|
|
ri := r.getRedisConn(rc)
|
2023-09-09 23:34:26 +08:00
|
|
|
|
rc.ReqParam = ri.Info
|
2023-06-15 19:18:29 +08:00
|
|
|
|
ri.GetCmdable().FlushDB(context.Background())
|
|
|
|
|
|
}
|