-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbpool.go
123 lines (106 loc) · 2.97 KB
/
bpool.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package bpool
import (
"sync"
"time"
)
const (
CHAN_SIZE = 1000
)
/*
Buffer struct
*/
type Buffer struct {
when time.Time // When the buffer was added in the pool
slice []byte // The slide used
}
/*
Pool struct
*/
type Pool struct {
buffers chan Buffer // The list of Buffer
bufferSize int // The fixed size of buffers
length int // The length of the list
expiration time.Duration // The expiration time (in second) of a buffer in the pool
sync.Mutex // A mutex to make the Pool threadsafe
}
/*
Get a buffer in the pool
If the buffer is empty, it create a new buffer
*/
func (p *Pool) Get() (b []byte) {
p.Lock() // Lock pool
defer p.Unlock() // Unlock pool
select {
case buffer := <-p.buffers: // If a buffer is in the pool, return it
b = buffer.slice // Attach buffer of the Buffer struct
p.length-- // Decrement pool length
return
default: // If the pool is empty, create a new buffer and return it
b = make([]byte, p.bufferSize) // Create buffer
return
}
return
}
/*
Put a buffer in the pool
*/
func (p *Pool) Put(b []byte) {
var buffer Buffer
// If buffer size is different of pool buffer size => dont keep it
if cap(b) != p.bufferSize {
return
}
// If buffer cap is different of buffer len => resize
if cap(b) != len(b) {
b = b[:cap(b)]
}
p.Lock() // Lock pool
defer p.Unlock() // Unlock pool
buffer.slice = b // Attach buffer in the Buffer struct
buffer.when = time.Now() // Reset the expiration date
p.buffers <- buffer // Add the buffer in the pool
p.length++ // Increment pool length
}
/*
Create a new Pool
It launch a garbage collector goroutine
bufferSize: fixed size of buffers
expiration: expiration time (in second) of a buffer in the pool
*/
func GetPool(bufferSize, expiration int) *Pool {
var pool Pool
pool.buffers = make(chan Buffer, CHAN_SIZE) // Make a huge channel to store buffers
pool.bufferSize = bufferSize // Set the fixed size of buffers
pool.expiration = time.Second * time.Duration(expiration) // Set the expiration time of buffers
// Garbage collector goroutine
go func() {
for {
tmpChan := make(chan Buffer, CHAN_SIZE) // Make a huge temporary channel to store buffers
time.Sleep(time.Second) // Sleep to avoid 100% CPU consumption
pool.Lock() // Lock pool
if pool.length == 0 {
pool.Unlock() // Unlock pool
continue
}
// GC loop
GC:
for {
select {
case buffer := <-pool.buffers: // If a buffer exist in the pool, check expiration date
if buffer.when.Add(pool.expiration).Before(time.Now()) {
// Expirate => Remove it
pool.length--
} else {
// Not expirate => Keep it
tmpChan <- buffer
}
default: // End of the pool
pool.buffers = tmpChan // Keep temporary chan
break GC
}
}
pool.Unlock() // Unlock pool
}
}()
return &pool
}