-
Notifications
You must be signed in to change notification settings - Fork 0
/
blockcache.go
147 lines (123 loc) · 3.4 KB
/
blockcache.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
package statecache
import (
"sync"
"sync/atomic"
"github.com/0chain/common/core/logging"
"go.uber.org/zap"
)
type BlockCacher interface {
Get(key string) (Value, bool)
Round() int64
Commit()
setValue(key string, v valueNode)
addStats(hit, miss int64)
}
// BlockCache is a pre commit cache for all changes in a block.
// This is mainly for caching values in current block when executing blocks.
//
// Call `Commit()` method to merge
// the changes to the StateCache when the block is executed.
type BlockCache struct {
mu sync.Mutex
cache map[string]valueNode
main *StateCache
blockHash string
prevBlockHash string
round int64
hits int64
miss int64
}
type Block struct {
Round int64 // round number when this block cache is created
Hash string // block hash
PrevHash string // previous hash of the block
}
func NewBlockCache(main *StateCache, b Block) *BlockCache {
return &BlockCache{
cache: make(map[string]valueNode),
main: main,
blockHash: b.Hash,
prevBlockHash: b.PrevHash,
round: b.Round,
}
}
// Set sets the value with the given key in the pre-commit cache
func (pcc *BlockCache) Set(key string, e Value) {
pcc.mu.Lock()
pcc.cache[key] = valueNode{
data: e.Clone(),
}
pcc.mu.Unlock()
}
func (pcc *BlockCache) Round() int64 {
return pcc.round
}
func (pcc *BlockCache) setValue(key string, v valueNode) {
pcc.mu.Lock()
defer pcc.mu.Unlock()
v.data = v.data.Clone()
pcc.cache[key] = v
}
// Get returns the value with the given key
func (pcc *BlockCache) Get(key string) (Value, bool) {
pcc.mu.Lock()
defer pcc.mu.Unlock()
// Check the cache first
value, ok := pcc.cache[key]
if ok && !value.deleted {
// logging.Logger.Debug("block cache get", zap.String("key", key))
return value.data.Clone(), true
}
// Should not return deleted value
if ok && value.deleted {
// logging.Logger.Debug("block cache get - deleted", zap.String("key", key))
logging.Logger.Debug("block state cache - deleted", zap.String("block", pcc.blockHash))
return nil, false
}
return pcc.main.Get(key, pcc.prevBlockHash)
// v, ok := pcc.main.Get(key, pcc.prevBlockHash)
// if ok {
// // load the value from the state cache and store it in the block cache
// vn := valueNode{
// data: v,
// round: pcc.round,
// prevBlockHash: pcc.prevBlockHash,
// }
// pcc.cache[key] = vn
// return v, true
// }
// return nil, false
}
// Remove marks the value with the given key as deleted in the pre-commit cache
func (pcc *BlockCache) remove(key string) {
pcc.mu.Lock()
defer pcc.mu.Unlock()
value, ok := pcc.cache[key]
if ok {
value.deleted = true
pcc.cache[key] = value
return
} else {
pcc.cache[key] = valueNode{
deleted: true,
}
}
}
func (pcc *BlockCache) addStats(hit, miss int64) {
atomic.AddInt64(&pcc.hits, hit)
atomic.AddInt64(&pcc.miss, miss)
}
func (pcc *BlockCache) Stats() (hit, miss int64) {
return atomic.LoadInt64(&pcc.hits), atomic.LoadInt64(&pcc.miss)
}
// SetBlockHash sets the block hash, which is used after miners generating the block.
// miners generator does not know the block hash until the block is generated.
func (pcc *BlockCache) SetBlockHash(hash string) {
pcc.mu.Lock()
pcc.blockHash = hash
pcc.mu.Unlock()
}
// Commit moves the values from the pre-commit cache to the main cache
func (pcc *BlockCache) Commit() {
pcc.main.commit(pcc)
}