Repository: grpc/grpc-go
File: internal/xds/balancer/clusterresolver/resource_resolver_dns.go (Go)

Code before:
}

// The definition of stop() mentions that implementations must not invoke any
// methods on the topLevelResolver once the call to `stop()` returns. The
// underlying dns resolver does not send any updates to the resolver.ClientConn
// interface passed to it (implemented by dnsDiscoveryMechanism in this case)
// after its `Close()` returns. Therefore, we can guarantee that no methods of
// the topLevelResolver are invoked after we return from this method.
func (dr *dnsDiscoveryMechanism) stop() {
	if dr.dnsR != nil {
		dr.dnsR.Close()
	}
}

// dnsDiscoveryMechanism needs to implement resolver.ClientConn interface to receive
// updates from the real DNS resolver.

func (dr *dnsDiscoveryMechanism) UpdateState(state resolver.State) error {
	if dr.logger.V(2) {
		dr.logger.Infof("DNS discovery mechanism for resource %q reported an update: %s", dr.target, pretty.ToJSON(state))
	}

	dr.mu.Lock()
	var endpoints = state.Endpoints
	if len(endpoints) == 0 {
		endpoints = []resolver.Endpoint{{Addresses: state.Addresses}}
	}
	dr.endpoints = endpoints
	dr.updateReceived = true
	dr.mu.Unlock()

	dr.topLevelResolver.onUpdate(func() {})
	return nil
}

func (dr *dnsDiscoveryMechanism) ReportError(err error) {
	if dr.logger.V(2) {
		dr.logger.Infof("DNS discovery mechanism for resource %q reported error: %v", dr.target, err)
	}

	dr.mu.Lock()
	// If a previous good update was received, suppress the error and continue
	// using the previous update. If RPCs were succeeding prior to this, they
	// will continue to do so. Also suppress errors if we previously received an
	// error, since there will be no downstream effects of propagating this
	// error.
	if dr.updateReceived {
		dr.mu.Unlock()
		return
	}
	dr.endpoints = nil

Review comment (bug):
@arjan-bal recently made a change https://github.com/grpc/grpc-go/pull/8812 to ensure that the DNS resolver returns endpoints. So, I think we don't need a special case here for `len(endpoints) == 0`. Please correct me if I'm wrong.

Code after:
}

// The definition of stop() mentions that implementations must not invoke any
// methods on the topLevelResolver once the call to `stop()` returns. The
// underlying dns resolver does not send any updates to the resolver.ClientConn
// interface passed to it (implemented by dnsDiscoveryMechanism in this case)
// after its `Close()` returns. Therefore, we can guarantee that no methods of
// the topLevelResolver are invoked after we return from this method.
func (dr *dnsDiscoveryMechanism) stop() {
	if dr.dnsR != nil {
		dr.dnsR.Close()
	}
}

// dnsDiscoveryMechanism needs to implement resolver.ClientConn interface to receive
// updates from the real DNS resolver.

func (dr *dnsDiscoveryMechanism) UpdateState(state resolver.State) error {
	if dr.logger.V(2) {
		dr.logger.Infof("DNS discovery mechanism for resource %q reported an update: %s", dr.target, pretty.ToJSON(state))
	}

	dr.mu.Lock()
	dr.endpoints = state.Endpoints
	dr.updateReceived = true
	dr.mu.Unlock()

	dr.topLevelResolver.onUpdate(func() {})
	return nil
}

func (dr *dnsDiscoveryMechanism) ReportError(err error) {
	if dr.logger.V(2) {
		dr.logger.Infof("DNS discovery mechanism for resource %q reported error: %v", dr.target, err)
	}

	dr.mu.Lock()
	// If a previous good update was received, suppress the error and continue
	// using the previous update. If RPCs were succeeding prior to this, they
	// will continue to do so. Also suppress errors if we previously received an
	// error, since there will be no downstream effects of propagating this
	// error.
	if dr.updateReceived {
		dr.mu.Unlock()
		return
	}
	dr.endpoints = nil
	dr.updateReceived = true
	dr.mu.Unlock()

	dr.topLevelResolver.onUpdate(func() {})