mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
clientv3: fix deadlock on Get with concurrent Close
This commit is contained in:
parent
7709cd84bb
commit
1d88130522
@ -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):
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user