@@ -131,6 +131,9 @@ type ConnPool[C Connection] struct {
131
131
close chan struct {}
132
132
capacityMu sync.Mutex
133
133
134
+ // generation of the pool, this is incremented every time the pool is closed
135
+ generation atomic.Int64
136
+
134
137
config struct {
135
138
// connect is the callback to create a new connection for the pool
136
139
connect Connector [C ]
@@ -395,7 +398,17 @@ func (pool *ConnPool[C]) Get(ctx context.Context, setting *Setting) (*Pooled[C],
395
398
396
399
// put returns a connection to the pool. This is a private API.
397
400
// Return connections to the pool by calling Pooled.Recycle
398
- func (pool * ConnPool [C ]) put (conn * Pooled [C ]) {
401
+ func (pool * ConnPool [C ]) put (conn * Pooled [C ], generation int64 ) {
402
+ // If the generations don't match, just close the connection and return.
403
+ // Don't update any metrics here.
404
+ if generation != pool .generation .Load () {
405
+ if conn != nil {
406
+ conn .Close ()
407
+ }
408
+
409
+ return
410
+ }
411
+
399
412
pool .borrowed .Add (- 1 )
400
413
401
414
if conn == nil {
@@ -524,8 +537,9 @@ func (pool *ConnPool[C]) connNew(ctx context.Context) (*Pooled[C], error) {
524
537
return nil , err
525
538
}
526
539
pooled := & Pooled [C ]{
527
- pool : pool ,
528
- Conn : conn ,
540
+ pool : pool ,
541
+ generation : pool .generation .Load (),
542
+ Conn : conn ,
529
543
}
530
544
now := monotonicNow ()
531
545
pooled .timeUsed .set (now )
@@ -720,32 +734,46 @@ func (pool *ConnPool[C]) setCapacity(ctx context.Context, newcap int64) error {
720
734
// wait for connections to be returned to the pool if we're reducing the capacity.
721
735
defer pool .setIdleCount ()
722
736
723
- const delay = 10 * time .Millisecond
737
+ if newcap == 0 {
738
+ pool .generation .Add (1 )
739
+ pool .active .Store (0 )
740
+ pool .borrowed .Store (0 )
724
741
725
- // close connections until we're under capacity
726
- for pool .active .Load () > newcap {
727
- if err := ctx .Err (); err != nil {
728
- return vterrors .Errorf (vtrpcpb .Code_ABORTED ,
729
- "timed out while waiting for connections to be returned to the pool (capacity=%d, active=%d, borrowed=%d)" ,
730
- pool .capacity .Load (), pool .active .Load (), pool .borrowed .Load ())
731
- }
732
- // if we're closing down the pool, make sure there's no clients waiting
733
- // for connections because they won't be returned in the future
734
- if newcap == 0 {
735
- pool .wait .expire (true )
736
- }
742
+ for {
743
+ conn := pool .getFromSettingsStack (nil )
744
+ if conn == nil {
745
+ conn = pool .pop (& pool .clean )
746
+ }
747
+ if conn == nil {
748
+ break
749
+ }
737
750
738
- // try closing from connections which are currently idle in the stacks
739
- conn := pool .getFromSettingsStack (nil )
740
- if conn == nil {
741
- conn = pool .pop (& pool .clean )
751
+ // Close the connection but don't update the metrics as we've already updated them
752
+ conn .Close ()
742
753
}
743
- if conn == nil {
744
- time .Sleep (delay )
745
- continue
754
+
755
+ pool .wait .expire (true )
756
+ } else {
757
+ const delay = 10 * time .Millisecond
758
+
759
+ // close connections until we're under capacity
760
+ for pool .active .Load () > newcap {
761
+ // try closing from connections which are currently idle in the stacks
762
+ conn := pool .getFromSettingsStack (nil )
763
+ if conn == nil {
764
+ conn = pool .pop (& pool .clean )
765
+ }
766
+
767
+ // Stop the loop if we don't have any more connections to close.
768
+ // Connections that were borrowed by clients and are over capacity
769
+ // will be closed when they are put back into the pool.
770
+ if conn == nil {
771
+ break
772
+ }
773
+
774
+ conn .Close ()
775
+ pool .closedConn ()
746
776
}
747
- conn .Close ()
748
- pool .closedConn ()
749
777
}
750
778
751
779
return nil
0 commit comments