-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmempool.go
More file actions
113 lines (95 loc) · 3 KB
/
mempool.go
File metadata and controls
113 lines (95 loc) · 3 KB
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
package mempool
import (
"bytes"
"fmt"
"sync"
)
const (
KB = 1 << 10
MB = 1 << 20
GB = 1 << 30
)
// reuse the memory slice
// and never gc
// Pool represents a buffer pool that can be used to reduce allocations and
// improve performance when dealing with byte buffers.
type Pool struct {
// pool is a channel that holds reusable byte buffers.
// Using a channel ensures that the pool is concurrency-safe.
pool chan *bytes.Buffer
// poolSize represents the number of goroutines that can be used to
// access the pool.
poolSize int
// bufferInitCap represents the capacity of the one buffer that will be
// added to the pool for future use.
bufferInitCap int
// maxBufferSize represents the maximum size of the buffer
// if the buffer is larger than this size, it will not be added to the pool.
maxBufferSize int
// lock is a read-write mutex that can be used to safely modify the
// pool attributes.
lock *sync.RWMutex
// len is the number of buffers currently in the pool.
len int
}
// NewPool creates a new Pool object with a given routineSize and cap.
func NewPool(routineSize, capacity int) *Pool {
// Create a channel that can hold *bytes.Buffer objects with a capacity of routineSize.
pool := make(chan *bytes.Buffer, routineSize)
// Create a Mutex object to manage access to the channel.
lock := &sync.RWMutex{}
for i := 0; i < routineSize; i++ {
// Add a new buffer to the pool.
pool <- bytes.NewBuffer(make([]byte, 0, capacity))
}
fmt.Println("pool size:", len(pool))
// Create a new Pool object with the given parameters.
return &Pool{
pool: pool,
lock: lock,
bufferInitCap: capacity,
poolSize: routineSize,
}
}
//Get and Put should be used in pairs
// Get retrieves a buffer from the pool. If the pool does not have
// any available buffers, it will create a new buffer and return it.
func (p *Pool) Get() *bytes.Buffer {
// Acquire lock to ensure thread safety
// If the number of available buffers is less than the pool size,
// create and return a new buffer.
// Otherwise, retrieve a buffer from the pool and return it.
buf := <-p.pool
return buf
}
// Put adds a buffer to the pool.
//
// If the buffer's capacity is at least twice its length, a new buffer
// is created with the same length as the input buffer and added to the pool.
// Otherwise, the input buffer is reset and added to the pool.
//
// Finally, the length of the pool is incremented and the mutex is unlocked
// to allow other goroutines to access the pool.
func (p *Pool) Put(b *bytes.Buffer) {
cap := b.Cap()
len := b.Len()
if len != 0 && cap >= 2*len {
// Create a new buffer with the same length as the input buffer
newBuf := bytes.NewBuffer(make([]byte, 0, len))
p.pool <- newBuf
} else {
// Reset the input buffer before adding it to the pool
b.Reset()
p.pool <- b
}
// Increment the length of the pool and unlock the mutex
// p.lock.Lock()
// p.len++
// p.lock.Unlock()
}
func (p *Pool) Len() int {
return len(p.pool)
}
func (p *Pool) Cap() int {
return cap(p.pool)
}