Repository: grpc/grpc-go
File: balancer/pickfirst/pickfirstleaf/pickfirstleaf.go (Go)

Code before:
			// entering READY. The SubConn should be present in the addressList.
			b.logger.Errorf("Address %q not found address list in  %v", sd.addr, b.addressList.addresses)
			return
		}
		b.state = connectivity.Ready
		b.cc.UpdateState(balancer.State{
			ConnectivityState: connectivity.Ready,
			Picker:            &picker{result: balancer.PickResult{SubConn: sd.subConn}},
		})
		return
	}

	// If the LB policy is READY, and it receives a subchannel state change,
	// it means that the READY subchannel has failed.
	// A SubConn can also transition from CONNECTING directly to IDLE when
	// a transport is successfully created, but the connection fails
	// before the SubConn can send the notification for READY. We treat
	// this as a successful connection and transition to IDLE.
	if (b.state == connectivity.Ready && newState.ConnectivityState != connectivity.Ready) || (oldState == connectivity.Connecting && newState.ConnectivityState == connectivity.Idle) {
		// Once a transport fails, the balancer enters IDLE and starts from
		// the first address when the picker is used.
		b.shutdownRemainingLocked(sd)
		b.state = connectivity.Idle
		// READY SubConn interspliced in between CONNECTING and IDLE, need to
		// account for that.
		if oldState == connectivity.Connecting && newState.ConnectivityState == connectivity.Idle {
			connectionAttemptsSucceeded.Record(b.metricsRecorder, 1, b.target)
		}
		disconnectionsMetric.Record(b.metricsRecorder, 1, b.target)
		b.addressList.reset()
		b.cc.UpdateState(balancer.State{
			ConnectivityState: connectivity.Idle,
			Picker:            &idlePicker{exitIdle: sync.OnceFunc(b.ExitIdle)},
		})
		return
	}

	if b.firstPass {
		switch newState.ConnectivityState {
		case connectivity.Connecting:
			// The balancer can be in either IDLE, CONNECTING or
			// TRANSIENT_FAILURE. If it's in TRANSIENT_FAILURE, stay in
			// TRANSIENT_FAILURE until it's READY. See A62.
			// If the balancer is already in CONNECTING, no update is needed.
			if b.state == connectivity.Idle {
				b.state = connectivity.Connecting
				b.cc.UpdateState(balancer.State{
					ConnectivityState: connectivity.Connecting,
					Picker:            &picker{err: balancer.ErrNoSubConnAvailable},
				})
			}

Review comment (suggestion):
+1 to something like:

```go
if oldState == Connecting {
  // A known issue causes a race that prevents the READY state change notification.  This works around it.
```

Also it would be great if we could create an issue for that problem and link it here so we know to come back and delete this one it's resolved.


Code after:
			return
		}
		b.state = connectivity.Ready
		b.cc.UpdateState(balancer.State{
			ConnectivityState: connectivity.Ready,
			Picker:            &picker{result: balancer.PickResult{SubConn: sd.subConn}},
		})
		return
	}

	// If the LB policy is READY, and it receives a subchannel state change,
	// it means that the READY subchannel has failed.
	// A SubConn can also transition from CONNECTING directly to IDLE when
	// a transport is successfully created, but the connection fails
	// before the SubConn can send the notification for READY. We treat
	// this as a successful connection and transition to IDLE.
	if (b.state == connectivity.Ready && newState.ConnectivityState != connectivity.Ready) || (oldState == connectivity.Connecting && newState.ConnectivityState == connectivity.Idle) {
		// Once a transport fails, the balancer enters IDLE and starts from
		// the first address when the picker is used.
		b.shutdownRemainingLocked(sd)
		b.state = connectivity.Idle
		// READY SubConn interspliced in between CONNECTING and IDLE, need to
		// account for that.
		if oldState == connectivity.Connecting {
			// A known issue (https://github.com/grpc/grpc-go/issues/7862)
			// causes a race that prevents the READY state change notification.
			// This works around it.
			connectionAttemptsSucceededMetric.Record(b.metricsRecorder, 1, b.target)
		}
		disconnectionsMetric.Record(b.metricsRecorder, 1, b.target)
		b.addressList.reset()
		b.cc.UpdateState(balancer.State{
			ConnectivityState: connectivity.Idle,
			Picker:            &idlePicker{exitIdle: sync.OnceFunc(b.ExitIdle)},
		})
		return
	}

	if b.firstPass {
		switch newState.ConnectivityState {
		case connectivity.Connecting:
			// The balancer can be in either IDLE, CONNECTING or
			// TRANSIENT_FAILURE. If it's in TRANSIENT_FAILURE, stay in
			// TRANSIENT_FAILURE until it's READY. See A62.
			// If the balancer is already in CONNECTING, no update is needed.
			if b.state == connectivity.Idle {
				b.state = connectivity.Connecting
				b.cc.UpdateState(balancer.State{
					ConnectivityState: connectivity.Connecting,
					Picker:            &picker{err: balancer.ErrNoSubConnAvailable},
				})