@@ -199,27 +199,10 @@ func (p *Pool) Get() Conn {
199
199
// If the function completes without error, then the application must close the
200
200
// returned connection.
201
201
func (p * Pool ) GetContext (ctx context.Context ) (Conn , error ) {
202
- // Handle limit for p.Wait == true.
203
- var waited time.Duration
204
- if p .Wait && p .MaxActive > 0 {
205
- p .lazyInit ()
206
-
207
- // wait indicates if we believe it will block so its not 100% accurate
208
- // however for stats it should be good enough.
209
- wait := len (p .ch ) == 0
210
- var start time.Time
211
- if wait {
212
- start = time .Now ()
213
- }
214
- select {
215
- case <- p .ch :
216
- case <- ctx .Done ():
217
- err := ctx .Err ()
218
- return errorConn {err }, err
219
- }
220
- if wait {
221
- waited = time .Since (start )
222
- }
202
+ // Wait until there is a vacant connection in the pool.
203
+ waited , err := p .waitVacantConn (ctx )
204
+ if err != nil {
205
+ return nil , err
223
206
}
224
207
225
208
p .mu .Lock ()
@@ -376,6 +359,51 @@ func (p *Pool) lazyInit() {
376
359
p .mu .Unlock ()
377
360
}
378
361
362
+ // waitVacantConn waits for a vacant connection in pool if waiting
363
+ // is enabled and pool size is limited, otherwise returns instantly.
364
+ // If ctx expires before that, an error is returned.
365
+ //
366
+ // If there were no vacant connection in the pool right away it returns the time spent waiting
367
+ // for that connection to appear in the pool.
368
+ func (p * Pool ) waitVacantConn (ctx context.Context ) (waited time.Duration , err error ) {
369
+ if ! p .Wait || p .MaxActive <= 0 {
370
+ // No wait or no connection limit.
371
+ return 0 , nil
372
+ }
373
+
374
+ p .lazyInit ()
375
+
376
+ // wait indicates if we believe it will block so its not 100% accurate
377
+ // however for stats it should be good enough.
378
+ wait := len (p .ch ) == 0
379
+ var start time.Time
380
+ if wait {
381
+ start = time .Now ()
382
+ }
383
+
384
+ if ctx == nil {
385
+ <- p .ch
386
+ } else {
387
+ select {
388
+ case <- p .ch :
389
+ // Additionally check that context hasn't expired while we were waiting,
390
+ // because `select` picks a random `case` if several of them are "ready".
391
+ select {
392
+ case <- ctx .Done ():
393
+ return 0 , ctx .Err ()
394
+ default :
395
+ }
396
+ case <- ctx .Done ():
397
+ return 0 , ctx .Err ()
398
+ }
399
+ }
400
+
401
+ if wait {
402
+ return time .Since (start ), nil
403
+ }
404
+ return 0 , nil
405
+ }
406
+
379
407
func (p * Pool ) dial (ctx context.Context ) (Conn , error ) {
380
408
if p .DialContext != nil {
381
409
return p .DialContext (ctx )
0 commit comments