-
Notifications
You must be signed in to change notification settings - Fork 202
/
evictionWaitingListMock.go
155 lines (126 loc) · 3.63 KB
/
evictionWaitingListMock.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
package state
import (
"errors"
"sync"
"github.com/ElrondNetwork/elrond-go-core/core/check"
"github.com/ElrondNetwork/elrond-go-core/data/batch"
"github.com/ElrondNetwork/elrond-go-core/marshal"
"github.com/ElrondNetwork/elrond-go/common"
"github.com/ElrondNetwork/elrond-go/state"
"github.com/ElrondNetwork/elrond-go/storage"
)
// EvictionWaitingList is a structure that caches keys that need to be removed from a certain database.
// If the cache is full, the keys will be stored in the underlying database. Writing at the same key in
// cacher and db will overwrite the previous values.
type EvictionWaitingList struct {
Cache map[string]common.ModifiedHashes
CacheSize uint
Db storage.Persister
Marshalizer marshal.Marshalizer
OpMutex sync.RWMutex
}
// NewEvictionWaitingList creates a new instance of evictionWaitingList
func NewEvictionWaitingList(size uint, db storage.Persister, marshalizer marshal.Marshalizer) *EvictionWaitingList {
return &EvictionWaitingList{
Cache: make(map[string]common.ModifiedHashes),
CacheSize: size,
Db: db,
Marshalizer: marshalizer,
}
}
// Put stores the given hashes in the eviction waiting list, in the position given by the root hash
func (ewl *EvictionWaitingList) Put(rootHash []byte, hashes common.ModifiedHashes) error {
ewl.OpMutex.Lock()
defer ewl.OpMutex.Unlock()
if uint(len(ewl.Cache)) < ewl.CacheSize {
ewl.Cache[string(rootHash)] = hashes
return nil
}
b := &batch.Batch{}
for h := range hashes {
b.Data = append(b.Data, []byte(h))
}
marshalizedHashes, err := ewl.Marshalizer.Marshal(b)
if err != nil {
return err
}
err = ewl.Db.Put(rootHash, marshalizedHashes)
if err != nil {
return err
}
return nil
}
// Evict returns and removes from the waiting list all the hashes from the position given by the root hash
func (ewl *EvictionWaitingList) Evict(rootHash []byte) (common.ModifiedHashes, error) {
ewl.OpMutex.Lock()
defer ewl.OpMutex.Unlock()
hashes, ok := ewl.Cache[string(rootHash)]
if ok {
delete(ewl.Cache, string(rootHash))
return hashes, nil
}
marshalizedHashes, err := ewl.Db.Get(rootHash)
if err != nil {
return nil, err
}
b := &batch.Batch{}
err = ewl.Marshalizer.Unmarshal(b, marshalizedHashes)
if err != nil {
return nil, err
}
hashes = make(common.ModifiedHashes, len(b.Data))
for _, h := range b.Data {
hashes[string(h)] = struct{}{}
}
err = ewl.Db.Remove(rootHash)
if err != nil {
return nil, err
}
return hashes, nil
}
// IsInterfaceNil returns true if there is no value under the interface
func (ewl *EvictionWaitingList) IsInterfaceNil() bool {
return ewl == nil
}
// ShouldKeepHash -
func (ewl *EvictionWaitingList) ShouldKeepHash(hash string, identifier state.TriePruningIdentifier) (bool, error) {
ewl.OpMutex.Lock()
defer ewl.OpMutex.Unlock()
for key := range ewl.Cache {
if len(key) == 0 {
return false, errors.New("invalid key")
}
lastByte := key[len(key)-1]
if state.TriePruningIdentifier(lastByte) == state.OldRoot && identifier == state.OldRoot {
continue
}
hashes := ewl.Cache[key]
if len(hashes) == 0 {
marshalizedHashes, err := ewl.Db.Get([]byte(key))
if err != nil {
return false, err
}
b := &batch.Batch{}
err = ewl.Marshalizer.Unmarshal(b, marshalizedHashes)
if err != nil {
return false, err
}
hashes = make(common.ModifiedHashes, len(b.Data))
for _, h := range b.Data {
hashes[string(h)] = struct{}{}
}
}
_, ok := hashes[hash]
if ok {
return true, nil
}
}
return false, nil
}
// Close -
func (ewl *EvictionWaitingList) Close() error {
if !check.IfNil(ewl.Db) {
return ewl.Db.Close()
}
return nil
}