-
Notifications
You must be signed in to change notification settings - Fork 22
/
tree_pool.go
129 lines (116 loc) · 2.45 KB
/
tree_pool.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
124
125
126
127
128
129
package exec
import (
"fmt"
"math"
"sync"
)
type tree []int
type TreePool struct {
l sync.Locker
trees map[int][]tree
pool map[int]*sync.Pool
cacheSize int
emptyTree map[int]tree
}
func initTree(t tree, size int) {
nodeSize := size * 2
for i := 0; i < 2*size-1; i++ {
if isPowOf2(i + 1) {
nodeSize /= 2
}
t[i] = nodeSize
}
}
func buildTree(size int) tree {
if size < 1 || !isPowOf2(size) {
panic(fmt.Errorf("build tree failed,wrong Size:%d", size))
}
tree := make([]int, size*2-1)
initTree(tree, size)
return tree
}
func NewTreePool(poolSize int, cacheSize int) *TreePool {
trees := make(map[int][]tree, 0)
pool := make(map[int]*sync.Pool, 0)
emptyTree := make(map[int]tree, 0)
for i := 0; i < poolSize; i++ {
size := int(math.Pow(2, float64(i))) * DefaultPageSize
treeC := buildTree(size)
for j := 0; j < cacheSize; j++ {
t := make([]int, (2*size)-1)
copy(t, treeC)
trees[i] = append(trees[i], t)
if j == 0 {
e := make([]int, (2*size)-1)
copy(e, t)
emptyTree[i] = e
}
}
pool[i] = &sync.Pool{
New: func() interface{} {
return buildTree(size)
},
}
}
return &TreePool{
l: &sync.Mutex{},
trees: trees,
pool: pool,
cacheSize: cacheSize,
emptyTree: emptyTree,
}
}
func (tp *TreePool) GetTree(pages int) tree {
tp.l.Lock()
defer tp.l.Unlock()
pages = fixSize(pages)
key := int(math.Log2(float64(pages)))
treeArr, ok := tp.trees[key]
if !ok {
_, ok := tp.pool[key]
if !ok {
tp.pool[key] = &sync.Pool{
New: func() interface{} {
return buildTree(pages * DefaultPageSize)
},
}
tp.emptyTree[key] = buildTree(pages * DefaultPageSize)
}
return tp.pool[key].Get().(tree)
}
if len(treeArr) > 0 {
tree := treeArr[0]
tp.trees[key] = append(treeArr[:0], treeArr[1:]...)
return tree
} else {
return tp.pool[key].Get().(tree)
}
}
func (tp *TreePool) PutTree(tree tree) {
tp.l.Lock()
defer tp.l.Unlock()
size := (len(tree) + 1) / 2
pages := size / DefaultPageSize
key := int(math.Log2(float64(pages)))
if tree[0] != size {
//log.Debug("reset memory tree...")
reset(tree, tp.trees[key], tp.emptyTree[key])
}
treeArr, ok := tp.trees[key]
if !ok || len(treeArr) >= tp.cacheSize {
tp.pool[key].Put(tree)
return
}
tp.trees[key] = append(treeArr, tree)
}
func reset(t tree, trees []tree, e tree) {
if trees != nil {
for _, treeC := range trees {
if treeC != nil {
copy(t, treeC)
return
}
}
}
copy(t, e)
}