Skip to content

Commit 0e4c251

Browse files
authored
chore: Simplify Pool.Get (gomodule#478)
Simplify Pool.Get by calling GetContext with context.Background().
1 parent 129455d commit 0e4c251

File tree

1 file changed

+84
-98
lines changed

1 file changed

+84
-98
lines changed

redis/pool.go

Lines changed: 84 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,9 @@ func NewPool(newFn func() (Conn, error), maxIdle int) *Pool {
185185
// getting an underlying connection, then the connection Err, Do, Send, Flush
186186
// and Receive methods return that error.
187187
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
193191
}
194192

195193
// GetContext gets a connection using the provided context.
@@ -201,11 +199,90 @@ func (p *Pool) Get() Conn {
201199
// If the function completes without error, then the application must close the
202200
// returned connection.
203201
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)
205275
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()
206283
return errorConn{err}, err
207284
}
208-
return &activeConn{p: p, pc: pc}, nil
285+
return &activeConn{p: p, pc: &poolConn{c: c, created: nowFunc()}}, nil
209286
}
210287

211288
// PoolStats contains pool statistics.
@@ -299,97 +376,6 @@ func (p *Pool) lazyInit() {
299376
p.mu.Unlock()
300377
}
301378

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-
393379
func (p *Pool) dial(ctx context.Context) (Conn, error) {
394380
if p.DialContext != nil {
395381
return p.DialContext(ctx)

0 commit comments

Comments
 (0)