@@ -11,9 +11,18 @@ import (
1111
1212 "github.com/zeebo/errs"
1313
14+ "storj.io/drpc"
1415 "storj.io/drpc/drpcdebug"
1516)
1617
18+ // PoolMetrics holds optional metrics for connection pool monitoring.
19+ type PoolMetrics struct {
20+ PoolSize drpc.Gauge
21+ ConnectionHitsTotal drpc.Counter
22+ ConnectionMissesTotal drpc.Counter
23+ ConnectionAgeSeconds drpc.Observer
24+ }
25+
1726// Options contains the options to configure a pool.
1827type Options struct {
1928 // Expiration will remove any values from the Pool after the
@@ -28,6 +37,10 @@ type Options struct {
2837 // the Pool holds unlimited for any single key. Negative means
2938 // no values for any single key.
3039 KeyCapacity int
40+
41+ // Metrics holds optional metrics the pool will populate. If nil,
42+ // no metrics are recorded.
43+ Metrics * PoolMetrics
3144}
3245
3346// Pool is a connection pool with key type K. It maintains a cache of connections
@@ -49,6 +62,30 @@ func New[K comparable, V Conn](opts Options) *Pool[K, V] {
4962 }
5063}
5164
65+ func (p * Pool [K , V ]) recordHit (created time.Time ) {
66+ if p .opts .Metrics == nil {
67+ return
68+ }
69+ if p .opts .Metrics .ConnectionHitsTotal != nil {
70+ p .opts .Metrics .ConnectionHitsTotal .Add (nil , 1 )
71+ }
72+ if p .opts .Metrics .ConnectionAgeSeconds != nil {
73+ p .opts .Metrics .ConnectionAgeSeconds .Observe (nil , time .Since (created ).Seconds ())
74+ }
75+ }
76+
77+ func (p * Pool [K , V ]) recordMiss () {
78+ if p .opts .Metrics != nil && p .opts .Metrics .ConnectionMissesTotal != nil {
79+ p .opts .Metrics .ConnectionMissesTotal .Add (nil , 1 )
80+ }
81+ }
82+
83+ func (p * Pool [K , V ]) recordPoolSizeChange (delta float64 ) {
84+ if p .opts .Metrics != nil && p .opts .Metrics .PoolSize != nil {
85+ p .opts .Metrics .PoolSize .Add (nil , delta )
86+ }
87+ }
88+
5289func (p * Pool [K , V ]) log (what string , cb func () string ) {
5390 if drpcdebug .Enabled {
5491 drpcdebug .Log (func () (_ , _ , _ string ) { return fmt .Sprintf ("<pül %p>" , p ), what , cb () })
@@ -62,12 +99,14 @@ func (p *Pool[K, V]) Close() (err error) {
6299 defer p .mu .Unlock ()
63100
64101 var eg errs.Group
102+ count := p .order .count
65103 for ent := p .order .head ; ent != nil ; ent = ent .global .next {
66104 eg .Add (p .closeEntry (ent ))
67105 }
68106
69107 p .entries = make (map [K ]* list [K , V ])
70108 p .order = list [K , V ]{}
109+ p .recordPoolSizeChange (- float64 (count ))
71110
72111 return eg .Err ()
73112}
@@ -99,6 +138,7 @@ func (p *Pool[K, V]) removeEntry(ent *entry[K, V]) {
99138
100139 local .removeEntry (ent , (* entry [K , V ]).localList )
101140 p .order .removeEntry (ent , (* entry [K , V ]).globalList )
141+ p .recordPoolSizeChange (- 1 )
102142
103143 if local .count == 0 {
104144 delete (p .entries , ent .key )
@@ -123,6 +163,7 @@ func (p *Pool[K, V]) Take(key K) (V, bool) {
123163
124164 local := p .entries [key ]
125165 if local == nil {
166+ p .recordMiss ()
126167 return * new (V ), false
127168 }
128169
@@ -137,6 +178,7 @@ func (p *Pool[K, V]) Take(key K) (V, bool) {
137178
138179 local .removeEntry (ent , (* entry [K , V ]).localList )
139180 p .order .removeEntry (ent , (* entry [K , V ]).globalList )
181+ p .recordPoolSizeChange (- 1 )
140182
141183 if ent .exp != nil && ! ent .exp .Stop () {
142184 continue
@@ -145,9 +187,11 @@ func (p *Pool[K, V]) Take(key K) (V, bool) {
145187 }
146188
147189 p .log ("TAKEN" , ent .String )
190+ p .recordHit (ent .created )
148191 return ent .val , true
149192 }
150193
194+ p .recordMiss ()
151195 return * new (V ), false
152196}
153197
@@ -177,6 +221,7 @@ func (p *Pool[K, V]) Put(key K, val V) {
177221
178222 local .removeEntry (ent , (* entry [K , V ]).localList )
179223 p .order .removeEntry (ent , (* entry [K , V ]).globalList )
224+ p .recordPoolSizeChange (- 1 )
180225 }
181226
182227 for p .opts .Capacity != 0 && p .order .count >= p .opts .Capacity {
@@ -187,15 +232,17 @@ func (p *Pool[K, V]) Put(key K, val V) {
187232
188233 local .removeEntry (ent , (* entry [K , V ]).localList )
189234 p .order .removeEntry (ent , (* entry [K , V ]).globalList )
235+ p .recordPoolSizeChange (- 1 )
190236
191237 if local .count == 0 {
192238 delete (p .entries , ent .key )
193239 }
194240 }
195241
196- ent := & entry [K , V ]{key : key , val : val }
242+ ent := & entry [K , V ]{key : key , val : val , created : time . Now () }
197243 local .appendEntry (ent , (* entry [K , V ]).localList )
198244 p .order .appendEntry (ent , (* entry [K , V ]).globalList )
245+ p .recordPoolSizeChange (1 )
199246 p .log ("PUT" , ent .String )
200247
201248 if p .opts .Expiration > 0 {
0 commit comments