Skip to content

Commit 0b44a40

Browse files
committed
clean cache for the rawdb
1 parent b56a4c0 commit 0b44a40

File tree

3 files changed

+108
-12
lines changed

3 files changed

+108
-12
lines changed

core/trie2/triedb/rawdb/cache.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package rawdb
2+
3+
import (
4+
"math"
5+
6+
"github.com/NethermindEth/juno/core/felt"
7+
"github.com/NethermindEth/juno/core/trie2/trieutils"
8+
"github.com/VictoriaMetrics/fastcache"
9+
)
10+
11+
const nodeCacheSize = ownerSize + trieutils.PathSize + 1
12+
13+
type trieType byte
14+
15+
const (
16+
contract trieType = iota
17+
class
18+
)
19+
20+
// Stores committed trie nodes in memory
21+
type cleanCache struct {
22+
cache *fastcache.Cache // map[nodeKey]node
23+
}
24+
25+
// Creates a new clean cache with the given size.
26+
// The size is the maximum size of the cache in bytes.
27+
func newCleanCache(size uint64) cleanCache {
28+
if size > uint64(math.MaxInt) {
29+
panic("cache size too large: uint64 to int conversion would overflow")
30+
}
31+
return cleanCache{
32+
cache: fastcache.New(int(size)),
33+
}
34+
}
35+
36+
func (c *cleanCache) putNode(owner *felt.Felt, path *trieutils.Path, isClass bool, blob []byte) {
37+
c.cache.Set(nodeKey(owner, path, isClass), blob)
38+
}
39+
40+
func (c *cleanCache) getNode(owner *felt.Felt, path *trieutils.Path, isClass bool) []byte {
41+
return c.cache.Get(nil, nodeKey(owner, path, isClass))
42+
}
43+
44+
func (c *cleanCache) deleteNode(owner *felt.Felt, path *trieutils.Path, isClass bool) {
45+
c.cache.Del(nodeKey(owner, path, isClass))
46+
}
47+
48+
// key = owner (32 bytes) + path (20 bytes) + trie type (1 byte)
49+
func nodeKey(owner *felt.Felt, path *trieutils.Path, isClass bool) []byte {
50+
key := make([]byte, nodeCacheSize)
51+
ownerBytes := owner.Bytes()
52+
copy(key[:felt.Bytes], ownerBytes[:])
53+
copy(key[felt.Bytes:felt.Bytes+trieutils.PathSize], path.EncodedBytes())
54+
55+
if isClass {
56+
key[nodeCacheSize-1] = byte(class)
57+
}
58+
59+
return key
60+
}

core/trie2/triedb/rawdb/database.go

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,32 @@ import (
1313

1414
var _ database.TrieDB = (*Database)(nil)
1515

16-
type Config struct{}
16+
type Config struct {
17+
CleanCacheSize uint64 // Maximum size (in bytes) for caching clean nodes
18+
}
1719

1820
type Database struct {
1921
disk db.KeyValueStore
2022

2123
lock sync.RWMutex
2224
log utils.StructuredLogger
25+
26+
config Config
27+
cleanCache *cleanCache
2328
}
2429

25-
func New(disk db.KeyValueStore) *Database {
30+
func New(disk db.KeyValueStore, config *Config) *Database {
31+
if config == nil {
32+
config = &Config{
33+
CleanCacheSize: 16 * utils.Megabyte,
34+
}
35+
}
36+
cleanCache := newCleanCache(config.CleanCacheSize)
2637
return &Database{
27-
disk: disk,
28-
log: utils.NewNopZapLogger(),
38+
disk: disk,
39+
config: *config,
40+
cleanCache: &cleanCache,
41+
log: utils.NewNopZapLogger(),
2942
}
3043
}
3144

@@ -37,11 +50,19 @@ func (d *Database) readNode(
3750
) ([]byte, error) {
3851
d.lock.RLock()
3952
defer d.lock.RUnlock()
53+
54+
isClass := id.Type() == trieutils.Class
55+
blob := d.cleanCache.getNode(owner, path, isClass)
56+
if blob != nil {
57+
return blob, nil
58+
}
59+
4060
blob, err := trieutils.GetNodeByPath(d.disk, id.Bucket(), owner, path, isLeaf)
4161
if err != nil {
4262
return nil, err
4363
}
4464

65+
d.cleanCache.putNode(owner, path, isClass, blob)
4566
return blob, nil
4667
}
4768

@@ -79,29 +100,26 @@ func (d *Database) Update(
79100
}
80101

81102
for path, n := range classNodes {
82-
err := d.updateNode(batch, db.ClassTrie, &felt.Address{}, &path, n)
83-
if err != nil {
103+
if err := d.updateNode(batch, db.ClassTrie, &felt.Zero, &path, n, true); err != nil {
84104
return err
85105
}
86106
}
87107

88108
for path, n := range contractNodes {
89-
err := d.updateNode(batch, db.ContractTrieContract, &felt.Address{}, &path, n)
90-
if err != nil {
109+
if err := d.updateNode(batch, db.ContractTrieContract, &felt.Zero, &path, n, false); err != nil {
91110
return err
92111
}
93112
}
94113

95114
for owner, nodes := range contractStorageNodes {
96115
for path, n := range nodes {
97-
err := d.updateNode(batch, db.ContractTrieStorage, &owner, &path, n)
98-
if err != nil {
116+
if err := d.updateNode(batch, db.ContractTrieStorage, &owner, &path, n, false); err != nil {
99117
return err
100118
}
101119
}
102120
}
103121

104-
return batch.Write()
122+
return nil
105123
}
106124

107125
func (d *Database) updateNode(
@@ -110,9 +128,25 @@ func (d *Database) updateNode(
110128
owner *felt.Address,
111129
path *trieutils.Path,
112130
n trienode.TrieNode,
131+
isClass bool,
113132
) error {
114133
if _, deleted := n.(*trienode.DeletedNode); deleted {
115-
return trieutils.DeleteNodeByPath(batch, bucket, owner, path, n.IsLeaf())
134+
if err := trieutils.DeleteNodeByPath(batch, bucket, owner, path, n.IsLeaf()); err != nil {
135+
return err
136+
}
137+
d.cleanCache.deleteNode(owner, path, isClass)
138+
} else {
139+
if err := trieutils.WriteNodeByPath(
140+
batch,
141+
bucket,
142+
owner,
143+
path,
144+
n.IsLeaf(),
145+
n.Blob(),
146+
); err != nil {
147+
return err
148+
}
149+
d.cleanCache.putNode(owner, path, isClass, n.Blob())
116150
}
117151
return trieutils.WriteNodeByPath(
118152
batch,

core/trie2/triedb/rawdb/types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ type (
1111
contractNodesMap = map[trieutils.Path]trienode.TrieNode
1212
contractStorageNodesMap = map[felt.Address]map[trieutils.Path]trienode.TrieNode
1313
)
14+
15+
const ownerSize = felt.Bytes

0 commit comments

Comments
 (0)