-
Notifications
You must be signed in to change notification settings - Fork 0
/
ramdatastore.go
135 lines (116 loc) · 2.45 KB
/
ramdatastore.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
130
131
132
133
134
135
package heatmap
import (
"regexp"
"strings"
"sync"
"time"
)
type treeNode struct {
name string
parent *treeNode
childrenMutex sync.Mutex
children map[string]*treeNode
data []*datapoint
}
func globPatternToRegexp(pattern string) *regexp.Regexp {
expr := "^"
var multipleChoice bool
for _, ch := range pattern {
if ch == '*' {
expr += ".*?"
} else if ch == '{' {
expr += "("
multipleChoice = true
} else if ch == '}' {
multipleChoice = false
expr += ")"
} else if multipleChoice && ch == ',' {
expr += "|"
} else {
expr += string(ch)
}
}
expr += "$"
return regexp.MustCompile(expr)
}
func (tn *treeNode) recursiveCleanup() {
tn.data = tn.data[len(tn.data)/10:]
for _, child := range tn.children {
child.recursiveCleanup()
}
}
func (tn *treeNode) glob(res *[]*globResult, prefix string, fragments []string) {
if len(fragments) == 0 {
if tn == nil {
return
}
*res = append(*res, &globResult{
name: prefix,
isLeaf: len(tn.data) > 0,
hasChildren: len(tn.children) > 0,
})
return
}
if prefix != "" {
prefix += "."
}
r := globPatternToRegexp(fragments[0])
for k, child := range tn.children {
if r.MatchString(k) {
child.glob(res, prefix+k, fragments[1:])
}
}
}
type ramDatastore struct {
root *treeNode
}
func newRAMDatastore() *ramDatastore {
return &ramDatastore{
root: &treeNode{
name: "",
parent: nil,
children: make(map[string]*treeNode),
},
}
}
func (rd *ramDatastore) Put(key string, p *datapoint) {
fragments := strings.Split(key, ".")
tn := rd.root
for _, f := range fragments {
if n, ok := tn.children[f]; ok {
tn = n
} else {
newNode := &treeNode{name: f, parent: tn, children: make(map[string]*treeNode)}
tn.children[f] = newNode
tn = newNode
}
}
tn.data = append(tn.data, p)
}
func (rd *ramDatastore) Get(key string, from, to time.Time) (res []*datapoint) {
fragments := strings.Split(key, ".")
tn := rd.root
for _, f := range fragments {
if n, ok := tn.children[f]; ok {
tn = n
} else {
return
}
}
fromInt := uint32(from.Unix())
toInt := uint32(to.Unix())
for _, d := range tn.data {
if d.timestamp >= fromInt && d.timestamp <= toInt {
res = append(res, d)
}
}
return
}
func (rd *ramDatastore) Glob(key string) (res []*globResult) {
fragments := strings.Split(key, ".")
rd.root.glob(&res, "", fragments)
return
}
func (rd *ramDatastore) cleanup() {
rd.root.recursiveCleanup()
}