Skip to content

Commit 2cf8d45

Browse files
committed
feat: add connection waiting statistics
1 parent 21bd40a commit 2cf8d45

File tree

2 files changed

+48
-12
lines changed

2 files changed

+48
-12
lines changed

internal/pool/pool.go

Lines changed: 13 additions & 6 deletions
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
@@ -304,6 +306,7 @@ func (p *ConnPool) waitTurn(ctx context.Context) error {
304306
default:
305307
}
306308

309+
start := time.Now()
307310
timer := timers.Get().(*time.Timer)
308311
timer.Reset(p.cfg.PoolTimeout)
309312

@@ -315,6 +318,8 @@ func (p *ConnPool) waitTurn(ctx context.Context) error {
315318
timers.Put(timer)
316319
return ctx.Err()
317320
case p.queue <- struct{}{}:
321+
atomic.AddInt64(&p.stats.WaitDurationNs, time.Since(start).Nanoseconds())
322+
atomic.AddUint32(&p.stats.WaitCount, 1)
318323
if !timer.Stop() {
319324
<-timer.C
320325
}
@@ -441,9 +446,11 @@ func (p *ConnPool) IdleLen() int {
441446

442447
func (p *ConnPool) Stats() *Stats {
443448
return &Stats{
444-
Hits: atomic.LoadUint32(&p.stats.Hits),
445-
Misses: atomic.LoadUint32(&p.stats.Misses),
446-
Timeouts: atomic.LoadUint32(&p.stats.Timeouts),
449+
Hits: atomic.LoadUint32(&p.stats.Hits),
450+
Misses: atomic.LoadUint32(&p.stats.Misses),
451+
Timeouts: atomic.LoadUint32(&p.stats.Timeouts),
452+
WaitCount: atomic.LoadUint32(&p.stats.WaitCount),
453+
WaitDurationNs: atomic.LoadInt64(&p.stats.WaitDurationNs),
447454

448455
TotalConns: uint32(p.Len()),
449456
IdleConns: uint32(p.IdleLen()),

internal/pool/pool_test.go

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,14 @@ var _ = Describe("ConnPool", func() {
5757
time.Sleep(time.Second)
5858

5959
Expect(connPool.Stats()).To(Equal(&pool.Stats{
60-
Hits: 0,
61-
Misses: 0,
62-
Timeouts: 0,
63-
TotalConns: 0,
64-
IdleConns: 0,
65-
StaleConns: 0,
60+
Hits: 0,
61+
Misses: 0,
62+
Timeouts: 0,
63+
WaitCount: 0,
64+
WaitDurationNs: 0,
65+
TotalConns: 0,
66+
IdleConns: 0,
67+
StaleConns: 0,
6668
}))
6769
})
6870

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

0 commit comments

Comments
 (0)