Skip to content

Commit ee7a48e

Browse files
committed
feat: add connection waiting statistics
1 parent 182a04f commit ee7a48e

File tree

2 files changed

+50
-13
lines changed

2 files changed

+50
-13
lines changed

internal/pool/pool.go

+15-7
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ var timers = sync.Pool{
3333

3434
// Stats contains pool state information and accumulated stats.
3535
type Stats struct {
36-
Hits uint32 // number of times free connection was found in the pool
37-
Misses uint32 // number of times free connection was NOT found in the pool
38-
Timeouts uint32 // number of times a wait timeout occurred
36+
Hits uint32 // number of times free connection was found in the pool
37+
Misses uint32 // number of times free connection was NOT found in the pool
38+
Timeouts uint32 // number of times a wait timeout occurred
39+
WaitCount uint32 // number of times a connection was waited
40+
WaitDurationNs int64 // total time spent for waiting a connection in nanoseconds
3941

4042
TotalConns uint32 // number of total connections in the pool
4143
IdleConns uint32 // number of idle connections in the pool
@@ -90,7 +92,8 @@ type ConnPool struct {
9092
poolSize int
9193
idleConnsLen int
9294

93-
stats Stats
95+
stats Stats
96+
waitDurationNs atomic.Int64
9497

9598
_closed uint32 // atomic
9699
}
@@ -320,6 +323,7 @@ func (p *ConnPool) waitTurn(ctx context.Context) error {
320323
default:
321324
}
322325

326+
start := time.Now()
323327
timer := timers.Get().(*time.Timer)
324328
timer.Reset(p.cfg.PoolTimeout)
325329

@@ -331,6 +335,8 @@ func (p *ConnPool) waitTurn(ctx context.Context) error {
331335
timers.Put(timer)
332336
return ctx.Err()
333337
case p.queue <- struct{}{}:
338+
p.waitDurationNs.Add(time.Since(start).Nanoseconds())
339+
atomic.AddUint32(&p.stats.WaitCount, 1)
334340
if !timer.Stop() {
335341
<-timer.C
336342
}
@@ -457,9 +463,11 @@ func (p *ConnPool) IdleLen() int {
457463

458464
func (p *ConnPool) Stats() *Stats {
459465
return &Stats{
460-
Hits: atomic.LoadUint32(&p.stats.Hits),
461-
Misses: atomic.LoadUint32(&p.stats.Misses),
462-
Timeouts: atomic.LoadUint32(&p.stats.Timeouts),
466+
Hits: atomic.LoadUint32(&p.stats.Hits),
467+
Misses: atomic.LoadUint32(&p.stats.Misses),
468+
Timeouts: atomic.LoadUint32(&p.stats.Timeouts),
469+
WaitCount: atomic.LoadUint32(&p.stats.WaitCount),
470+
WaitDurationNs: p.waitDurationNs.Load(),
463471

464472
TotalConns: uint32(p.Len()),
465473
IdleConns: uint32(p.IdleLen()),

internal/pool/pool_test.go

+35-6
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,14 @@ var _ = Describe("ConnPool", func() {
5959
time.Sleep(time.Second)
6060

6161
Expect(connPool.Stats()).To(Equal(&pool.Stats{
62-
Hits: 0,
63-
Misses: 0,
64-
Timeouts: 0,
65-
TotalConns: 0,
66-
IdleConns: 0,
67-
StaleConns: 0,
62+
Hits: 0,
63+
Misses: 0,
64+
Timeouts: 0,
65+
WaitCount: 0,
66+
WaitDurationNs: 0,
67+
TotalConns: 0,
68+
IdleConns: 0,
69+
StaleConns: 0,
6870
}))
6971
})
7072

@@ -358,4 +360,31 @@ var _ = Describe("race", func() {
358360
Expect(stats.IdleConns).To(Equal(uint32(0)))
359361
Expect(stats.TotalConns).To(Equal(uint32(opt.PoolSize)))
360362
})
363+
364+
It("wait", func() {
365+
opt := &pool.Options{
366+
Dialer: func(ctx context.Context) (net.Conn, error) {
367+
return &net.TCPConn{}, nil
368+
},
369+
PoolSize: 1,
370+
PoolTimeout: 3 * time.Second,
371+
}
372+
p := pool.NewConnPool(opt)
373+
374+
wait := make(chan struct{})
375+
conn, _ := p.Get(ctx)
376+
go func() {
377+
_, _ = p.Get(ctx)
378+
wait <- struct{}{}
379+
}()
380+
time.Sleep(time.Second)
381+
p.Put(ctx, conn)
382+
<-wait
383+
384+
stats := p.Stats()
385+
Expect(stats.IdleConns).To(Equal(uint32(0)))
386+
Expect(stats.TotalConns).To(Equal(uint32(1)))
387+
Expect(stats.WaitCount).To(Equal(uint32(1)))
388+
Expect(stats.WaitDurationNs).To(BeNumerically("~", time.Second.Nanoseconds(), 100*time.Millisecond.Nanoseconds()))
389+
})
361390
})

0 commit comments

Comments
 (0)