Merge pull request #2221 from tisonkun/eval_ro

feat: support eval_ro and evalsha_ro
This commit is contained in:
Vladimir Mihailenco 2022-10-04 14:29:22 +03:00 committed by GitHub
commit be25907703
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 61 additions and 15 deletions

View File

@ -65,7 +65,7 @@ func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int {
} }
switch cmd.Name() { switch cmd.Name() {
case "eval", "evalsha": case "eval", "evalsha", "eval_ro", "evalsha_ro":
if cmd.stringArg(2) != "0" { if cmd.stringArg(2) != "0" {
return 3 return 3
} }

View File

@ -339,6 +339,8 @@ type Cmdable interface {
Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
EvalRO(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
EvalShaRO(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd
ScriptFlush(ctx context.Context) *StatusCmd ScriptFlush(ctx context.Context) *StatusCmd
ScriptKill(ctx context.Context) *StatusCmd ScriptKill(ctx context.Context) *StatusCmd
@ -3010,24 +3012,25 @@ func (c cmdable) MemoryUsage(ctx context.Context, key string, samples ...int) *I
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
func (c cmdable) Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd { func (c cmdable) Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd {
cmdArgs := make([]interface{}, 3+len(keys), 3+len(keys)+len(args)) return c.eval(ctx, "eval", script, keys, args...)
cmdArgs[0] = "eval" }
cmdArgs[1] = script
cmdArgs[2] = len(keys) func (c cmdable) EvalRO(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd {
for i, key := range keys { return c.eval(ctx, "eval_ro", script, keys, args...)
cmdArgs[3+i] = key
}
cmdArgs = appendArgs(cmdArgs, args)
cmd := NewCmd(ctx, cmdArgs...)
cmd.SetFirstKeyPos(3)
_ = c(ctx, cmd)
return cmd
} }
func (c cmdable) EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd { func (c cmdable) EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd {
return c.eval(ctx, "evalsha", sha1, keys, args...)
}
func (c cmdable) EvalShaRO(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd {
return c.eval(ctx, "evalsha_ro", sha1, keys, args...)
}
func (c cmdable) eval(ctx context.Context, name, payload string, keys []string, args ...interface{}) *Cmd {
cmdArgs := make([]interface{}, 3+len(keys), 3+len(keys)+len(args)) cmdArgs := make([]interface{}, 3+len(keys), 3+len(keys)+len(args))
cmdArgs[0] = "evalsha" cmdArgs[0] = name
cmdArgs[1] = sha1 cmdArgs[1] = payload
cmdArgs[2] = len(keys) cmdArgs[2] = len(keys)
for i, key := range keys { for i, key := range keys {
cmdArgs[3+i] = key cmdArgs[3+i] = key

View File

@ -5413,6 +5413,29 @@ var _ = Describe("Commands", func() {
}) })
}) })
Describe("EvalRO", func() {
It("returns keys and values", func() {
vals, err := client.EvalRO(
ctx,
"return {KEYS[1],ARGV[1]}",
[]string{"key"},
"hello",
).Result()
Expect(err).NotTo(HaveOccurred())
Expect(vals).To(Equal([]interface{}{"key", "hello"}))
})
It("returns all values after an error", func() {
vals, err := client.EvalRO(
ctx,
`return {12, {err="error"}, "abc"}`,
nil,
).Result()
Expect(err).NotTo(HaveOccurred())
Expect(vals).To(Equal([]interface{}{int64(12), proto.RedisError("error"), "abc"}))
})
})
Describe("SlowLogGet", func() { Describe("SlowLogGet", func() {
It("returns slow query result", func() { It("returns slow query result", func() {
const key = "slowlog-log-slower-than" const key = "slowlog-log-slower-than"

View File

@ -11,6 +11,8 @@ import (
type Scripter interface { type Scripter interface {
Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
EvalRO(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
EvalShaRO(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd
ScriptLoad(ctx context.Context, script string) *StringCmd ScriptLoad(ctx context.Context, script string) *StringCmd
} }
@ -50,10 +52,18 @@ func (s *Script) Eval(ctx context.Context, c Scripter, keys []string, args ...in
return c.Eval(ctx, s.src, keys, args...) return c.Eval(ctx, s.src, keys, args...)
} }
func (s *Script) EvalRO(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
return c.EvalRO(ctx, s.src, keys, args...)
}
func (s *Script) EvalSha(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd { func (s *Script) EvalSha(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
return c.EvalSha(ctx, s.hash, keys, args...) return c.EvalSha(ctx, s.hash, keys, args...)
} }
func (s *Script) EvalShaRO(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
return c.EvalShaRO(ctx, s.hash, keys, args...)
}
// Run optimistically uses EVALSHA to run the script. If script does not exist // Run optimistically uses EVALSHA to run the script. If script does not exist
// it is retried using EVAL. // it is retried using EVAL.
func (s *Script) Run(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd { func (s *Script) Run(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
@ -63,3 +73,13 @@ func (s *Script) Run(ctx context.Context, c Scripter, keys []string, args ...int
} }
return r return r
} }
// RunRO optimistically uses EVALSHA_RO to run the script. If script does not exist
// it is retried using EVAL_RO.
func (s *Script) RunRO(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
r := s.EvalShaRO(ctx, c, keys, args...)
if err := r.Err(); err != nil && strings.HasPrefix(err.Error(), "NOSCRIPT ") {
return s.EvalRO(ctx, c, keys, args...)
}
return r
}