@@ -21,10 +21,11 @@ import (
21
21
"golang.org/x/sys/unix"
22
22
)
23
23
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
28
29
29
30
var errUnexpectedRead error = errors .New ("pool: unexpected read" )
30
31
@@ -34,42 +35,55 @@ type superpool[T comparable] struct {
34
35
}
35
36
36
37
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
40
42
}
41
43
42
44
func NewMultConnPool [T comparable ](ctx context.Context ) * MultConnPool [T ] {
43
- mc := & MultConnPool [T ]{
45
+ return & MultConnPool [T ]{
44
46
ctx : ctx ,
45
47
m : make (map [T ]* superpool [T ]),
46
48
}
47
- every10m := time .NewTicker (10 * time .Minute )
48
- go mc .scrub (ctx , every10m )
49
- return mc
50
49
}
51
50
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 )
69
81
}
70
- m .mu .Unlock ()
71
82
}
72
- }
83
+
84
+ log .D ("pool: scrubbed: %d, closed: %d, quit: %d, total: %d" ,
85
+ nscrubbed , nclosed , nquit , n )
86
+ })
73
87
}
74
88
75
89
func (m * MultConnPool [T ]) Get (id T ) net.Conn {
@@ -106,6 +120,7 @@ func (m *MultConnPool[T]) Put(id T, conn net.Conn) bool {
106
120
m .mu .Unlock ()
107
121
}
108
122
123
+ m .scrub ()
109
124
return super .pool .Put (conn )
110
125
}
111
126
0 commit comments