-
Notifications
You must be signed in to change notification settings - Fork 122
/
Copy pathlayeredbucket.go
130 lines (115 loc) · 2.66 KB
/
layeredbucket.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
package ccache
import (
"sync"
"time"
)
type layeredBucket[T any] struct {
sync.RWMutex
buckets map[string]*bucket[T]
}
func (b *layeredBucket[T]) itemCount() int {
count := 0
b.RLock()
defer b.RUnlock()
for _, b := range b.buckets {
count += b.itemCount()
}
return count
}
func (b *layeredBucket[T]) get(primary, secondary string) *Item[T] {
bucket := b.getSecondaryBucket(primary)
if bucket == nil {
return nil
}
return bucket.get(secondary)
}
func (b *layeredBucket[T]) getSecondaryBucket(primary string) *bucket[T] {
b.RLock()
bucket, exists := b.buckets[primary]
b.RUnlock()
if !exists {
return nil
}
return bucket
}
func (b *layeredBucket[T]) set(primary, secondary string, value T, duration time.Duration, track bool) (*Item[T], *Item[T]) {
b.Lock()
bkt, exists := b.buckets[primary]
if !exists {
bkt = &bucket[T]{lookup: make(map[string]*Item[T])}
b.buckets[primary] = bkt
}
b.Unlock()
item, existing := bkt.set(secondary, value, duration, track)
item.group = primary
return item, existing
}
func (b *layeredBucket[T]) remove(primary, secondary string) *Item[T] {
b.RLock()
bucket, exists := b.buckets[primary]
b.RUnlock()
if !exists {
return nil
}
return bucket.remove(secondary)
}
func (b *layeredBucket[T]) delete(primary, secondary string) {
b.RLock()
bucket, exists := b.buckets[primary]
b.RUnlock()
if !exists {
return
}
bucket.delete(secondary)
}
func (b *layeredBucket[T]) deletePrefix(primary, prefix string, deletables chan *Item[T]) int {
b.RLock()
bucket, exists := b.buckets[primary]
b.RUnlock()
if !exists {
return 0
}
return bucket.deletePrefix(prefix, deletables)
}
func (b *layeredBucket[T]) deleteFunc(primary string, matches func(key string, item *Item[T]) bool, deletables chan *Item[T]) int {
b.RLock()
bucket, exists := b.buckets[primary]
b.RUnlock()
if !exists {
return 0
}
return bucket.deleteFunc(matches, deletables)
}
func (b *layeredBucket[T]) deleteAll(primary string, deletables chan *Item[T]) bool {
b.RLock()
bucket, exists := b.buckets[primary]
b.RUnlock()
if !exists {
return false
}
bucket.Lock()
defer bucket.Unlock()
if l := len(bucket.lookup); l == 0 {
return false
}
for key, item := range bucket.lookup {
delete(bucket.lookup, key)
deletables <- item
}
return true
}
func (b *layeredBucket[T]) forEachFunc(primary string, matches func(key string, item *Item[T]) bool) {
b.RLock()
bucket, exists := b.buckets[primary]
b.RUnlock()
if exists {
bucket.forEachFunc(matches)
}
}
// we expect the caller to have acquired a write lock
func (b *layeredBucket[T]) clear() {
for _, bucket := range b.buckets {
bucket.clear()
}
b.buckets = make(map[string]*bucket[T])
}