mirror of
https://github.com/hanzokv/go.git
synced 2026-09-24 00:31:51 +00:00
* async create conn * update default values and testcase * fix comments * fix data race * remove context.WithoutCancel, which is a function introduced in Go 1.21 * fix TestDialerRetryConfiguration/DefaultDialerRetries, because tryDial are likely done in async flow * change to share failed to delivery connection to other waiting * remove chinese comment * fix: optimize WantConnQueue benchmarks to prevent memory exhaustion - Fix BenchmarkWantConnQueue_Dequeue timeout issue by limiting pre-population - Use object pooling in BenchmarkWantConnQueue_Enqueue to reduce allocations - Optimize BenchmarkWantConnQueue_EnqueueDequeue with reusable wantConn pool - Prevent GitHub Actions benchmark failures due to excessive memory usage Before: BenchmarkWantConnQueue_Dequeue ran for 11+ minutes and was killed After: All benchmarks complete in ~8 seconds with consistent performance * format * fix turn leaks --------- Co-authored-by: Nedyalko Dyakov <[email protected]> Co-authored-by: Hristo Temelski <[email protected]>
94 lines
1.6 KiB
Go
94 lines
1.6 KiB
Go
package pool
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
)
|
|
|
|
type wantConn struct {
|
|
mu sync.Mutex // protects ctx, done and sending of the result
|
|
ctx context.Context // context for dial, cleared after delivered or canceled
|
|
cancelCtx context.CancelFunc
|
|
done bool // true after delivered or canceled
|
|
result chan wantConnResult // channel to deliver connection or error
|
|
}
|
|
|
|
// getCtxForDial returns context for dial or nil if connection was delivered or canceled.
|
|
func (w *wantConn) getCtxForDial() context.Context {
|
|
w.mu.Lock()
|
|
defer w.mu.Unlock()
|
|
|
|
return w.ctx
|
|
}
|
|
|
|
func (w *wantConn) tryDeliver(cn *Conn, err error) bool {
|
|
w.mu.Lock()
|
|
defer w.mu.Unlock()
|
|
if w.done {
|
|
return false
|
|
}
|
|
|
|
w.done = true
|
|
w.ctx = nil
|
|
|
|
w.result <- wantConnResult{cn: cn, err: err}
|
|
close(w.result)
|
|
|
|
return true
|
|
}
|
|
|
|
func (w *wantConn) cancel() *Conn {
|
|
w.mu.Lock()
|
|
var cn *Conn
|
|
if w.done {
|
|
select {
|
|
case result := <-w.result:
|
|
cn = result.cn
|
|
default:
|
|
}
|
|
} else {
|
|
close(w.result)
|
|
}
|
|
|
|
w.done = true
|
|
w.ctx = nil
|
|
w.mu.Unlock()
|
|
|
|
return cn
|
|
}
|
|
|
|
type wantConnResult struct {
|
|
cn *Conn
|
|
err error
|
|
}
|
|
|
|
type wantConnQueue struct {
|
|
mu sync.RWMutex
|
|
items []*wantConn
|
|
}
|
|
|
|
func newWantConnQueue() *wantConnQueue {
|
|
return &wantConnQueue{
|
|
items: make([]*wantConn, 0),
|
|
}
|
|
}
|
|
|
|
func (q *wantConnQueue) enqueue(w *wantConn) {
|
|
q.mu.Lock()
|
|
defer q.mu.Unlock()
|
|
q.items = append(q.items, w)
|
|
}
|
|
|
|
func (q *wantConnQueue) dequeue() (*wantConn, bool) {
|
|
q.mu.Lock()
|
|
defer q.mu.Unlock()
|
|
|
|
if len(q.items) == 0 {
|
|
return nil, false
|
|
}
|
|
|
|
item := q.items[0]
|
|
q.items = q.items[1:]
|
|
return item, true
|
|
}
|