@@ -1091,8 +1091,8 @@ func (ac *addrConn) updateAddrs(addrs []resolver.Address) {
10911091 ac .cancel ()
10921092 ac .ctx , ac .cancel = context .WithCancel (ac .cc .ctx )
10931093
1094- // We have to defer here because GracefulClose => Close => onClose, which
1095- // requires locking ac.mu.
1094+ // We have to defer here because GracefulClose => onClose, which requires
1095+ // locking ac.mu.
10961096 if ac .transport != nil {
10971097 defer ac .transport .GracefulClose ()
10981098 ac .transport = nil
@@ -1680,16 +1680,7 @@ func (ac *addrConn) tearDown(err error) {
16801680 ac .updateConnectivityState (connectivity .Shutdown , nil )
16811681 ac .cancel ()
16821682 ac .curAddr = resolver.Address {}
1683- if err == errConnDrain && curTr != nil {
1684- // GracefulClose(...) may be executed multiple times when
1685- // i) receiving multiple GoAway frames from the server; or
1686- // ii) there are concurrent name resolver/Balancer triggered
1687- // address removal and GoAway.
1688- // We have to unlock and re-lock here because GracefulClose => Close => onClose, which requires locking ac.mu.
1689- ac .mu .Unlock ()
1690- curTr .GracefulClose ()
1691- ac .mu .Lock ()
1692- }
1683+
16931684 channelz .AddTraceEvent (logger , ac .channelzID , 0 , & channelz.TraceEventDesc {
16941685 Desc : "Subchannel deleted" ,
16951686 Severity : channelz .CtInfo ,
@@ -1703,6 +1694,29 @@ func (ac *addrConn) tearDown(err error) {
17031694 // being deleted right away.
17041695 channelz .RemoveEntry (ac .channelzID )
17051696 ac .mu .Unlock ()
1697+
1698+ // We have to release the lock before the call to GracefulClose/Close here
1699+ // because both of them call onClose(), which requires locking ac.mu.
1700+ if curTr != nil {
1701+ if err == errConnDrain {
1702+ // Close the transport gracefully when the subConn is being shutdown.
1703+ //
1704+ // GracefulClose() may be executed multiple times if:
1705+ // - multiple GoAway frames are received from the server
1706+ // - there are concurrent name resolver or balancer triggered
1707+ // address removal and GoAway
1708+ curTr .GracefulClose ()
1709+ } else {
1710+ // Hard close the transport when the channel is entering idle or is
1711+ // being shutdown. In the case where the channel is being shutdown,
1712+ // closing of transports is also taken care of by cancelation of cc.ctx.
1713+ // But in the case where the channel is entering idle, we need to
1714+ // explicitly close the transports here. Instead of distinguishing
1715+ // between these two cases, it is simpler to close the transport
1716+ // unconditionally here.
1717+ curTr .Close (err )
1718+ }
1719+ }
17061720}
17071721
17081722func (ac * addrConn ) getState () connectivity.State {
0 commit comments