gitee.com/h79/goutils@v1.22.10/thrift/client/resolver_conn_wrapper.go (about)

     1  package client
     2  
     3  import (
     4  	"gitee.com/h79/goutils/common/system"
     5  	"gitee.com/h79/goutils/thrift/resolver"
     6  	"sync"
     7  	"time"
     8  )
     9  
    10  type ccResolverWrapper struct {
    11  	cc         *Client
    12  	resolverMu sync.Mutex
    13  	resolver   resolver.Resolver
    14  	curState   resolver.State
    15  	done       *system.Event
    16  	pollingMu  sync.Mutex
    17  	polling    chan struct{}
    18  }
    19  
    20  // newCCResolverWrapper uses the resolver.Builder to build a Resolver and
    21  // returns a ccResolverWrapper object which wraps the newly built resolver.
    22  func newCCResolverWrapper(cc *Client, rb resolver.Builder) (*ccResolverWrapper, error) {
    23  	ccr := &ccResolverWrapper{
    24  		cc:   cc,
    25  		done: system.NewEvent(),
    26  	}
    27  
    28  	var err error
    29  	// We need to hold the lock here while we assign to the ccr.resolver field
    30  	// to guard against a data race caused by the following code path,
    31  	// rb.Build-->ccr.ReportError-->ccr.poll-->ccr.resolveNow, would end up
    32  	// accessing ccr.resolver which is being assigned here.
    33  	ccr.resolverMu.Lock()
    34  	defer ccr.resolverMu.Unlock()
    35  	ccr.resolver, err = rb.Build(cc.parsedTarget, ccr)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	return ccr, nil
    40  }
    41  
    42  func (ccr *ccResolverWrapper) resolveNow() {
    43  	ccr.resolverMu.Lock()
    44  	if !ccr.done.HasFired() {
    45  		ccr.resolver.ResolveNow()
    46  	}
    47  	ccr.resolverMu.Unlock()
    48  }
    49  
    50  func (ccr *ccResolverWrapper) close() {
    51  	ccr.resolverMu.Lock()
    52  	ccr.resolver.Close()
    53  	ccr.done.Fire()
    54  	ccr.resolverMu.Unlock()
    55  }
    56  
    57  func (ccr *ccResolverWrapper) stopPolling() {
    58  	// stop polling
    59  	if ccr.polling != nil {
    60  		close(ccr.polling)
    61  		ccr.polling = nil
    62  	}
    63  }
    64  
    65  // poll begins or ends asynchronous polling of the resolver based on whether
    66  // err is ErrBadResolverState.
    67  func (ccr *ccResolverWrapper) poll(err error) {
    68  	ccr.pollingMu.Lock()
    69  	defer ccr.pollingMu.Unlock()
    70  	if err != nil {
    71  		ccr.stopPolling()
    72  		return
    73  	}
    74  	if ccr.polling != nil {
    75  		// already polling
    76  		return
    77  	}
    78  	p := make(chan struct{})
    79  	ccr.polling = p
    80  	system.ChildRunning(func() {
    81  		for i := 0; ; i++ {
    82  			ccr.resolveNow()
    83  			t := time.NewTimer(time.Second * time.Duration(2+i*5))
    84  			select {
    85  			case <-p:
    86  				t.Stop()
    87  				return
    88  			case <-ccr.done.Done():
    89  				// Resolver has been closed.
    90  				t.Stop()
    91  				return
    92  			case <-t.C:
    93  				select {
    94  				case <-p:
    95  					return
    96  				default:
    97  				}
    98  				// Timer expired; re-resolve.
    99  			case <-system.Closed():
   100  				return
   101  			}
   102  		}
   103  	})
   104  }
   105  
   106  func (ccr *ccResolverWrapper) UpdateState(s resolver.State) {
   107  	if ccr.done.HasFired() {
   108  		return
   109  	}
   110  	ccr.curState = s
   111  	ccr.poll(ccr.cc.updateResolverState(ccr.curState, nil))
   112  }
   113  
   114  func (ccr *ccResolverWrapper) ReportError(err error) {
   115  	if ccr.done.HasFired() {
   116  		return
   117  	}
   118  	ccr.poll(ccr.cc.updateResolverState(resolver.State{}, err))
   119  }
   120  
   121  func (ccr *ccResolverWrapper) NewAddress(adders []resolver.Address) {
   122  	if ccr.done.HasFired() {
   123  		return
   124  	}
   125  
   126  	ccr.curState.Addresses = adders
   127  	ccr.poll(ccr.cc.updateResolverState(ccr.curState, nil))
   128  }