From 3031343dae0383e56fb6f107cf6dd0616b55cf2d Mon Sep 17 00:00:00 2001 From: Vladimir Mihailenco Date: Sat, 9 May 2020 17:30:16 +0300 Subject: [PATCH] Make cmd.String() faster --- command.go | 80 +++++++++++++++++++++++++++++----------- internal/proto/writer.go | 3 +- 2 files changed, 61 insertions(+), 22 deletions(-) diff --git a/command.go b/command.go index 1b052ba..7741cd2 100644 --- a/command.go +++ b/command.go @@ -5,7 +5,6 @@ import ( "fmt" "net" "strconv" - "strings" "time" "github.com/go-redis/redis/v8/internal" @@ -56,26 +55,6 @@ func writeCmd(wr *proto.Writer, cmd Cmder) error { return wr.WriteArgs(cmd.Args()) } -func cmdString(cmd Cmder, val interface{}) string { - ss := make([]string, 0, len(cmd.Args())) - for _, arg := range cmd.Args() { - ss = append(ss, fmt.Sprint(arg)) - } - s := strings.Join(ss, " ") - if err := cmd.Err(); err != nil { - return s + ": " + err.Error() - } - if val != nil { - switch vv := val.(type) { - case []byte: - return s + ": " + string(vv) - default: - return s + ": " + fmt.Sprint(val) - } - } - return s -} - func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int { switch cmd.Name() { case "eval", "evalsha": @@ -93,6 +72,65 @@ func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int { return int(info.FirstKeyPos) } +func cmdString(cmd Cmder, val interface{}) string { + b := make([]byte, 0, 32) + + for i, arg := range cmd.Args() { + if i > 0 { + b = append(b, ' ') + } + b = appendArg(b, arg) + } + + if err := cmd.Err(); err != nil { + b = append(b, ": "...) + b = append(b, err.Error()...) + } else if val != nil { + b = append(b, ": "...) + + switch val := val.(type) { + case []byte: + b = append(b, val...) + default: + b = appendArg(b, val) + } + } + + return string(b) +} + +func appendArg(b []byte, v interface{}) []byte { + switch v := v.(type) { + case nil: + return append(b, ""...) + case string: + return append(b, v...) + case []byte: + return append(b, v...) + case int: + return strconv.AppendInt(b, int64(v), 10) + case int32: + return strconv.AppendInt(b, int64(v), 10) + case int64: + return strconv.AppendInt(b, v, 10) + case uint: + return strconv.AppendUint(b, uint64(v), 10) + case uint32: + return strconv.AppendUint(b, uint64(v), 10) + case uint64: + return strconv.AppendUint(b, v, 10) + case bool: + if v { + return append(b, "true"...) + } + return append(b, "false"...) + case time.Time: + return v.AppendFormat(b, time.RFC3339Nano) + default: + return append(b, fmt.Sprint(v)...) + } +} + //------------------------------------------------------------------------------ type baseCmd struct { diff --git a/internal/proto/writer.go b/internal/proto/writer.go index a7c53c8..ed969e3 100644 --- a/internal/proto/writer.go +++ b/internal/proto/writer.go @@ -93,7 +93,8 @@ func (w *Writer) writeArg(v interface{}) error { } return w.int(0) case time.Time: - return w.string(v.Format(time.RFC3339)) + w.numBuf = v.AppendFormat(w.numBuf[:0], time.RFC3339Nano) + return w.bytes(w.numBuf) case encoding.BinaryMarshaler: b, err := v.MarshalBinary() if err != nil {