@@ -53,6 +53,7 @@ type Options struct {
53
53
OnClose func (* Conn ) error
54
54
55
55
PoolSize int
56
+ MinIdleConns int
56
57
PoolTimeout time.Duration
57
58
IdleTimeout time.Duration
58
59
IdleCheckFrequency time.Duration
@@ -63,16 +64,16 @@ type ConnPool struct {
63
64
64
65
dialErrorsNum uint32 // atomic
65
66
66
- lastDialError error
67
67
lastDialErrorMu sync.RWMutex
68
+ lastDialError error
68
69
69
70
queue chan struct {}
70
71
71
- connsMu sync.Mutex
72
- conns []* Conn
73
-
74
- idleConnsMu sync. RWMutex
75
- idleConns [] * Conn
72
+ connsMu sync.Mutex
73
+ conns []* Conn
74
+ idleConns [] * Conn
75
+ poolSize int
76
+ idleConnsLen int
76
77
77
78
stats Stats
78
79
@@ -90,26 +91,64 @@ func NewConnPool(opt *Options) *ConnPool {
90
91
idleConns : make ([]* Conn , 0 , opt .PoolSize ),
91
92
}
92
93
94
+ for i := 0 ; i < opt .MinIdleConns ; i ++ {
95
+ p .checkMinIdleConns ()
96
+ }
97
+
93
98
if opt .IdleTimeout > 0 && opt .IdleCheckFrequency > 0 {
94
99
go p .reaper (opt .IdleCheckFrequency )
95
100
}
96
101
97
102
return p
98
103
}
99
104
105
+ func (p * ConnPool ) checkMinIdleConns () {
106
+ if p .opt .MinIdleConns == 0 {
107
+ return
108
+ }
109
+ if p .poolSize < p .opt .PoolSize && p .idleConnsLen < p .opt .MinIdleConns {
110
+ p .poolSize ++
111
+ p .idleConnsLen ++
112
+ go p .addIdleConn ()
113
+ }
114
+ }
115
+
116
+ func (p * ConnPool ) addIdleConn () {
117
+ cn , err := p .newConn (true )
118
+ if err != nil {
119
+ return
120
+ }
121
+
122
+ p .connsMu .Lock ()
123
+ p .conns = append (p .conns , cn )
124
+ p .idleConns = append (p .idleConns , cn )
125
+ p .connsMu .Unlock ()
126
+ }
127
+
100
128
func (p * ConnPool ) NewConn () (* Conn , error ) {
101
- cn , err := p .newConn ()
129
+ return p ._NewConn (false )
130
+ }
131
+
132
+ func (p * ConnPool ) _NewConn (pooled bool ) (* Conn , error ) {
133
+ cn , err := p .newConn (pooled )
102
134
if err != nil {
103
135
return nil , err
104
136
}
105
137
106
138
p .connsMu .Lock ()
107
139
p .conns = append (p .conns , cn )
140
+ if pooled {
141
+ if p .poolSize < p .opt .PoolSize {
142
+ p .poolSize ++
143
+ } else {
144
+ cn .pooled = false
145
+ }
146
+ }
108
147
p .connsMu .Unlock ()
109
148
return cn , nil
110
149
}
111
150
112
- func (p * ConnPool ) newConn () (* Conn , error ) {
151
+ func (p * ConnPool ) newConn (pooled bool ) (* Conn , error ) {
113
152
if p .closed () {
114
153
return nil , ErrClosed
115
154
}
@@ -127,7 +166,9 @@ func (p *ConnPool) newConn() (*Conn, error) {
127
166
return nil , err
128
167
}
129
168
130
- return NewConn (netConn ), nil
169
+ cn := NewConn (netConn )
170
+ cn .pooled = pooled
171
+ return cn , nil
131
172
}
132
173
133
174
func (p * ConnPool ) tryDial () {
@@ -174,9 +215,9 @@ func (p *ConnPool) Get() (*Conn, error) {
174
215
}
175
216
176
217
for {
177
- p .idleConnsMu .Lock ()
218
+ p .connsMu .Lock ()
178
219
cn := p .popIdle ()
179
- p .idleConnsMu .Unlock ()
220
+ p .connsMu .Unlock ()
180
221
181
222
if cn == nil {
182
223
break
@@ -193,7 +234,7 @@ func (p *ConnPool) Get() (*Conn, error) {
193
234
194
235
atomic .AddUint32 (& p .stats .Misses , 1 )
195
236
196
- newcn , err := p .NewConn ( )
237
+ newcn , err := p ._NewConn ( true )
197
238
if err != nil {
198
239
p .freeTurn ()
199
240
return nil , err
@@ -241,7 +282,8 @@ func (p *ConnPool) popIdle() *Conn {
241
282
idx := len (p .idleConns ) - 1
242
283
cn := p .idleConns [idx ]
243
284
p .idleConns = p .idleConns [:idx ]
244
-
285
+ p .idleConnsLen --
286
+ p .checkMinIdleConns ()
245
287
return cn
246
288
}
247
289
@@ -253,9 +295,15 @@ func (p *ConnPool) Put(cn *Conn) {
253
295
return
254
296
}
255
297
256
- p .idleConnsMu .Lock ()
298
+ if ! cn .pooled {
299
+ p .Remove (cn )
300
+ return
301
+ }
302
+
303
+ p .connsMu .Lock ()
257
304
p .idleConns = append (p .idleConns , cn )
258
- p .idleConnsMu .Unlock ()
305
+ p .idleConnsLen ++
306
+ p .connsMu .Unlock ()
259
307
p .freeTurn ()
260
308
}
261
309
@@ -275,6 +323,10 @@ func (p *ConnPool) removeConn(cn *Conn) {
275
323
for i , c := range p .conns {
276
324
if c == cn {
277
325
p .conns = append (p .conns [:i ], p .conns [i + 1 :]... )
326
+ if cn .pooled {
327
+ p .poolSize --
328
+ p .checkMinIdleConns ()
329
+ }
278
330
break
279
331
}
280
332
}
@@ -291,17 +343,17 @@ func (p *ConnPool) closeConn(cn *Conn) error {
291
343
// Len returns total number of connections.
292
344
func (p * ConnPool ) Len () int {
293
345
p .connsMu .Lock ()
294
- l := len ( p . conns )
346
+ n := p . poolSize
295
347
p .connsMu .Unlock ()
296
- return l
348
+ return n
297
349
}
298
350
299
351
// FreeLen returns number of idle connections.
300
352
func (p * ConnPool ) IdleLen () int {
301
- p .idleConnsMu . RLock ()
302
- l := len ( p . idleConns )
303
- p .idleConnsMu . RUnlock ()
304
- return l
353
+ p .connsMu . Lock ()
354
+ n := p . idleConnsLen
355
+ p .connsMu . Unlock ()
356
+ return n
305
357
}
306
358
307
359
func (p * ConnPool ) Stats () * Stats {
@@ -349,11 +401,10 @@ func (p *ConnPool) Close() error {
349
401
}
350
402
}
351
403
p .conns = nil
352
- p .connsMu .Unlock ()
353
-
354
- p .idleConnsMu .Lock ()
404
+ p .poolSize = 0
355
405
p .idleConns = nil
356
- p .idleConnsMu .Unlock ()
406
+ p .idleConnsLen = 0
407
+ p .connsMu .Unlock ()
357
408
358
409
return firstErr
359
410
}
@@ -369,6 +420,7 @@ func (p *ConnPool) reapStaleConn() *Conn {
369
420
}
370
421
371
422
p .idleConns = append (p .idleConns [:0 ], p .idleConns [1 :]... )
423
+ p .idleConnsLen --
372
424
373
425
return cn
374
426
}
@@ -378,9 +430,9 @@ func (p *ConnPool) ReapStaleConns() (int, error) {
378
430
for {
379
431
p .getTurn ()
380
432
381
- p .idleConnsMu .Lock ()
433
+ p .connsMu .Lock ()
382
434
cn := p .reapStaleConn ()
383
- p .idleConnsMu .Unlock ()
435
+ p .connsMu .Unlock ()
384
436
385
437
if cn != nil {
386
438
p .removeConn (cn )
0 commit comments