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 }