github.com/searKing/golang/go@v1.2.117/sync/lru_pool.want_resource.go (about)

     1  // Copyright 2021 The searKing Author. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package sync
     6  
     7  import (
     8  	"context"
     9  	"sync"
    10  )
    11  
    12  // A wantResource records state about a wanted resource.
    13  // The resource may be gotten by New() or by finding an idle resource,
    14  // or a cancellation may make the resource no longer wanted.
    15  // These three options are racing against each other and use
    16  // wantResource to coordinate and agree about the winning outcome.
    17  type wantResource struct {
    18  	req   any
    19  	key   any             // cm.key()
    20  	ctx   context.Context // context for New
    21  	ready chan struct{}   // closed when pr, err pair is delivered
    22  
    23  	mu  sync.Mutex // protects pr, err, close(ready)
    24  	pr  *PersistResource
    25  	err error
    26  }
    27  
    28  // waiting reports whether w is still waiting for an answer (connection or error).
    29  func (w *wantResource) waiting() bool {
    30  	select {
    31  	case <-w.ready:
    32  		return false
    33  	default:
    34  		return true
    35  	}
    36  }
    37  
    38  // deliveredLock returns whether resource has been delivered already.
    39  func (w *wantResource) deliveredLock() bool {
    40  	return w.pr != nil || w.err != nil
    41  }
    42  
    43  // tryDeliver attempts to deliver pr, err to w and reports whether it succeeded.
    44  func (w *wantResource) tryDeliver(pr *PersistResource, err error) bool {
    45  	w.mu.Lock()
    46  	defer w.mu.Unlock()
    47  
    48  	if w.deliveredLock() {
    49  		return false
    50  	}
    51  
    52  	// deliver and notify delivered event
    53  	w.pr = pr
    54  	w.err = err
    55  	if w.pr == nil && w.err == nil {
    56  		panic("sync: internal error: misuse of tryDeliver")
    57  	}
    58  	close(w.ready)
    59  	return true
    60  }
    61  
    62  // cancel marks w as no longer wanting a result (for example, due to cancellation).
    63  // If a connection has been delivered already, cancel returns it with t.putOrCloseIdleResource.
    64  func (w *wantResource) cancel(t *LruPool, err error) {
    65  	w.mu.Lock()
    66  	if !w.deliveredLock() {
    67  		// notify deliver cancelled event
    68  		close(w.ready) // catch misbehavior in future delivery
    69  	}
    70  
    71  	// deliver and notify delivered event
    72  	pc := w.pr
    73  	w.pr = nil
    74  	w.err = err // not nil always
    75  	w.mu.Unlock()
    76  
    77  	if pc != nil {
    78  		t.putOrCloseIdleResource(pc)
    79  	}
    80  }