Skip to content

Commit a109302

Browse files
authored
fix: #2730 data race at hooksMixin (#2814)
1 parent 21bd40a commit a109302

File tree

2 files changed

+63
-0
lines changed

2 files changed

+63
-0
lines changed

redis.go

+13
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"errors"
66
"fmt"
77
"net"
8+
"sync"
89
"sync/atomic"
910
"time"
1011

@@ -40,12 +41,15 @@ type (
4041
)
4142

4243
type hooksMixin struct {
44+
hooksMu *sync.Mutex
45+
4346
slice []Hook
4447
initial hooks
4548
current hooks
4649
}
4750

4851
func (hs *hooksMixin) initHooks(hooks hooks) {
52+
hs.hooksMu = new(sync.Mutex)
4953
hs.initial = hooks
5054
hs.chain()
5155
}
@@ -116,6 +120,9 @@ func (hs *hooksMixin) AddHook(hook Hook) {
116120
func (hs *hooksMixin) chain() {
117121
hs.initial.setDefaults()
118122

123+
hs.hooksMu.Lock()
124+
defer hs.hooksMu.Unlock()
125+
119126
hs.current.dial = hs.initial.dial
120127
hs.current.process = hs.initial.process
121128
hs.current.pipeline = hs.initial.pipeline
@@ -138,9 +145,13 @@ func (hs *hooksMixin) chain() {
138145
}
139146

140147
func (hs *hooksMixin) clone() hooksMixin {
148+
hs.hooksMu.Lock()
149+
defer hs.hooksMu.Unlock()
150+
141151
clone := *hs
142152
l := len(clone.slice)
143153
clone.slice = clone.slice[:l:l]
154+
clone.hooksMu = new(sync.Mutex)
144155
return clone
145156
}
146157

@@ -165,6 +176,8 @@ func (hs *hooksMixin) withProcessPipelineHook(
165176
}
166177

167178
func (hs *hooksMixin) dialHook(ctx context.Context, network, addr string) (net.Conn, error) {
179+
hs.hooksMu.Lock()
180+
defer hs.hooksMu.Unlock()
168181
return hs.current.dial(ctx, network, addr)
169182
}
170183

redis_test.go

+50
Original file line numberDiff line numberDiff line change
@@ -579,3 +579,53 @@ var _ = Describe("Hook", func() {
579579
Expect(cmd.Val()).To(Equal("Script and hook"))
580580
})
581581
})
582+
583+
var _ = Describe("Hook with MinIdleConns", func() {
584+
var client *redis.Client
585+
586+
BeforeEach(func() {
587+
options := redisOptions()
588+
options.MinIdleConns = 1
589+
client = redis.NewClient(options)
590+
Expect(client.FlushDB(ctx).Err()).NotTo(HaveOccurred())
591+
})
592+
593+
AfterEach(func() {
594+
err := client.Close()
595+
Expect(err).NotTo(HaveOccurred())
596+
})
597+
598+
It("fifo", func() {
599+
var res []string
600+
client.AddHook(&hook{
601+
processHook: func(hook redis.ProcessHook) redis.ProcessHook {
602+
return func(ctx context.Context, cmd redis.Cmder) error {
603+
res = append(res, "hook-1-process-start")
604+
err := hook(ctx, cmd)
605+
res = append(res, "hook-1-process-end")
606+
return err
607+
}
608+
},
609+
})
610+
client.AddHook(&hook{
611+
processHook: func(hook redis.ProcessHook) redis.ProcessHook {
612+
return func(ctx context.Context, cmd redis.Cmder) error {
613+
res = append(res, "hook-2-process-start")
614+
err := hook(ctx, cmd)
615+
res = append(res, "hook-2-process-end")
616+
return err
617+
}
618+
},
619+
})
620+
621+
err := client.Ping(ctx).Err()
622+
Expect(err).NotTo(HaveOccurred())
623+
624+
Expect(res).To(Equal([]string{
625+
"hook-1-process-start",
626+
"hook-2-process-start",
627+
"hook-2-process-end",
628+
"hook-1-process-end",
629+
}))
630+
})
631+
})

0 commit comments

Comments
 (0)