@@ -185,11 +185,9 @@ func NewPool(newFn func() (Conn, error), maxIdle int) *Pool {
185
185
// getting an underlying connection, then the connection Err, Do, Send, Flush
186
186
// and Receive methods return that error.
187
187
func (p * Pool ) Get () Conn {
188
- pc , err := p .get (nil )
189
- if err != nil {
190
- return errorConn {err }
191
- }
192
- return & activeConn {p : p , pc : pc }
188
+ // GetContext returns errorConn in the first argument when an error occurs.
189
+ c , _ := p .GetContext (context .Background ())
190
+ return c
193
191
}
194
192
195
193
// GetContext gets a connection using the provided context.
@@ -201,11 +199,90 @@ func (p *Pool) Get() Conn {
201
199
// If the function completes without error, then the application must close the
202
200
// returned connection.
203
201
func (p * Pool ) GetContext (ctx context.Context ) (Conn , error ) {
204
- pc , err := p .get (ctx )
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
+ }
223
+ }
224
+
225
+ p .mu .Lock ()
226
+
227
+ if waited > 0 {
228
+ p .waitCount ++
229
+ p .waitDuration += waited
230
+ }
231
+
232
+ // Prune stale connections at the back of the idle list.
233
+ if p .IdleTimeout > 0 {
234
+ n := p .idle .count
235
+ for i := 0 ; i < n && p .idle .back != nil && p .idle .back .t .Add (p .IdleTimeout ).Before (nowFunc ()); i ++ {
236
+ pc := p .idle .back
237
+ p .idle .popBack ()
238
+ p .mu .Unlock ()
239
+ pc .c .Close ()
240
+ p .mu .Lock ()
241
+ p .active --
242
+ }
243
+ }
244
+
245
+ // Get idle connection from the front of idle list.
246
+ for p .idle .front != nil {
247
+ pc := p .idle .front
248
+ p .idle .popFront ()
249
+ p .mu .Unlock ()
250
+ if (p .TestOnBorrow == nil || p .TestOnBorrow (pc .c , pc .t ) == nil ) &&
251
+ (p .MaxConnLifetime == 0 || nowFunc ().Sub (pc .created ) < p .MaxConnLifetime ) {
252
+ return & activeConn {p : p , pc : pc }, nil
253
+ }
254
+ pc .c .Close ()
255
+ p .mu .Lock ()
256
+ p .active --
257
+ }
258
+
259
+ // Check for pool closed before dialing a new connection.
260
+ if p .closed {
261
+ p .mu .Unlock ()
262
+ err := errors .New ("redigo: get on closed pool" )
263
+ return errorConn {err }, err
264
+ }
265
+
266
+ // Handle limit for p.Wait == false.
267
+ if ! p .Wait && p .MaxActive > 0 && p .active >= p .MaxActive {
268
+ p .mu .Unlock ()
269
+ return errorConn {ErrPoolExhausted }, ErrPoolExhausted
270
+ }
271
+
272
+ p .active ++
273
+ p .mu .Unlock ()
274
+ c , err := p .dial (ctx )
205
275
if err != nil {
276
+ c = nil
277
+ p .mu .Lock ()
278
+ p .active --
279
+ if p .ch != nil && ! p .closed {
280
+ p .ch <- struct {}{}
281
+ }
282
+ p .mu .Unlock ()
206
283
return errorConn {err }, err
207
284
}
208
- return & activeConn {p : p , pc : pc }, nil
285
+ return & activeConn {p : p , pc : & poolConn { c : c , created : nowFunc ()} }, nil
209
286
}
210
287
211
288
// PoolStats contains pool statistics.
@@ -299,97 +376,6 @@ func (p *Pool) lazyInit() {
299
376
p .mu .Unlock ()
300
377
}
301
378
302
- // get prunes stale connections and returns a connection from the idle list or
303
- // creates a new connection.
304
- func (p * Pool ) get (ctx context.Context ) (* poolConn , error ) {
305
-
306
- // Handle limit for p.Wait == true.
307
- var waited time.Duration
308
- if p .Wait && p .MaxActive > 0 {
309
- p .lazyInit ()
310
-
311
- // wait indicates if we believe it will block so its not 100% accurate
312
- // however for stats it should be good enough.
313
- wait := len (p .ch ) == 0
314
- var start time.Time
315
- if wait {
316
- start = time .Now ()
317
- }
318
- if ctx == nil {
319
- <- p .ch
320
- } else {
321
- select {
322
- case <- p .ch :
323
- case <- ctx .Done ():
324
- return nil , ctx .Err ()
325
- }
326
- }
327
- if wait {
328
- waited = time .Since (start )
329
- }
330
- }
331
-
332
- p .mu .Lock ()
333
-
334
- if waited > 0 {
335
- p .waitCount ++
336
- p .waitDuration += waited
337
- }
338
-
339
- // Prune stale connections at the back of the idle list.
340
- if p .IdleTimeout > 0 {
341
- n := p .idle .count
342
- for i := 0 ; i < n && p .idle .back != nil && p .idle .back .t .Add (p .IdleTimeout ).Before (nowFunc ()); i ++ {
343
- pc := p .idle .back
344
- p .idle .popBack ()
345
- p .mu .Unlock ()
346
- pc .c .Close ()
347
- p .mu .Lock ()
348
- p .active --
349
- }
350
- }
351
-
352
- // Get idle connection from the front of idle list.
353
- for p .idle .front != nil {
354
- pc := p .idle .front
355
- p .idle .popFront ()
356
- p .mu .Unlock ()
357
- if (p .TestOnBorrow == nil || p .TestOnBorrow (pc .c , pc .t ) == nil ) &&
358
- (p .MaxConnLifetime == 0 || nowFunc ().Sub (pc .created ) < p .MaxConnLifetime ) {
359
- return pc , nil
360
- }
361
- pc .c .Close ()
362
- p .mu .Lock ()
363
- p .active --
364
- }
365
-
366
- // Check for pool closed before dialing a new connection.
367
- if p .closed {
368
- p .mu .Unlock ()
369
- return nil , errors .New ("redigo: get on closed pool" )
370
- }
371
-
372
- // Handle limit for p.Wait == false.
373
- if ! p .Wait && p .MaxActive > 0 && p .active >= p .MaxActive {
374
- p .mu .Unlock ()
375
- return nil , ErrPoolExhausted
376
- }
377
-
378
- p .active ++
379
- p .mu .Unlock ()
380
- c , err := p .dial (ctx )
381
- if err != nil {
382
- c = nil
383
- p .mu .Lock ()
384
- p .active --
385
- if p .ch != nil && ! p .closed {
386
- p .ch <- struct {}{}
387
- }
388
- p .mu .Unlock ()
389
- }
390
- return & poolConn {c : c , created : nowFunc ()}, err
391
- }
392
-
393
379
func (p * Pool ) dial (ctx context.Context ) (Conn , error ) {
394
380
if p .DialContext != nil {
395
381
return p .DialContext (ctx )
0 commit comments