clientv3: fix deadlock on Get with concurrent Close

This commit is contained in:
Anthony Romano 2016-05-31 13:20:36 -07:00
parent 7709cd84bb
commit 1d88130522
2 changed files with 10 additions and 14 deletions

View File

@ -288,25 +288,19 @@ func TestKVGetErrConnClosed(t *testing.T) {
cli := clus.Client(0) cli := clus.Client(0)
kv := clientv3.NewKV(cli) kv := clientv3.NewKV(cli)
closed, donec := make(chan struct{}), make(chan struct{}) donec := make(chan struct{})
go func() { go func() {
select { defer close(donec)
case <-time.After(3 * time.Second): _, err := kv.Get(context.TODO(), "foo")
t.Fatal("cli.Close took too long") if err != nil && err != rpctypes.ErrConnClosed {
case <-closed:
}
if _, err := kv.Get(context.TODO(), "foo"); err != rpctypes.ErrConnClosed {
t.Fatalf("expected %v, got %v", rpctypes.ErrConnClosed, err) t.Fatalf("expected %v, got %v", rpctypes.ErrConnClosed, err)
} }
close(donec)
}() }()
if err := cli.Close(); err != nil { if err := cli.Close(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
clus.TakeClient(0) clus.TakeClient(0)
close(closed)
select { select {
case <-time.After(3 * time.Second): case <-time.After(3 * time.Second):

View File

@ -80,21 +80,23 @@ func (r *remoteClient) tryUpdate() bool {
return true return true
} }
// acquire gets the client read lock on an established connection or
// returns an error without holding the lock.
func (r *remoteClient) acquire(ctx context.Context) error { func (r *remoteClient) acquire(ctx context.Context) error {
for { for {
r.mu.Lock()
r.client.mu.RLock() r.client.mu.RLock()
closed := r.client.cancel == nil closed := r.client.cancel == nil
c := r.client.conn c := r.client.conn
r.mu.Lock()
match := r.conn == c match := r.conn == c
r.mu.Unlock() r.mu.Unlock()
if closed {
return rpctypes.ErrConnClosed
}
if match { if match {
return nil return nil
} }
r.client.mu.RUnlock() r.client.mu.RUnlock()
if closed {
return rpctypes.ErrConnClosed
}
if err := r.reconnectWait(ctx, nil); err != nil { if err := r.reconnectWait(ctx, nil); err != nil {
return err return err
} }