feat: add lock for hooks.dial

Signed-off-by: monkey92t <golang@88.com>
This commit is contained in:
monkey92t 2023-02-26 18:29:59 +08:00
parent e309eaf915
commit 24fa725799
5 changed files with 35 additions and 11 deletions

View File

@ -838,7 +838,7 @@ type ClusterClient struct {
state *clusterStateHolder
cmdsInfoCache *cmdsInfoCache
cmdable
hooksMixin
*hooksMixin
}
// NewClusterClient returns a Redis Cluster client as described in
@ -849,6 +849,7 @@ func NewClusterClient(opt *ClusterOptions) *ClusterClient {
c := &ClusterClient{
opt: opt,
nodes: newClusterNodes(opt),
hooksMixin: &hooksMixin{},
}
c.state = newClusterStateHolder(c.loadState)

View File

@ -6,6 +6,7 @@ import (
"fmt"
"net"
"strings"
"sync"
"sync/atomic"
"time"
@ -44,6 +45,8 @@ type hooksMixin struct {
slice []Hook
initial hooks
current hooks
hooksMu sync.RWMutex
}
func (hs *hooksMixin) initHooks(hooks hooks) {
@ -117,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,8 +144,15 @@ func (hs *hooksMixin) chain() {
}
}
func (hs *hooksMixin) clone() hooksMixin {
clone := *hs
func (hs *hooksMixin) clone() *hooksMixin {
hs.hooksMu.Lock()
defer hs.hooksMu.Unlock()
clone := &hooksMixin{
slice: hs.slice,
initial: hs.initial,
current: hs.current,
}
l := len(clone.slice)
clone.slice = clone.slice[:l:l]
return clone
@ -166,7 +179,11 @@ func (hs *hooksMixin) withProcessPipelineHook(
}
func (hs *hooksMixin) dialHook(ctx context.Context, network, addr string) (net.Conn, error) {
return hs.current.dial(ctx, network, addr)
hs.hooksMu.RLock()
conn, err := hs.current.dial(ctx, network, addr)
hs.hooksMu.RUnlock()
return conn, err
}
func (hs *hooksMixin) processHook(ctx context.Context, cmd Cmder) error {
@ -588,8 +605,8 @@ func (c *baseClient) context(ctx context.Context) context.Context {
// of idle connections. You can control the pool size with Config.PoolSize option.
type Client struct {
*baseClient
*hooksMixin
cmdable
hooksMixin
}
// NewClient returns a client to the Redis Server specified by Options.
@ -600,6 +617,7 @@ func NewClient(opt *Options) *Client {
baseClient: &baseClient{
opt: opt,
},
hooksMixin: &hooksMixin{},
}
c.init()
c.connPool = newConnPool(opt, c.dialHook)
@ -620,6 +638,7 @@ func (c *Client) init() {
func (c *Client) WithTimeout(timeout time.Duration) *Client {
clone := *c
clone.baseClient = c.baseClient.withTimeout(timeout)
clone.hooksMixin = c.hooksMixin.clone()
clone.init()
return &clone
}
@ -758,7 +777,7 @@ type Conn struct {
baseClient
cmdable
statefulCmdable
hooksMixin
*hooksMixin
}
func newConn(opt *Options, connPool pool.Pooler) *Conn {
@ -767,6 +786,7 @@ func newConn(opt *Options, connPool pool.Pooler) *Conn {
opt: opt,
connPool: connPool,
},
hooksMixin: &hooksMixin{},
}
c.cmdable = c.Process

View File

@ -487,7 +487,7 @@ func (c *ringSharding) Close() error {
// Otherwise you should use Redis Cluster.
type Ring struct {
cmdable
hooksMixin
*hooksMixin
opt *RingOptions
sharding *ringSharding
@ -504,6 +504,7 @@ func NewRing(opt *RingOptions) *Ring {
opt: opt,
sharding: newRingSharding(opt),
heartbeatCancelFn: hbCancel,
hooksMixin: &hooksMixin{},
}
ring.cmdsInfoCache = newCmdsInfoCache(ring.cmdsInfo)

View File

@ -211,6 +211,7 @@ func NewFailoverClient(failoverOpt *FailoverOptions) *Client {
baseClient: &baseClient{
opt: opt,
},
hooksMixin: &hooksMixin{},
}
rdb.init()
@ -267,7 +268,7 @@ func masterReplicaDialer(
// SentinelClient is a client for a Redis Sentinel.
type SentinelClient struct {
*baseClient
hooksMixin
*hooksMixin
}
func NewSentinelClient(opt *Options) *SentinelClient {
@ -276,6 +277,7 @@ func NewSentinelClient(opt *Options) *SentinelClient {
baseClient: &baseClient{
opt: opt,
},
hooksMixin: &hooksMixin{},
}
c.initHooks(hooks{

2
tx.go
View File

@ -19,7 +19,7 @@ type Tx struct {
baseClient
cmdable
statefulCmdable
hooksMixin
*hooksMixin
}
func (c *Client) newTx() *Tx {