Skip to content

Commit 68ac781

Browse files
committed
Add MinIdleConns
1 parent 618e647 commit 68ac781

File tree

4 files changed

+254
-28
lines changed

4 files changed

+254
-28
lines changed

internal/pool/conn.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type Conn struct {
1919
concurrentReadWrite bool
2020

2121
Inited bool
22+
pooled bool
2223
usedAt atomic.Value
2324
}
2425

internal/pool/pool.go

Lines changed: 79 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ type Options struct {
5353
OnClose func(*Conn) error
5454

5555
PoolSize int
56+
MinIdleConns int
5657
PoolTimeout time.Duration
5758
IdleTimeout time.Duration
5859
IdleCheckFrequency time.Duration
@@ -63,16 +64,16 @@ type ConnPool struct {
6364

6465
dialErrorsNum uint32 // atomic
6566

66-
lastDialError error
6767
lastDialErrorMu sync.RWMutex
68+
lastDialError error
6869

6970
queue chan struct{}
7071

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
7677

7778
stats Stats
7879

@@ -90,26 +91,64 @@ func NewConnPool(opt *Options) *ConnPool {
9091
idleConns: make([]*Conn, 0, opt.PoolSize),
9192
}
9293

94+
for i := 0; i < opt.MinIdleConns; i++ {
95+
p.checkMinIdleConns()
96+
}
97+
9398
if opt.IdleTimeout > 0 && opt.IdleCheckFrequency > 0 {
9499
go p.reaper(opt.IdleCheckFrequency)
95100
}
96101

97102
return p
98103
}
99104

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+
100128
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)
102134
if err != nil {
103135
return nil, err
104136
}
105137

106138
p.connsMu.Lock()
107139
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+
}
108147
p.connsMu.Unlock()
109148
return cn, nil
110149
}
111150

112-
func (p *ConnPool) newConn() (*Conn, error) {
151+
func (p *ConnPool) newConn(pooled bool) (*Conn, error) {
113152
if p.closed() {
114153
return nil, ErrClosed
115154
}
@@ -127,7 +166,9 @@ func (p *ConnPool) newConn() (*Conn, error) {
127166
return nil, err
128167
}
129168

130-
return NewConn(netConn), nil
169+
cn := NewConn(netConn)
170+
cn.pooled = pooled
171+
return cn, nil
131172
}
132173

133174
func (p *ConnPool) tryDial() {
@@ -174,9 +215,9 @@ func (p *ConnPool) Get() (*Conn, error) {
174215
}
175216

176217
for {
177-
p.idleConnsMu.Lock()
218+
p.connsMu.Lock()
178219
cn := p.popIdle()
179-
p.idleConnsMu.Unlock()
220+
p.connsMu.Unlock()
180221

181222
if cn == nil {
182223
break
@@ -193,7 +234,7 @@ func (p *ConnPool) Get() (*Conn, error) {
193234

194235
atomic.AddUint32(&p.stats.Misses, 1)
195236

196-
newcn, err := p.NewConn()
237+
newcn, err := p._NewConn(true)
197238
if err != nil {
198239
p.freeTurn()
199240
return nil, err
@@ -241,7 +282,8 @@ func (p *ConnPool) popIdle() *Conn {
241282
idx := len(p.idleConns) - 1
242283
cn := p.idleConns[idx]
243284
p.idleConns = p.idleConns[:idx]
244-
285+
p.idleConnsLen--
286+
p.checkMinIdleConns()
245287
return cn
246288
}
247289

@@ -253,9 +295,15 @@ func (p *ConnPool) Put(cn *Conn) {
253295
return
254296
}
255297

256-
p.idleConnsMu.Lock()
298+
if !cn.pooled {
299+
p.Remove(cn)
300+
return
301+
}
302+
303+
p.connsMu.Lock()
257304
p.idleConns = append(p.idleConns, cn)
258-
p.idleConnsMu.Unlock()
305+
p.idleConnsLen++
306+
p.connsMu.Unlock()
259307
p.freeTurn()
260308
}
261309

@@ -275,6 +323,10 @@ func (p *ConnPool) removeConn(cn *Conn) {
275323
for i, c := range p.conns {
276324
if c == cn {
277325
p.conns = append(p.conns[:i], p.conns[i+1:]...)
326+
if cn.pooled {
327+
p.poolSize--
328+
p.checkMinIdleConns()
329+
}
278330
break
279331
}
280332
}
@@ -291,17 +343,17 @@ func (p *ConnPool) closeConn(cn *Conn) error {
291343
// Len returns total number of connections.
292344
func (p *ConnPool) Len() int {
293345
p.connsMu.Lock()
294-
l := len(p.conns)
346+
n := p.poolSize
295347
p.connsMu.Unlock()
296-
return l
348+
return n
297349
}
298350

299351
// FreeLen returns number of idle connections.
300352
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
305357
}
306358

307359
func (p *ConnPool) Stats() *Stats {
@@ -349,11 +401,10 @@ func (p *ConnPool) Close() error {
349401
}
350402
}
351403
p.conns = nil
352-
p.connsMu.Unlock()
353-
354-
p.idleConnsMu.Lock()
404+
p.poolSize = 0
355405
p.idleConns = nil
356-
p.idleConnsMu.Unlock()
406+
p.idleConnsLen = 0
407+
p.connsMu.Unlock()
357408

358409
return firstErr
359410
}
@@ -369,6 +420,7 @@ func (p *ConnPool) reapStaleConn() *Conn {
369420
}
370421

371422
p.idleConns = append(p.idleConns[:0], p.idleConns[1:]...)
423+
p.idleConnsLen--
372424

373425
return cn
374426
}
@@ -378,9 +430,9 @@ func (p *ConnPool) ReapStaleConns() (int, error) {
378430
for {
379431
p.getTurn()
380432

381-
p.idleConnsMu.Lock()
433+
p.connsMu.Lock()
382434
cn := p.reapStaleConn()
383-
p.idleConnsMu.Unlock()
435+
p.connsMu.Unlock()
384436

385437
if cn != nil {
386438
p.removeConn(cn)

0 commit comments

Comments
 (0)