mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-13 00:13:33 +08:00
🐛 fix(redis): 修复精确搜索无法命中命名空间
- 精确搜索识别无通配符的 Redis literal pattern - 同时查询完整 Key 与同名命名空间前缀 - 修复输入 Agent 无法显示 Agent 文件夹的问题 - 避免误匹配 AgentCapacity、AgentState 等相似前缀 - 补充 glob literal 与命名空间搜索回归测试 - 更新 Redis 精确搜索输入提示文案
This commit is contained in:
@@ -155,6 +155,46 @@ func (r *RedisClientImpl) toPhysicalPattern(pattern string) string {
|
||||
return prefix + normalized
|
||||
}
|
||||
|
||||
func redisGlobPatternLiteralKey(pattern string) (string, bool) {
|
||||
if pattern == "" {
|
||||
return "", false
|
||||
}
|
||||
|
||||
var builder strings.Builder
|
||||
for i := 0; i < len(pattern); i++ {
|
||||
char := pattern[i]
|
||||
if char == '\\' {
|
||||
if i+1 >= len(pattern) {
|
||||
return "", false
|
||||
}
|
||||
i++
|
||||
builder.WriteByte(pattern[i])
|
||||
continue
|
||||
}
|
||||
if char == '*' || char == '?' || char == '[' {
|
||||
return "", false
|
||||
}
|
||||
builder.WriteByte(char)
|
||||
}
|
||||
return builder.String(), true
|
||||
}
|
||||
|
||||
func escapeRedisGlobLiteral(value string) string {
|
||||
var builder strings.Builder
|
||||
for i := 0; i < len(value); i++ {
|
||||
char := value[i]
|
||||
if char == '*' || char == '?' || char == '[' || char == ']' || char == '\\' {
|
||||
builder.WriteByte('\\')
|
||||
}
|
||||
builder.WriteByte(char)
|
||||
}
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func redisExactSearchPattern(literalKey string) (string, string) {
|
||||
return literalKey, escapeRedisGlobLiteral(literalKey) + ":*"
|
||||
}
|
||||
|
||||
func (r *RedisClientImpl) toPhysicalKeys(keys []string) []string {
|
||||
if len(keys) == 0 {
|
||||
return nil
|
||||
@@ -367,6 +407,15 @@ func (r *RedisClientImpl) ScanKeys(pattern string, cursor uint64, count int64) (
|
||||
if pattern == "" {
|
||||
pattern = "*"
|
||||
}
|
||||
exactPhysicalKey := ""
|
||||
if literalKey, ok := redisGlobPatternLiteralKey(pattern); ok {
|
||||
exactKey, namespacePattern := redisExactSearchPattern(literalKey)
|
||||
exactPhysicalKey = r.toPhysicalKey(exactKey)
|
||||
if exactPhysicalKey == "" {
|
||||
return &RedisScanResult{Keys: []RedisKeyInfo{}, Cursor: "0"}, nil
|
||||
}
|
||||
pattern = namespacePattern
|
||||
}
|
||||
physicalPattern := r.toPhysicalPattern(pattern)
|
||||
|
||||
isSearchPattern := pattern != "*"
|
||||
@@ -393,6 +442,10 @@ func (r *RedisClientImpl) ScanKeys(pattern string, cursor uint64, count int64) (
|
||||
keys := make([]string, 0, int(targetCount))
|
||||
seen := make(map[string]struct{}, int(targetCount))
|
||||
var mu sync.Mutex
|
||||
if exactPhysicalKey != "" {
|
||||
keys = append(keys, exactPhysicalKey)
|
||||
seen[exactPhysicalKey] = struct{}{}
|
||||
}
|
||||
|
||||
err := r.clusterClient.ForEachMaster(ctx, func(nodeCtx context.Context, node *redis.Client) error {
|
||||
var nodeCursor uint64
|
||||
@@ -453,6 +506,10 @@ func (r *RedisClientImpl) ScanKeys(pattern string, cursor uint64, count int64) (
|
||||
|
||||
keys := make([]string, 0, int(targetCount))
|
||||
seen := make(map[string]struct{}, int(targetCount))
|
||||
if exactPhysicalKey != "" && currentCursor == 0 {
|
||||
keys = append(keys, exactPhysicalKey)
|
||||
seen[exactPhysicalKey] = struct{}{}
|
||||
}
|
||||
|
||||
for len(keys) < int(targetCount) {
|
||||
if time.Since(scanStartedAt) >= maxDuration {
|
||||
|
||||
Reference in New Issue
Block a user