mirror of
https://github.com/redis/go-redis.git
synced 2025-12-02 06:22:31 +03:00
* Add search module builders and tests (#1) * Add search module builders and tests * Add tests * Use builders and Actions in more clean way * Update search_builders.go Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com> * Update search_builders.go Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com> * feat(routing): add internal request/response policy enums * feat: load the policy table in cluster client (#4) * feat: load the policy table in cluster client * Remove comments * modify Tips and command pplicy in commandInfo (#5) * centralize cluster command routing in osscluster_router.go and refactor osscluster.go (#6) * centralize cluster command routing in osscluster_router.go and refactor osscluster.go * enalbe ci on all branches * Add debug prints * Add debug prints * FIX: deal with nil policy * FIX: fixing clusterClient process * chore(osscluster): simplify switch case * wip(command): ai generated clone method for commands * feat: implement response aggregator for Redis cluster commands * feat: implement response aggregator for Redis cluster commands * fix: solve concurrency errors * fix: solve concurrency errors * return MaxRedirects settings * remove locks from getCommandPolicy * Handle MOVED errors more robustly, remove cluster reloading at exectutions, ennsure better routing * Fix: supports Process hook test * Fix: remove response aggregation for single shard commands * Add more preformant type conversion for Cmd type * Add router logic into processPipeline --------- Co-authored-by: Nedyalko Dyakov <nedyalko.dyakov@gmail.com> * remove thread debugging code * remove thread debugging code && reject commands with policy that cannot be used in pipeline * refactor processPipline and cmdType enum * remove FDescribe from cluster tests * Add tests * fix aggregation test * fix mget test * fix mget test * remove aggregateKeyedResponses * added scaffolding for the req-resp manager * added default policies for the search commands * split command map into module->command * cleanup, added logic to refresh the cache * added reactive cache refresh * revert cluster refresh * fixed lint * addresed first batch of comments * rewrote aggregator implementations with atomic for native or nearnative primitives * addressed more comments, fixed lint * added batch aggregator operations * fixed lint * updated batch aggregator, fixed extractcommandvalue * fixed lint * added batching to aggregateResponses * fixed deadlocks * changed aggregator logic, added error params * added preemptive return to the aggregators * more work on the aggregators * updated and and or aggregators * fixed lint * added configurable policy resolvers * slight refactor * removed the interface, slight refactor * change func signature from cmdName to cmder * added nil safety assertions * few small refactors * added read only policies * removed leftover prints * Rebased to master, resolved comnflicts * fixed lint * updated gha * fixed tests, minor consistency refactor * preallocated simple errors * changed numeric aggregators to use float64 * speculative test fix * Update command.go Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com> * Update main_test.go Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com> * Add static shard picker * Fix nil value handling in command aggregation * Modify the Clone method to return a shallow copy * Add clone method to digest command * Optimize keyless command routing to respect ShardPicker policy * Remove MGET references * Fix MGET aggregation to map individual values to keys across shards * Add clone method to hybrid search commands * Undo changes in route keyless test * remove comments * Add test for DisableRoutingPolicies option * Add Routing Policies Comprehensive Test Suite and Fix multi keyed aggregation for different step --------- Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com> Co-authored-by: Nedyalko Dyakov <nedyalko.dyakov@gmail.com> Co-authored-by: Hristo Temelski <hristo.temelski@redis.com>
210 lines
4.5 KiB
Go
210 lines
4.5 KiB
Go
package redis
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"github.com/redis/go-redis/v9/internal/routing"
|
|
)
|
|
|
|
type (
|
|
module = string
|
|
commandName = string
|
|
)
|
|
|
|
var defaultPolicies = map[module]map[commandName]*routing.CommandPolicy{
|
|
"ft": {
|
|
"create": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
},
|
|
"search": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
Tips: map[string]string{
|
|
routing.ReadOnlyCMD: "",
|
|
},
|
|
},
|
|
"aggregate": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
Tips: map[string]string{
|
|
routing.ReadOnlyCMD: "",
|
|
},
|
|
},
|
|
"dictadd": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
},
|
|
"dictdump": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
Tips: map[string]string{
|
|
routing.ReadOnlyCMD: "",
|
|
},
|
|
},
|
|
"dictdel": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
},
|
|
"suglen": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultHashSlot,
|
|
Tips: map[string]string{
|
|
routing.ReadOnlyCMD: "",
|
|
},
|
|
},
|
|
"cursor": {
|
|
Request: routing.ReqSpecial,
|
|
Response: routing.RespDefaultKeyless,
|
|
Tips: map[string]string{
|
|
routing.ReadOnlyCMD: "",
|
|
},
|
|
},
|
|
"sugadd": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultHashSlot,
|
|
},
|
|
"sugget": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultHashSlot,
|
|
Tips: map[string]string{
|
|
routing.ReadOnlyCMD: "",
|
|
},
|
|
},
|
|
"sugdel": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultHashSlot,
|
|
},
|
|
"spellcheck": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
Tips: map[string]string{
|
|
routing.ReadOnlyCMD: "",
|
|
},
|
|
},
|
|
"explain": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
Tips: map[string]string{
|
|
routing.ReadOnlyCMD: "",
|
|
},
|
|
},
|
|
"explaincli": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
Tips: map[string]string{
|
|
routing.ReadOnlyCMD: "",
|
|
},
|
|
},
|
|
"aliasadd": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
},
|
|
"aliasupdate": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
},
|
|
"aliasdel": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
},
|
|
"info": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
Tips: map[string]string{
|
|
routing.ReadOnlyCMD: "",
|
|
},
|
|
},
|
|
"tagvals": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
Tips: map[string]string{
|
|
routing.ReadOnlyCMD: "",
|
|
},
|
|
},
|
|
"syndump": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
Tips: map[string]string{
|
|
routing.ReadOnlyCMD: "",
|
|
},
|
|
},
|
|
"synupdate": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
},
|
|
"profile": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
Tips: map[string]string{
|
|
routing.ReadOnlyCMD: "",
|
|
},
|
|
},
|
|
"alter": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
},
|
|
"dropindex": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
},
|
|
"drop": {
|
|
Request: routing.ReqDefault,
|
|
Response: routing.RespDefaultKeyless,
|
|
},
|
|
},
|
|
}
|
|
|
|
type CommandInfoResolveFunc func(ctx context.Context, cmd Cmder) *routing.CommandPolicy
|
|
|
|
type commandInfoResolver struct {
|
|
resolveFunc CommandInfoResolveFunc
|
|
fallBackResolver *commandInfoResolver
|
|
}
|
|
|
|
func NewCommandInfoResolver(resolveFunc CommandInfoResolveFunc) *commandInfoResolver {
|
|
return &commandInfoResolver{
|
|
resolveFunc: resolveFunc,
|
|
}
|
|
}
|
|
|
|
func NewDefaultCommandPolicyResolver() *commandInfoResolver {
|
|
return NewCommandInfoResolver(func(ctx context.Context, cmd Cmder) *routing.CommandPolicy {
|
|
module := "core"
|
|
command := cmd.Name()
|
|
cmdParts := strings.Split(command, ".")
|
|
if len(cmdParts) == 2 {
|
|
module = cmdParts[0]
|
|
command = cmdParts[1]
|
|
}
|
|
|
|
if policy, ok := defaultPolicies[module][command]; ok {
|
|
return policy
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (r *commandInfoResolver) GetCommandPolicy(ctx context.Context, cmd Cmder) *routing.CommandPolicy {
|
|
if r.resolveFunc == nil {
|
|
return nil
|
|
}
|
|
|
|
policy := r.resolveFunc(ctx, cmd)
|
|
if policy != nil {
|
|
return policy
|
|
}
|
|
|
|
if r.fallBackResolver != nil {
|
|
return r.fallBackResolver.GetCommandPolicy(ctx, cmd)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *commandInfoResolver) SetFallbackResolver(fallbackResolver *commandInfoResolver) {
|
|
r.fallBackResolver = fallbackResolver
|
|
}
|