Skip to content

Commit 9539876

Browse files
committed
core/connpool: scrub lazily on Put()
unclear if timer.Ticker would force wake up and/or prevent sleep
1 parent a2ceb84 commit 9539876

File tree

1 file changed

+45
-30
lines changed

1 file changed

+45
-30
lines changed

intra/core/connpool.go

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ import (
2121
"golang.org/x/sys/unix"
2222
)
2323

24-
const useread = false // always false; here for doc purposes
25-
const poolcapacity = 8 // default capacity
26-
const maxattempts = poolcapacity / 2 // max attempts to retrieve a conn from pool
27-
const Nobody = uintptr(0) // nobody
24+
const useread = false // always false; here for doc purposes
25+
const poolcapacity = 8 // default capacity
26+
const maxattempts = poolcapacity / 2 // max attempts to retrieve a conn from pool
27+
const Nobody = uintptr(0) // nobody
28+
const scrubinterval = 5 * time.Minute // interval between subsequent scrubs
2829

2930
var errUnexpectedRead error = errors.New("pool: unexpected read")
3031

@@ -34,42 +35,55 @@ type superpool[T comparable] struct {
3435
}
3536

3637
type MultConnPool[T comparable] struct {
37-
ctx context.Context
38-
mu sync.RWMutex
39-
m map[T]*superpool[T]
38+
ctx context.Context
39+
mu sync.RWMutex
40+
m map[T]*superpool[T]
41+
scrubtime time.Time
4042
}
4143

4244
func NewMultConnPool[T comparable](ctx context.Context) *MultConnPool[T] {
43-
mc := &MultConnPool[T]{
45+
return &MultConnPool[T]{
4446
ctx: ctx,
4547
m: make(map[T]*superpool[T]),
4648
}
47-
every10m := time.NewTicker(10 * time.Minute)
48-
go mc.scrub(ctx, every10m)
49-
return mc
5049
}
5150

52-
func (m *MultConnPool[T]) scrub(ctx context.Context, tick *time.Ticker) {
53-
defer tick.Stop()
54-
for {
55-
select {
56-
case <-ctx.Done():
57-
return
58-
case <-tick.C:
59-
m.mu.Lock()
60-
for id, super := range m.m {
61-
if !super.pool.closed.Load() {
62-
delete(m.m, id)
63-
} else if super.pool.empty() {
64-
super.quit()
65-
delete(m.m, id)
66-
} else {
67-
go super.pool.scrub()
68-
}
51+
func (m *MultConnPool[T]) scrub() {
52+
now := time.Now()
53+
if now.Sub(m.scrubtime) <= scrubinterval { // too soon
54+
return
55+
}
56+
m.scrubtime = now
57+
58+
select {
59+
case <-m.ctx.Done():
60+
return
61+
default:
62+
}
63+
64+
Go("superpool.scrub", func() {
65+
m.mu.Lock()
66+
defer m.mu.Unlock()
67+
68+
var n, nclosed, nquit, nscrubbed int
69+
n = len(m.m)
70+
for id, super := range m.m {
71+
if super.pool.closed.Load() {
72+
nclosed++
73+
delete(m.m, id)
74+
} else if super.pool.empty() {
75+
nquit++
76+
super.quit()
77+
delete(m.m, id)
78+
} else {
79+
nscrubbed++
80+
Go("poo.scrub", super.pool.scrub)
6981
}
70-
m.mu.Unlock()
7182
}
72-
}
83+
84+
log.D("pool: scrubbed: %d, closed: %d, quit: %d, total: %d",
85+
nscrubbed, nclosed, nquit, n)
86+
})
7387
}
7488

7589
func (m *MultConnPool[T]) Get(id T) net.Conn {
@@ -106,6 +120,7 @@ func (m *MultConnPool[T]) Put(id T, conn net.Conn) bool {
106120
m.mu.Unlock()
107121
}
108122

123+
m.scrub()
109124
return super.pool.Put(conn)
110125
}
111126

0 commit comments

Comments
 (0)