Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
snail007
GitHub Repository: snail007/goproxy
Path: blob/master/utils/pool.go
686 views
1
package utils
2
3
import (
4
"log"
5
"sync"
6
"time"
7
)
8
9
//ConnPool to use
10
type ConnPool interface {
11
Get() (conn interface{}, err error)
12
Put(conn interface{})
13
ReleaseAll()
14
Len() (length int)
15
}
16
type poolConfig struct {
17
Factory func() (interface{}, error)
18
IsActive func(interface{}) bool
19
Release func(interface{})
20
InitialCap int
21
MaxCap int
22
}
23
24
func NewConnPool(poolConfig poolConfig) (pool ConnPool, err error) {
25
p := netPool{
26
config: poolConfig,
27
conns: make(chan interface{}, poolConfig.MaxCap),
28
lock: &sync.Mutex{},
29
}
30
//log.Printf("pool MaxCap:%d", poolConfig.MaxCap)
31
if poolConfig.MaxCap > 0 {
32
err = p.initAutoFill(false)
33
if err == nil {
34
p.initAutoFill(true)
35
}
36
}
37
return &p, nil
38
}
39
40
type netPool struct {
41
conns chan interface{}
42
lock *sync.Mutex
43
config poolConfig
44
}
45
46
func (p *netPool) initAutoFill(async bool) (err error) {
47
var worker = func() (err error) {
48
for {
49
//log.Printf("pool fill: %v , len: %d", p.Len() <= p.config.InitialCap/2, p.Len())
50
if p.Len() <= p.config.InitialCap/2 {
51
p.lock.Lock()
52
errN := 0
53
for i := 0; i < p.config.InitialCap; i++ {
54
c, err := p.config.Factory()
55
if err != nil {
56
errN++
57
if async {
58
continue
59
} else {
60
p.lock.Unlock()
61
return err
62
}
63
}
64
select {
65
case p.conns <- c:
66
default:
67
p.config.Release(c)
68
break
69
}
70
if p.Len() >= p.config.InitialCap {
71
break
72
}
73
}
74
if errN > 0 {
75
log.Printf("fill conn pool fail , ERRN:%d", errN)
76
}
77
p.lock.Unlock()
78
}
79
if !async {
80
return
81
}
82
time.Sleep(time.Second * 2)
83
}
84
}
85
if async {
86
go worker()
87
} else {
88
err = worker()
89
}
90
return
91
92
}
93
94
func (p *netPool) Get() (conn interface{}, err error) {
95
// defer func() {
96
// log.Printf("pool len : %d", p.Len())
97
// }()
98
p.lock.Lock()
99
defer p.lock.Unlock()
100
// for {
101
select {
102
case conn = <-p.conns:
103
if p.config.IsActive(conn) {
104
return
105
}
106
p.config.Release(conn)
107
default:
108
conn, err = p.config.Factory()
109
if err != nil {
110
return nil, err
111
}
112
return conn, nil
113
}
114
// }
115
return
116
}
117
118
func (p *netPool) Put(conn interface{}) {
119
if conn == nil {
120
return
121
}
122
p.lock.Lock()
123
defer p.lock.Unlock()
124
if !p.config.IsActive(conn) {
125
p.config.Release(conn)
126
}
127
select {
128
case p.conns <- conn:
129
default:
130
p.config.Release(conn)
131
}
132
}
133
func (p *netPool) ReleaseAll() {
134
p.lock.Lock()
135
defer p.lock.Unlock()
136
close(p.conns)
137
for c := range p.conns {
138
p.config.Release(c)
139
}
140
p.conns = make(chan interface{}, p.config.InitialCap)
141
142
}
143
func (p *netPool) Len() (length int) {
144
return len(p.conns)
145
}
146
147