-
Notifications
You must be signed in to change notification settings - Fork 186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: send readonly command #430
Changes from 5 commits
7759b3a
92288cc
519cd72
0231a44
a2a1aa8
98040d7
f328c8f
ccd4a28
3ec3548
cd6a674
5702ce3
1375321
87e2b39
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -18,7 +18,6 @@ import ( | |||||
|
||||||
// ErrNoSlot indicates that there is no redis node owns the key slot. | ||||||
var ErrNoSlot = errors.New("the slot has no redis node") | ||||||
var ErrReplicaOnlyConflict = errors.New("ReplicaOnly conflicts with SendToReplicas option") | ||||||
|
||||||
type retry struct { | ||||||
cIndexes []int | ||||||
|
@@ -93,17 +92,13 @@ type connrole struct { | |||||
func newClusterClient(opt *ClientOption, connFn connFn) (client *clusterClient, err error) { | ||||||
client = &clusterClient{ | ||||||
cmd: cmds.NewBuilder(cmds.InitSlot), | ||||||
opt: opt, | ||||||
connFn: connFn, | ||||||
opt: opt, | ||||||
conns: make(map[string]connrole), | ||||||
retry: !opt.DisableRetry, | ||||||
aws: len(opt.InitAddress) == 1 && strings.Contains(opt.InitAddress[0], "amazonaws.com"), | ||||||
} | ||||||
|
||||||
if opt.ReplicaOnly && opt.SendToReplicas != nil { | ||||||
return nil, ErrReplicaOnlyConflict | ||||||
} | ||||||
|
||||||
client.connFn = func(dst string, opt *ClientOption) conn { | ||||||
cc := connFn(dst, opt) | ||||||
cc.SetOnCloseHook(func(err error) { | ||||||
|
@@ -222,10 +217,42 @@ func (c *clusterClient) _refresh() (err error) { | |||||
|
||||||
groups := result.parse(c.opt.TLSConfig != nil) | ||||||
conns := make(map[string]connrole, len(groups)) | ||||||
var wg sync.WaitGroup | ||||||
for master, g := range groups { | ||||||
conns[master] = connrole{conn: c.connFn(master, c.opt), replica: false} | ||||||
conns[master] = connrole{ | ||||||
conn: c.connFn(master, c.opt), | ||||||
replica: false, | ||||||
} | ||||||
for _, addr := range g.nodes[1:] { | ||||||
conns[addr] = connrole{conn: c.connFn(addr, c.opt), replica: true} | ||||||
cc := c.connFn(addr, c.opt) | ||||||
|
||||||
if !c.opt.ReplicaOnly { | ||||||
conns[addr] = connrole{ | ||||||
conn: cc, | ||||||
replica: true, | ||||||
} | ||||||
continue | ||||||
} | ||||||
|
||||||
wg.Add(1) | ||||||
go func(cc conn) { | ||||||
defer wg.Done() | ||||||
|
||||||
timeout := c.opt.Dialer.Timeout | ||||||
if timeout <= 0 { | ||||||
timeout = DefaultDialTimeout | ||||||
} | ||||||
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout) | ||||||
defer cancel() | ||||||
|
||||||
cc.Do(ctx, cmds.NewCompleted([]string{"READONLY"})) // ignore error | ||||||
}(cc) | ||||||
|
||||||
conns[addr] = connrole{ | ||||||
conn: cc, | ||||||
replica: true, | ||||||
} | ||||||
} | ||||||
} | ||||||
// make sure InitAddress always be present | ||||||
|
@@ -236,12 +263,14 @@ func (c *clusterClient) _refresh() (err error) { | |||||
} | ||||||
} | ||||||
} | ||||||
wg.Wait() | ||||||
|
||||||
var removes []conn | ||||||
|
||||||
c.mu.RLock() | ||||||
for addr, cc := range c.conns { | ||||||
if fresh, ok := conns[addr]; ok { | ||||||
fresh, ok := conns[addr] | ||||||
if ok && cc.replica == fresh.replica { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can still reuse the conn if c.opt.SendToReplicas is not configured. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @proost, thank you very much! It looks great! |
||||||
conns[addr] = connrole{ | ||||||
conn: cc.conn, | ||||||
replica: fresh.replica, | ||||||
|
@@ -256,7 +285,7 @@ func (c *clusterClient) _refresh() (err error) { | |||||
var rslots []conn | ||||||
for master, g := range groups { | ||||||
switch { | ||||||
case c.opt.ReplicaOnly && len(g.nodes) > 1: | ||||||
case c.opt.SendToReplicas == nil && c.opt.ReplicaOnly && len(g.nodes) > 1: | ||||||
nodesCount := len(g.nodes) | ||||||
for _, slot := range g.slots { | ||||||
for i := slot[0]; i <= slot[1]; i++ { | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @proost,
Thank you for the changes, but this goroutine looks wired to me and I don't expect there will be breaking change by reusing the
ReplicaOnly
. I am afraid we have some misunderstanding here.What I previously suggested is that the
pipe
will sendREADONLY
command already if itsReplicaOnly
is true.So I think we can reuse this behavior by modifying the
c.connFn(addr, c.opt)
in the refresh function, and then the above goroutine is not necessary.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that the signature of the
connFn
isfunc(dst string, opt *ClientOption) conn
which accepts a ClientOption pointer, I think we can copy thec.opt
toc.optReplica
with theReplicaOnly
set to true and then we can usec.connFn(addr, c.optReplica)
for replica connections.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
98040d7
@rueian
I'm sorry about serious misunderstanding. I figured out.