Upgrade go-redis from v9.3.0 to v9.4.0 (#7593)

Skip v9.3.1 and go straight to v9.4.0 because it's a fix for a
breaking change introduced in v9.3.1. I don't believe we can upgrade to
v9.5.x at this time because of our [redis container
version](fa3b0106e5/docker-compose.yml (L110-L111)).

Changes from
[v9.3.1](https://github.com/redis/go-redis/releases/tag/v9.3.1)
Changes from
[v9.4.0](https://github.com/redis/go-redis/releases/tag/v9.4.0)
This commit is contained in:
Phil Porada 2024-07-16 11:55:33 -04:00 committed by GitHub
parent 472effbb9b
commit b61c7e1fdd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 243 additions and 83 deletions

4
go.mod
View File

@ -24,7 +24,7 @@ require (
github.com/nxadm/tail v1.4.11
github.com/prometheus/client_golang v1.15.1
github.com/prometheus/client_model v0.4.0
github.com/redis/go-redis/v9 v9.3.0
github.com/redis/go-redis/v9 v9.4.0
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399
github.com/weppos/publicsuffix-go v0.30.3-0.20240510084413-5f1d03393b3d
github.com/zmap/zcrypto v0.0.0-20231219022726-a1f61fb1661c
@ -63,7 +63,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/sts v1.30.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect

8
go.sum
View File

@ -55,8 +55,8 @@ github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7N
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
@ -214,8 +214,8 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/redis/go-redis/v9 v9.3.0 h1:RiVDjmig62jIWp7Kk4XVLs0hzV6pI3PyTnnL0cnn0u0=
github.com/redis/go-redis/v9 v9.3.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwyKk=
github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=

View File

@ -70,3 +70,5 @@ benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')
- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics)
- [FreeCache](https://github.com/coocood/freecache)
- [FastCache](https://github.com/VictoriaMetrics/fastcache)
- [Ristretto](https://github.com/dgraph-io/ristretto)
- [Badger](https://github.com/dgraph-io/badger)

View File

@ -19,10 +19,13 @@ const (
// Store the primes in an array as well.
//
// The consts are used when possible in Go code to avoid MOVs but we need a
// contiguous array of the assembly code.
// contiguous array for the assembly code.
var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5}
// Digest implements hash.Hash64.
//
// Note that a zero-valued Digest is not ready to receive writes.
// Call Reset or create a Digest using New before calling other methods.
type Digest struct {
v1 uint64
v2 uint64
@ -33,19 +36,31 @@ type Digest struct {
n int // how much of mem is used
}
// New creates a new Digest that computes the 64-bit xxHash algorithm.
// New creates a new Digest with a zero seed.
func New() *Digest {
return NewWithSeed(0)
}
// NewWithSeed creates a new Digest with the given seed.
func NewWithSeed(seed uint64) *Digest {
var d Digest
d.Reset()
d.ResetWithSeed(seed)
return &d
}
// Reset clears the Digest's state so that it can be reused.
// It uses a seed value of zero.
func (d *Digest) Reset() {
d.v1 = primes[0] + prime2
d.v2 = prime2
d.v3 = 0
d.v4 = -primes[0]
d.ResetWithSeed(0)
}
// ResetWithSeed clears the Digest's state so that it can be reused.
// It uses the given seed to initialize the state.
func (d *Digest) ResetWithSeed(seed uint64) {
d.v1 = seed + prime1 + prime2
d.v2 = seed + prime2
d.v3 = seed
d.v4 = seed - prime1
d.total = 0
d.n = 0
}

View File

@ -6,7 +6,7 @@
package xxhash
// Sum64 computes the 64-bit xxHash digest of b.
// Sum64 computes the 64-bit xxHash digest of b with a zero seed.
//
//go:noescape
func Sum64(b []byte) uint64

View File

@ -3,7 +3,7 @@
package xxhash
// Sum64 computes the 64-bit xxHash digest of b.
// Sum64 computes the 64-bit xxHash digest of b with a zero seed.
func Sum64(b []byte) uint64 {
// A simpler version would be
// d := New()

View File

@ -5,7 +5,7 @@
package xxhash
// Sum64String computes the 64-bit xxHash digest of s.
// Sum64String computes the 64-bit xxHash digest of s with a zero seed.
func Sum64String(s string) uint64 {
return Sum64([]byte(s))
}

View File

@ -33,7 +33,7 @@ import (
//
// See https://github.com/golang/go/issues/42739 for discussion.
// Sum64String computes the 64-bit xxHash digest of s.
// Sum64String computes the 64-bit xxHash digest of s with a zero seed.
// It may be faster than Sum64([]byte(s)) by avoiding a copy.
func Sum64String(s string) uint64 {
b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)}))

View File

@ -149,15 +149,16 @@ import (
"github.com/redis/go-redis/v9"
)
var ctx = context.Background()
func ExampleClient() {
url := "redis://localhost:6379?password=hello&protocol=3"
func ExampleClient() *redis.Client {
url := "redis://user:password@localhost:6379/0?protocol=3"
opts, err := redis.ParseURL(url)
if err != nil {
panic(err)
}
rdb := redis.NewClient(opts)
return redis.NewClient(opts)
}
```
## Contributing

View File

@ -1,6 +1,8 @@
package redis
import "context"
import (
"context"
)
type BitMapCmdable interface {
GetBit(ctx context.Context, key string, offset int64) *IntCmd
@ -127,3 +129,21 @@ func (c cmdable) BitField(ctx context.Context, key string, values ...interface{}
_ = c(ctx, cmd)
return cmd
}
// BitFieldRO - Read-only variant of the BITFIELD command.
// It is like the original BITFIELD but only accepts GET subcommand and can safely be used in read-only replicas.
// - BitFieldRO(ctx, key, "<Encoding0>", "<Offset0>", "<Encoding1>","<Offset1>")
func (c cmdable) BitFieldRO(ctx context.Context, key string, values ...interface{}) *IntSliceCmd {
args := make([]interface{}, 2, 2+len(values))
args[0] = "BITFIELD_RO"
args[1] = key
if len(values)%2 != 0 {
panic("BitFieldRO: invalid number of arguments, must be even")
}
for i := 0; i < len(values); i += 2 {
args = append(args, "GET", values[i], values[i+1])
}
cmd := NewIntSliceCmd(ctx, args...)
_ = c(ctx, cmd)
return cmd
}

View File

@ -8,6 +8,7 @@ import (
"regexp"
"strconv"
"strings"
"sync"
"time"
"github.com/redis/go-redis/v9/internal"
@ -17,10 +18,22 @@ import (
)
type Cmder interface {
// command name.
// e.g. "set k v ex 10" -> "set", "cluster info" -> "cluster".
Name() string
// full command name.
// e.g. "set k v ex 10" -> "set", "cluster info" -> "cluster info".
FullName() string
// all args of the command.
// e.g. "set k v ex 10" -> "[set k v ex 10]".
Args() []interface{}
// format request and response string.
// e.g. "set k v ex 10" -> "set k v ex 10: OK", "get k" -> "get k: v".
String() string
stringArg(int) string
firstKeyPos() int8
SetFirstKeyPos(int8)
@ -62,7 +75,7 @@ func writeCmd(wr *proto.Writer, cmd Cmder) error {
return wr.WriteArgs(cmd.Args())
}
func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int {
func cmdFirstKeyPos(cmd Cmder) int {
if pos := cmd.firstKeyPos(); pos != 0 {
return int(pos)
}
@ -82,10 +95,6 @@ func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int {
return 2
}
}
if info != nil {
return int(info.FirstKeyPos)
}
return 1
}
@ -845,7 +854,7 @@ func (cmd *StringCmd) Val() string {
}
func (cmd *StringCmd) Result() (string, error) {
return cmd.Val(), cmd.err
return cmd.val, cmd.err
}
func (cmd *StringCmd) Bytes() ([]byte, error) {
@ -949,7 +958,7 @@ func (cmd *FloatCmd) Val() float64 {
}
func (cmd *FloatCmd) Result() (float64, error) {
return cmd.Val(), cmd.Err()
return cmd.val, cmd.err
}
func (cmd *FloatCmd) String() string {
@ -1044,7 +1053,7 @@ func (cmd *StringSliceCmd) Val() []string {
}
func (cmd *StringSliceCmd) Result() ([]string, error) {
return cmd.Val(), cmd.Err()
return cmd.val, cmd.err
}
func (cmd *StringSliceCmd) String() string {
@ -2706,7 +2715,7 @@ func (cmd *ZWithKeyCmd) Val() *ZWithKey {
}
func (cmd *ZWithKeyCmd) Result() (*ZWithKey, error) {
return cmd.Val(), cmd.Err()
return cmd.val, cmd.err
}
func (cmd *ZWithKeyCmd) String() string {
@ -2844,7 +2853,7 @@ func (cmd *ClusterSlotsCmd) Val() []ClusterSlot {
}
func (cmd *ClusterSlotsCmd) Result() ([]ClusterSlot, error) {
return cmd.Val(), cmd.Err()
return cmd.val, cmd.err
}
func (cmd *ClusterSlotsCmd) String() string {
@ -3304,7 +3313,7 @@ func (cmd *GeoPosCmd) Val() []*GeoPos {
}
func (cmd *GeoPosCmd) Result() ([]*GeoPos, error) {
return cmd.Val(), cmd.Err()
return cmd.val, cmd.err
}
func (cmd *GeoPosCmd) String() string {
@ -3385,7 +3394,7 @@ func (cmd *CommandsInfoCmd) Val() map[string]*CommandInfo {
}
func (cmd *CommandsInfoCmd) Result() (map[string]*CommandInfo, error) {
return cmd.Val(), cmd.Err()
return cmd.val, cmd.err
}
func (cmd *CommandsInfoCmd) String() string {
@ -3575,7 +3584,7 @@ func (cmd *SlowLogCmd) Val() []SlowLog {
}
func (cmd *SlowLogCmd) Result() ([]SlowLog, error) {
return cmd.Val(), cmd.Err()
return cmd.val, cmd.err
}
func (cmd *SlowLogCmd) String() string {
@ -3674,7 +3683,7 @@ func (cmd *MapStringInterfaceCmd) Val() map[string]interface{} {
}
func (cmd *MapStringInterfaceCmd) Result() (map[string]interface{}, error) {
return cmd.Val(), cmd.Err()
return cmd.val, cmd.err
}
func (cmd *MapStringInterfaceCmd) String() string {
@ -3738,7 +3747,7 @@ func (cmd *MapStringStringSliceCmd) Val() []map[string]string {
}
func (cmd *MapStringStringSliceCmd) Result() ([]map[string]string, error) {
return cmd.Val(), cmd.Err()
return cmd.val, cmd.err
}
func (cmd *MapStringStringSliceCmd) String() string {
@ -3802,7 +3811,7 @@ func (cmd *MapStringInterfaceSliceCmd) Val() []map[string]interface{} {
}
func (cmd *MapStringInterfaceSliceCmd) Result() ([]map[string]interface{}, error) {
return cmd.Val(), cmd.Err()
return cmd.val, cmd.err
}
func (cmd *MapStringInterfaceSliceCmd) String() string {
@ -4652,7 +4661,7 @@ func (cmd *ClusterLinksCmd) Val() []ClusterLink {
}
func (cmd *ClusterLinksCmd) Result() ([]ClusterLink, error) {
return cmd.Val(), cmd.Err()
return cmd.val, cmd.err
}
func (cmd *ClusterLinksCmd) String() string {
@ -4754,7 +4763,7 @@ func (cmd *ClusterShardsCmd) Val() []ClusterShard {
}
func (cmd *ClusterShardsCmd) Result() ([]ClusterShard, error) {
return cmd.Val(), cmd.Err()
return cmd.val, cmd.err
}
func (cmd *ClusterShardsCmd) String() string {
@ -5227,7 +5236,7 @@ func (cmd *ACLLogCmd) Val() []*ACLLogEntry {
}
func (cmd *ACLLogCmd) Result() ([]*ACLLogEntry, error) {
return cmd.Val(), cmd.Err()
return cmd.val, cmd.err
}
func (cmd *ACLLogCmd) String() string {
@ -5328,7 +5337,7 @@ func (cmd *InfoCmd) Val() map[string]map[string]string {
}
func (cmd *InfoCmd) Result() (map[string]map[string]string, error) {
return cmd.Val(), cmd.Err()
return cmd.val, cmd.err
}
func (cmd *InfoCmd) String() string {
@ -5369,7 +5378,6 @@ func (cmd *InfoCmd) readReply(rd *proto.Reader) error {
}
return nil
}
func (cmd *InfoCmd) Item(section, key string) string {
@ -5381,3 +5389,85 @@ func (cmd *InfoCmd) Item(section, key string) string {
return cmd.val[section][key]
}
}
type MonitorStatus int
const (
monitorStatusIdle MonitorStatus = iota
monitorStatusStart
monitorStatusStop
)
type MonitorCmd struct {
baseCmd
ch chan string
status MonitorStatus
mu sync.Mutex
}
func newMonitorCmd(ctx context.Context, ch chan string) *MonitorCmd {
return &MonitorCmd{
baseCmd: baseCmd{
ctx: ctx,
args: []interface{}{"monitor"},
},
ch: ch,
status: monitorStatusIdle,
mu: sync.Mutex{},
}
}
func (cmd *MonitorCmd) String() string {
return cmdString(cmd, nil)
}
func (cmd *MonitorCmd) readReply(rd *proto.Reader) error {
ctx, cancel := context.WithCancel(cmd.ctx)
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
default:
err := cmd.readMonitor(rd, cancel)
if err != nil {
cmd.err = err
return
}
}
}
}(ctx)
return nil
}
func (cmd *MonitorCmd) readMonitor(rd *proto.Reader, cancel context.CancelFunc) error {
for {
cmd.mu.Lock()
st := cmd.status
cmd.mu.Unlock()
if pk, _ := rd.Peek(1); len(pk) != 0 && st == monitorStatusStart {
line, err := rd.ReadString()
if err != nil {
return err
}
cmd.ch <- line
}
if st == monitorStatusStop {
cancel()
break
}
}
return nil
}
func (cmd *MonitorCmd) Start() {
cmd.mu.Lock()
defer cmd.mu.Unlock()
cmd.status = monitorStatusStart
}
func (cmd *MonitorCmd) Stop() {
cmd.mu.Lock()
defer cmd.mu.Unlock()
cmd.status = monitorStatusStop
}

View File

@ -204,7 +204,6 @@ type Cmdable interface {
SlowLogGet(ctx context.Context, num int64) *SlowLogCmd
Time(ctx context.Context) *TimeCmd
DebugObject(ctx context.Context, key string) *StringCmd
MemoryUsage(ctx context.Context, key string, samples ...int) *IntCmd
ModuleLoadex(ctx context.Context, conf *ModuleLoadexConfig) *StringCmd
@ -700,3 +699,20 @@ func (c cmdable) ModuleLoadex(ctx context.Context, conf *ModuleLoadexConfig) *St
_ = c(ctx, cmd)
return cmd
}
/*
Monitor - represents a Redis MONITOR command, allowing the user to capture
and process all commands sent to a Redis server. This mimics the behavior of
MONITOR in the redis-cli.
Notes:
- Using MONITOR blocks the connection to the server for itself. It needs a dedicated connection
- The user should create a channel of type string
- This runs concurrently in the background. Trigger via the Start and Stop functions
See further: Redis MONITOR command: https://redis.io/commands/monitor
*/
func (c cmdable) Monitor(ctx context.Context, ch chan string) *MonitorCmd {
cmd := newMonitorCmd(ctx, ch)
_ = c(ctx, cmd)
return cmd
}

View File

@ -61,7 +61,11 @@ func newStructSpec(t reflect.Type, fieldTag string) *structSpec {
}
// Use the built-in decoder.
out.set(tag, &structField{index: i, fn: decoders[f.Type.Kind()]})
kind := f.Type.Kind()
if kind == reflect.Pointer {
kind = f.Type.Elem().Kind()
}
out.set(tag, &structField{index: i, fn: decoders[kind]})
}
return out

View File

@ -66,7 +66,6 @@ type JSONCmd struct {
var _ Cmder = (*JSONCmd)(nil)
func newJSONCmd(ctx context.Context, args ...interface{}) *JSONCmd {
return &JSONCmd{
baseCmd: baseCmd{
ctx: ctx,
@ -95,7 +94,6 @@ func (cmd *JSONCmd) Val() string {
} else {
return cmd.val
}
}
func (cmd *JSONCmd) Result() (string, error) {
@ -103,7 +101,6 @@ func (cmd *JSONCmd) Result() (string, error) {
}
func (cmd JSONCmd) Expanded() (interface{}, error) {
if len(cmd.val) != 0 && cmd.expanded == nil {
err := json.Unmarshal([]byte(cmd.val), &cmd.expanded)
if err != nil {
@ -115,7 +112,6 @@ func (cmd JSONCmd) Expanded() (interface{}, error) {
}
func (cmd *JSONCmd) readReply(rd *proto.Reader) error {
// nil response from JSON.(M)GET (cmd.baseCmd.err will be "redis: nil")
if cmd.baseCmd.Err() == Nil {
cmd.val = ""
@ -131,7 +127,7 @@ func (cmd *JSONCmd) readReply(rd *proto.Reader) error {
return err
}
var expanded = make([]interface{}, size)
expanded := make([]interface{}, size)
for i := 0; i < size; i++ {
if expanded[i], err = rd.ReadReply(); err != nil {
@ -182,11 +178,10 @@ func (cmd *JSONSliceCmd) Val() []interface{} {
}
func (cmd *JSONSliceCmd) Result() ([]interface{}, error) {
return cmd.Val(), cmd.Err()
return cmd.val, cmd.err
}
func (cmd *JSONSliceCmd) readReply(rd *proto.Reader) error {
if cmd.baseCmd.Err() == Nil {
cmd.val = nil
return Nil
@ -220,7 +215,6 @@ func (cmd *JSONSliceCmd) readReply(rd *proto.Reader) error {
}
}
return nil
}
/*******************************************************************************
@ -258,11 +252,10 @@ func (cmd *IntPointerSliceCmd) Val() []*int64 {
}
func (cmd *IntPointerSliceCmd) Result() ([]*int64, error) {
return cmd.Val(), cmd.Err()
return cmd.val, cmd.err
}
func (cmd *IntPointerSliceCmd) readReply(rd *proto.Reader) error {
n, err := rd.ReadArrayLen()
if err != nil {
return err

View File

@ -144,6 +144,9 @@ type Options struct {
// Disable set-lib on connect. Default is false.
DisableIndentity bool
// Add suffix to client name. Default is empty.
IdentitySuffix string
}
func (opt *Options) init() {

View File

@ -86,6 +86,8 @@ type ClusterOptions struct {
TLSConfig *tls.Config
DisableIndentity bool // Disable set-lib on connect. Default is false.
IdentitySuffix string // Add suffix to client name. Default is empty.
}
func (opt *ClusterOptions) init() {
@ -291,6 +293,7 @@ func (opt *ClusterOptions) clientOptions() *Options {
ConnMaxIdleTime: opt.ConnMaxIdleTime,
ConnMaxLifetime: opt.ConnMaxLifetime,
DisableIndentity: opt.DisableIndentity,
IdentitySuffix: opt.IdentitySuffix,
TLSConfig: opt.TLSConfig,
// If ClusterSlots is populated, then we probably have an artificial
// cluster whose nodes are not in clustering mode (otherwise there isn't
@ -907,7 +910,6 @@ func (c *ClusterClient) Process(ctx context.Context, cmd Cmder) error {
}
func (c *ClusterClient) process(ctx context.Context, cmd Cmder) error {
cmdInfo := c.cmdInfo(ctx, cmd.Name())
slot := c.cmdSlot(ctx, cmd)
var node *clusterNode
var ask bool
@ -921,7 +923,7 @@ func (c *ClusterClient) process(ctx context.Context, cmd Cmder) error {
if node == nil {
var err error
node, err = c.cmdNode(ctx, cmdInfo, slot)
node, err = c.cmdNode(ctx, cmd.Name(), slot)
if err != nil {
return err
}
@ -1783,8 +1785,7 @@ func (c *ClusterClient) cmdSlot(ctx context.Context, cmd Cmder) int {
return args[2].(int)
}
cmdInfo := c.cmdInfo(ctx, cmd.Name())
return cmdSlot(cmd, cmdFirstKeyPos(cmd, cmdInfo))
return cmdSlot(cmd, cmdFirstKeyPos(cmd))
}
func cmdSlot(cmd Cmder, pos int) int {
@ -1797,7 +1798,7 @@ func cmdSlot(cmd Cmder, pos int) int {
func (c *ClusterClient) cmdNode(
ctx context.Context,
cmdInfo *CommandInfo,
cmdName string,
slot int,
) (*clusterNode, error) {
state, err := c.state.Get(ctx)
@ -1805,8 +1806,11 @@ func (c *ClusterClient) cmdNode(
return nil, err
}
if c.opt.ReadOnly && cmdInfo != nil && cmdInfo.ReadOnly {
return c.slotReadOnlyNode(state, slot)
if c.opt.ReadOnly {
cmdInfo := c.cmdInfo(ctx, cmdName)
if cmdInfo != nil && cmdInfo.ReadOnly {
return c.slotReadOnlyNode(state, slot)
}
}
return state.slotMasterNode(slot)
}

View File

@ -1,6 +1,6 @@
{
"name": "redis",
"version": "9.3.0",
"version": "9.4.0",
"main": "index.js",
"repository": "git@github.com:redis/go-redis.git",
"author": "Vladimir Mihailenco <vladimir.webdev@gmail.com>",

View File

@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"net"
"sync"
"sync/atomic"
"time"
@ -40,12 +41,15 @@ type (
)
type hooksMixin struct {
hooksMu *sync.Mutex
slice []Hook
initial hooks
current hooks
}
func (hs *hooksMixin) initHooks(hooks hooks) {
hs.hooksMu = new(sync.Mutex)
hs.initial = hooks
hs.chain()
}
@ -116,6 +120,9 @@ func (hs *hooksMixin) AddHook(hook Hook) {
func (hs *hooksMixin) chain() {
hs.initial.setDefaults()
hs.hooksMu.Lock()
defer hs.hooksMu.Unlock()
hs.current.dial = hs.initial.dial
hs.current.process = hs.initial.process
hs.current.pipeline = hs.initial.pipeline
@ -138,9 +145,13 @@ func (hs *hooksMixin) chain() {
}
func (hs *hooksMixin) clone() hooksMixin {
hs.hooksMu.Lock()
defer hs.hooksMu.Unlock()
clone := *hs
l := len(clone.slice)
clone.slice = clone.slice[:l:l]
clone.hooksMu = new(sync.Mutex)
return clone
}
@ -165,6 +176,8 @@ func (hs *hooksMixin) withProcessPipelineHook(
}
func (hs *hooksMixin) dialHook(ctx context.Context, network, addr string) (net.Conn, error) {
hs.hooksMu.Lock()
defer hs.hooksMu.Unlock()
return hs.current.dial(ctx, network, addr)
}
@ -302,6 +315,9 @@ func (c *baseClient) initConn(ctx context.Context, cn *pool.Conn) error {
if !c.opt.DisableIndentity {
libName := ""
libVer := Version()
if c.opt.IdentitySuffix != "" {
libName = c.opt.IdentitySuffix
}
libInfo := LibraryInfo{LibName: &libName}
conn.ClientSetInfo(ctx, libInfo)
libInfo = LibraryInfo{LibVer: &libVer}

View File

@ -99,6 +99,7 @@ type RingOptions struct {
Limiter Limiter
DisableIndentity bool
IdentitySuffix string
}
func (opt *RingOptions) init() {
@ -166,6 +167,7 @@ func (opt *RingOptions) clientOptions() *Options {
Limiter: opt.Limiter,
DisableIndentity: opt.DisableIndentity,
IdentitySuffix: opt.IdentitySuffix,
}
}
@ -678,21 +680,8 @@ func (c *Ring) cmdsInfo(ctx context.Context) (map[string]*CommandInfo, error) {
return nil, firstErr
}
func (c *Ring) cmdInfo(ctx context.Context, name string) *CommandInfo {
cmdsInfo, err := c.cmdsInfoCache.Get(ctx)
if err != nil {
return nil
}
info := cmdsInfo[name]
if info == nil {
internal.Logger.Printf(ctx, "info for cmd=%s not found", name)
}
return info
}
func (c *Ring) cmdShard(ctx context.Context, cmd Cmder) (*ringShard, error) {
cmdInfo := c.cmdInfo(ctx, cmd.Name())
pos := cmdFirstKeyPos(cmd, cmdInfo)
pos := cmdFirstKeyPos(cmd)
if pos == 0 {
return c.sharding.Random()
}
@ -760,8 +749,7 @@ func (c *Ring) generalProcessPipeline(
cmdsMap := make(map[string][]Cmder)
for _, cmd := range cmds {
cmdInfo := c.cmdInfo(ctx, cmd.Name())
hash := cmd.stringArg(cmdFirstKeyPos(cmd, cmdInfo))
hash := cmd.stringArg(cmdFirstKeyPos(cmd))
if hash != "" {
hash = c.sharding.Hash(hash)
}

View File

@ -81,6 +81,7 @@ type FailoverOptions struct {
TLSConfig *tls.Config
DisableIndentity bool
IdentitySuffix string
}
func (opt *FailoverOptions) clientOptions() *Options {
@ -117,6 +118,7 @@ func (opt *FailoverOptions) clientOptions() *Options {
TLSConfig: opt.TLSConfig,
DisableIndentity: opt.DisableIndentity,
IdentitySuffix: opt.IdentitySuffix,
}
}

View File

@ -531,6 +531,8 @@ func (c cmdable) TSInfoWithArgs(ctx context.Context, key string, options *TSInfo
}
// TSMAdd - Adds multiple samples to multiple time-series keys.
// It accepts a slice of 'ktv' slices, each containing exactly three elements: key, timestamp, and value.
// This struct must be provided for this command to work.
// For more information - https://redis.io/commands/ts.madd/
func (c cmdable) TSMAdd(ctx context.Context, ktvSlices [][]interface{}) *IntSliceCmd {
args := []interface{}{"TS.MADD"}

View File

@ -67,6 +67,7 @@ type UniversalOptions struct {
MasterName string
DisableIndentity bool
IdentitySuffix string
}
// Cluster returns cluster options created from the universal options.
@ -112,6 +113,7 @@ func (o *UniversalOptions) Cluster() *ClusterOptions {
TLSConfig: o.TLSConfig,
DisableIndentity: o.DisableIndentity,
IdentitySuffix: o.IdentitySuffix,
}
}
@ -157,6 +159,7 @@ func (o *UniversalOptions) Failover() *FailoverOptions {
TLSConfig: o.TLSConfig,
DisableIndentity: o.DisableIndentity,
IdentitySuffix: o.IdentitySuffix,
}
}
@ -199,6 +202,7 @@ func (o *UniversalOptions) Simple() *Options {
TLSConfig: o.TLSConfig,
DisableIndentity: o.DisableIndentity,
IdentitySuffix: o.IdentitySuffix,
}
}

View File

@ -2,5 +2,5 @@ package redis
// Version is the current release version.
func Version() string {
return "9.3.0"
return "9.4.0"
}

4
vendor/modules.txt vendored
View File

@ -129,7 +129,7 @@ github.com/beorn7/perks/quantile
# github.com/cenkalti/backoff/v4 v4.3.0
## explicit; go 1.18
github.com/cenkalti/backoff/v4
# github.com/cespare/xxhash/v2 v2.2.0
# github.com/cespare/xxhash/v2 v2.3.0
## explicit; go 1.11
github.com/cespare/xxhash/v2
# github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f
@ -249,7 +249,7 @@ github.com/prometheus/common/model
github.com/prometheus/procfs
github.com/prometheus/procfs/internal/fs
github.com/prometheus/procfs/internal/util
# github.com/redis/go-redis/v9 v9.3.0
# github.com/redis/go-redis/v9 v9.4.0
## explicit; go 1.18
github.com/redis/go-redis/v9
github.com/redis/go-redis/v9/internal