Skip to content

Commit ea13abf

Browse files
fix: idle connection count logic and added unit test
Signed-off-by: Harshit Gangal <harshit@planetscale.com>
1 parent e8eb29e commit ea13abf

File tree

2 files changed

+52
-10
lines changed

2 files changed

+52
-10
lines changed

go/pools/smartconnpool/pool.go

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -413,14 +413,7 @@ func (pool *ConnPool[C]) put(conn *Pooled[C]) {
413413
}
414414

415415
if !pool.wait.tryReturnConn(conn) {
416-
// Option 1: do not care if more connections are closed than the allowed idle count
417-
if pool.active.Load() > pool.idleCount.Load() {
418-
conn.Close()
419-
pool.closedConn()
420-
return
421-
}
422-
// Option 2: precisely maintain the idle count
423-
if pool.tryClose(conn) {
416+
if pool.closeOnIdleLimitReached(conn) {
424417
return
425418
}
426419

@@ -435,13 +428,17 @@ func (pool *ConnPool[C]) put(conn *Pooled[C]) {
435428
}
436429
}
437430

438-
func (pool *ConnPool[C]) tryClose(conn *Pooled[C]) bool {
431+
// closeOnIdleLimitReached closes a connection if the number of idle connections (active - inuse) in the pool
432+
// exceeds the idleCount limit. It returns true if the connection is closed, false otherwise.
433+
func (pool *ConnPool[C]) closeOnIdleLimitReached(conn *Pooled[C]) bool {
439434
for {
440435
open := pool.active.Load()
441-
if open <= pool.idleCount.Load() {
436+
idle := open - pool.borrowed.Load()
437+
if idle <= pool.idleCount.Load() {
442438
return false
443439
}
444440
if pool.active.CompareAndSwap(open, open-1) {
441+
pool.Metrics.idleClosed.Add(1)
445442
conn.Close()
446443
return true
447444
}

go/pools/smartconnpool/pool_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,51 @@ func TestExtendedLifetimeTimeout(t *testing.T) {
746746
}
747747
}
748748

749+
// TestMaxIdleCount tests the MaxIdleCount setting, to check if the pool closes
750+
// the idle connections when the number of idle connections exceeds the limit.
751+
func TestMaxIdleCount(t *testing.T) {
752+
testMaxIdleCount := func(t *testing.T, setting *Setting, maxIdleCount int64, expClosedConn int) {
753+
var state TestState
754+
755+
ctx := context.Background()
756+
p := NewPool(&Config[*TestConn]{
757+
Capacity: 5,
758+
MaxIdleCount: maxIdleCount,
759+
LogWait: state.LogWait,
760+
}).Open(newConnector(&state), nil)
761+
762+
defer p.Close()
763+
764+
var conns []*Pooled[*TestConn]
765+
for i := 0; i < 5; i++ {
766+
r, err := p.Get(ctx, setting)
767+
require.NoError(t, err)
768+
assert.EqualValues(t, i+1, state.open.Load())
769+
assert.EqualValues(t, 0, p.Metrics.IdleClosed())
770+
771+
conns = append(conns, r)
772+
}
773+
774+
for _, conn := range conns {
775+
p.put(conn)
776+
}
777+
778+
closedConn := 0
779+
for _, conn := range conns {
780+
if conn.Conn.IsClosed() {
781+
closedConn++
782+
}
783+
}
784+
assert.EqualValues(t, expClosedConn, closedConn)
785+
assert.EqualValues(t, expClosedConn, p.Metrics.IdleClosed())
786+
}
787+
788+
t.Run("WithoutSettings", func(t *testing.T) { testMaxIdleCount(t, nil, 2, 3) })
789+
t.Run("WithSettings", func(t *testing.T) { testMaxIdleCount(t, sFoo, 2, 3) })
790+
t.Run("WithoutSettings-MaxIdleCount-Zero", func(t *testing.T) { testMaxIdleCount(t, nil, 0, 0) })
791+
t.Run("WithSettings-MaxIdleCount-Zero", func(t *testing.T) { testMaxIdleCount(t, sFoo, 0, 0) })
792+
}
793+
749794
func TestCreateFail(t *testing.T) {
750795
var state TestState
751796
state.chaos.failConnect = true

0 commit comments

Comments
 (0)