-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcache.go
195 lines (179 loc) · 4.21 KB
/
cache.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/*
Package cache offers concurrency safe in-memory cache based on b-tree and hash-map indexing.
All methods of Cache struct are concurrency safe and operates cache atomically.
*/
package cache
import (
"sync"
"github.com/google/btree"
)
var (
// DefaultDegree is default b-tree degree.
DefaultDegree = 4
)
// Cache struct is concurrency safe in-memory cache based on b-tree and hash-map indexing.
// All methods of Cache struct are concurrency safe and operates cache atomically.
type Cache struct {
done chan struct{}
tr *btree.BTree
trMu sync.RWMutex
qu chan *item
degree int
}
// NewCache returns a new Cache has default degree.
func NewCache() (ce *Cache) {
return NewCacheDegree(DefaultDegree)
}
// NewCacheDegree returns a new Cache given degree.
func NewCacheDegree(degree int) (ce *Cache) {
ce = &Cache{
done: make(chan struct{}),
qu: make(chan *item, 1024),
degree: degree,
}
ce.Flush()
go ce.queueWorker()
return
}
// Flush flushes the cache.
func (ce *Cache) Flush() {
ce.trMu.Lock()
ce.tr = btree.New(ce.degree)
ce.trMu.Unlock()
//ce.qu = make(chan *item, 1024)
}
// Close closes the cache. It must be called if the cache will not use.
func (ce *Cache) Close() {
ce.done <- struct{}{}
close(ce.qu)
}
func (ce *Cache) queueWorker() {
for im := range ce.qu {
ce.trMu.Lock()
if im.Val != nil {
ce.tr.ReplaceOrInsert(*im)
} else {
ce.tr.Delete(*im)
}
ce.trMu.Unlock()
}
}
// Get returns the value of given key. It returns nil, if the key wasn't exist.
func (ce *Cache) Get(key string) (val interface{}) {
done := false
for !done {
select {
case im := <-ce.qu:
if im.Key == key {
val = im.Val
return
}
ce.qu <- im
default:
done = true
}
}
ce.trMu.RLock()
r := ce.tr.Get(item{Key: key})
if r == nil {
ce.trMu.RUnlock()
return
}
ce.trMu.RUnlock()
val = r.(item).Val
return
}
// Set sets the value of given key. It deletes the key, if the val is nil.
func (ce *Cache) Set(key string, val interface{}) {
ce.qu <- &item{Key: key, Val: val}
}
// Del deletes the key.
func (ce *Cache) Del(key string) {
ce.Set(key, nil)
}
/*// GetOrSet returns the existing value for the key if present. Otherwise, it sets and returns the given value.
// If the key was exist, the found is true.
func (ce *Cache) GetOrSet(key string, newVal interface{}) (oldVal interface{}, found bool) {
found = true
ce.quMu.Lock()
if im, ok := ce.qu[key]; ok {
ce.quMu.Unlock()
oldVal = im.Val
return
}
ce.trMu.RLock()
r := ce.tr.Get(item{Key: key})
if r == nil {
ce.qu[key] = item{Key: key, Val: newVal}
ce.quMu.Unlock()
ce.trMu.RUnlock()
select {
case ce.quCh <- struct{}{}:
default:
}
oldVal = newVal
found = false
return
}
ce.quMu.Unlock()
ce.trMu.RUnlock()
oldVal = r.(item).Val
return
}
// GetAndSet returns the replaced value for the key if present. Otherwise, returns nil.
// Value replaces by f.
func (ce *Cache) GetAndSet(key string, f func(interface{}) interface{}) (newVal interface{}) {
ce.quMu.Lock()
if im, ok := ce.qu[key]; ok {
newVal = f(im.Val)
ce.qu[key] = item{Key: key, Val: newVal}
ce.quMu.Unlock()
select {
case ce.quCh <- struct{}{}:
default:
}
return
}
ce.trMu.RLock()
r := ce.tr.Get(item{Key: key})
if r == nil {
ce.quMu.Unlock()
ce.trMu.RUnlock()
return
}
newVal = f(r.(item).Val)
ce.qu[key] = item{Key: key, Val: newVal}
ce.quMu.Unlock()
ce.trMu.RUnlock()
select {
case ce.quCh <- struct{}{}:
default:
}
return
}
// Inc increases and the value of given key if the value is int or int64, and after returns new value.
// Otherwise returns old value.
func (ce *Cache) Inc(key string, x int64) (val interface{}) {
return ce.GetAndSet(key, func(val2 interface{}) interface{} {
switch val2.(type) {
case int:
return val2.(int) + int(x)
case int64:
return val2.(int64) + int64(x)
}
return val2
})
}
// Dec decreases and the value of given key if the value is int or int64, and after returns new value.
// Otherwise returns old value.
func (ce *Cache) Dec(key string, x int64) (val interface{}) {
return ce.GetAndSet(key, func(val2 interface{}) interface{} {
switch val2.(type) {
case int:
return val2.(int) - int(x)
case int64:
return val2.(int64) - int64(x)
}
return val2
})
}*/