-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexpectation_db.go
113 lines (87 loc) · 2.63 KB
/
expectation_db.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
package tsuki
import (
"sync"
)
type ExpectAction int
const (
ExpectActionNothing = ExpectAction(0)
ExpectActionRead = ExpectAction(1)
ExpectActionWrite = ExpectAction(2)
)
var strToExpectAction = map[string]ExpectAction {
"read": ExpectActionRead,
"write": ExpectActionWrite,
}
// token -> chunkId -> ExpectAction
// Putting token first makes it more cache-friendly, since there much less
// tokens than chunks.
//type TokenExpectations map[string]map[string]ExpectAction
type TokenExpectation struct {
action ExpectAction
processedChunks map[string]bool
pendingCount int
mu sync.RWMutex
}
type ExpectationDB struct {
mu sync.RWMutex
index map[string]*TokenExpectation
expectsPerChunk map[string]int
purgeChunk map[string]struct{}
}
func NewExpectationDB() *ExpectationDB {
return &ExpectationDB {
index: make(map[string]*TokenExpectation),
expectsPerChunk: make(map[string]int),
purgeChunk: make(map[string]struct{}),
}
}
func (e *ExpectationDB) Get(token string) *TokenExpectation {
e.mu.RLock()
defer e.mu.RUnlock()
return e.index[token]
}
func (e *ExpectationDB) Set(token string, exp *TokenExpectation) {
e.mu.Lock()
defer e.mu.Unlock()
e.index[token] = exp
for k := range exp.processedChunks {
e.expectsPerChunk[k]++
}
}
func (e *ExpectationDB) Remove(token string) []string {
e.mu.Lock()
defer e.mu.Unlock()
toPurge := make([]string, 0, len(e.purgeChunk))
for id := range e.index[token].processedChunks {
e.expectsPerChunk[id]--
if e.expectsPerChunk[id] == 0 {
delete(e.expectsPerChunk, id)
_, obsolete := e.purgeChunk[id]
if obsolete {
toPurge = append(toPurge, id)
delete(e.purgeChunk, id)
}
}
}
delete(e.index, token)
return toPurge
}
func (e *ExpectationDB) MakeObsolete(chunks ...string) (toPurge []string) {
e.mu.Lock()
defer e.mu.Unlock()
for _, id := range chunks {
expCount := e.expectsPerChunk[id]
if expCount == 0 {
// Note that there's no `id` in the e.purgeChunk if we've entered
// this if. The only way to make chunk obsolete is to call this
// function. Hence, if MakeObsolete didn't remove it the first
// call, there was at least one expect action associated with
// this chunk. And because of this, the Remove will return it
// and clear e.purgeChunk.
toPurge = append(toPurge, id)
continue
}
e.purgeChunk[id] = struct{}{}
}
return
}