|
|
@ -31,6 +31,7 @@ import ( |
|
|
|
"github.com/ethereum/go-ethereum/log" |
|
|
|
"github.com/ethereum/go-ethereum/log" |
|
|
|
"github.com/ethereum/go-ethereum/metrics" |
|
|
|
"github.com/ethereum/go-ethereum/metrics" |
|
|
|
"github.com/ethereum/go-ethereum/rlp" |
|
|
|
"github.com/ethereum/go-ethereum/rlp" |
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/trie" |
|
|
|
"github.com/ethereum/go-ethereum/trie/trienode" |
|
|
|
"github.com/ethereum/go-ethereum/trie/trienode" |
|
|
|
"github.com/ethereum/go-ethereum/trie/triestate" |
|
|
|
"github.com/ethereum/go-ethereum/trie/triestate" |
|
|
|
"github.com/ethereum/go-ethereum/triedb/database" |
|
|
|
"github.com/ethereum/go-ethereum/triedb/database" |
|
|
@ -60,12 +61,6 @@ var ( |
|
|
|
memcacheCommitBytesMeter = metrics.NewRegisteredMeter("hashdb/memcache/commit/bytes", nil) |
|
|
|
memcacheCommitBytesMeter = metrics.NewRegisteredMeter("hashdb/memcache/commit/bytes", nil) |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
// ChildResolver defines the required method to decode the provided
|
|
|
|
|
|
|
|
// trie node and iterate the children on top.
|
|
|
|
|
|
|
|
type ChildResolver interface { |
|
|
|
|
|
|
|
ForEach(node []byte, onChild func(common.Hash)) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Config contains the settings for database.
|
|
|
|
// Config contains the settings for database.
|
|
|
|
type Config struct { |
|
|
|
type Config struct { |
|
|
|
CleanCacheSize int // Maximum memory allowance (in bytes) for caching clean nodes
|
|
|
|
CleanCacheSize int // Maximum memory allowance (in bytes) for caching clean nodes
|
|
|
@ -85,8 +80,6 @@ var Defaults = &Config{ |
|
|
|
// periodically flush a couple tries to disk, garbage collecting the remainder.
|
|
|
|
// periodically flush a couple tries to disk, garbage collecting the remainder.
|
|
|
|
type Database struct { |
|
|
|
type Database struct { |
|
|
|
diskdb ethdb.Database // Persistent storage for matured trie nodes
|
|
|
|
diskdb ethdb.Database // Persistent storage for matured trie nodes
|
|
|
|
resolver ChildResolver // The handler to resolve children of nodes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cleans *fastcache.Cache // GC friendly memory cache of clean node RLPs
|
|
|
|
cleans *fastcache.Cache // GC friendly memory cache of clean node RLPs
|
|
|
|
dirties map[common.Hash]*cachedNode // Data and references relationships of dirty trie nodes
|
|
|
|
dirties map[common.Hash]*cachedNode // Data and references relationships of dirty trie nodes
|
|
|
|
oldest common.Hash // Oldest tracked node, flush-list head
|
|
|
|
oldest common.Hash // Oldest tracked node, flush-list head
|
|
|
@ -124,15 +117,15 @@ var cachedNodeSize = int(reflect.TypeOf(cachedNode{}).Size()) |
|
|
|
// forChildren invokes the callback for all the tracked children of this node,
|
|
|
|
// forChildren invokes the callback for all the tracked children of this node,
|
|
|
|
// both the implicit ones from inside the node as well as the explicit ones
|
|
|
|
// both the implicit ones from inside the node as well as the explicit ones
|
|
|
|
// from outside the node.
|
|
|
|
// from outside the node.
|
|
|
|
func (n *cachedNode) forChildren(resolver ChildResolver, onChild func(hash common.Hash)) { |
|
|
|
func (n *cachedNode) forChildren(onChild func(hash common.Hash)) { |
|
|
|
for child := range n.external { |
|
|
|
for child := range n.external { |
|
|
|
onChild(child) |
|
|
|
onChild(child) |
|
|
|
} |
|
|
|
} |
|
|
|
resolver.ForEach(n.node, onChild) |
|
|
|
trie.ForGatherChildren(n.node, onChild) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// New initializes the hash-based node database.
|
|
|
|
// New initializes the hash-based node database.
|
|
|
|
func New(diskdb ethdb.Database, config *Config, resolver ChildResolver) *Database { |
|
|
|
func New(diskdb ethdb.Database, config *Config) *Database { |
|
|
|
if config == nil { |
|
|
|
if config == nil { |
|
|
|
config = Defaults |
|
|
|
config = Defaults |
|
|
|
} |
|
|
|
} |
|
|
@ -142,7 +135,6 @@ func New(diskdb ethdb.Database, config *Config, resolver ChildResolver) *Databas |
|
|
|
} |
|
|
|
} |
|
|
|
return &Database{ |
|
|
|
return &Database{ |
|
|
|
diskdb: diskdb, |
|
|
|
diskdb: diskdb, |
|
|
|
resolver: resolver, |
|
|
|
|
|
|
|
cleans: cleans, |
|
|
|
cleans: cleans, |
|
|
|
dirties: make(map[common.Hash]*cachedNode), |
|
|
|
dirties: make(map[common.Hash]*cachedNode), |
|
|
|
} |
|
|
|
} |
|
|
@ -163,7 +155,7 @@ func (db *Database) insert(hash common.Hash, node []byte) { |
|
|
|
node: node, |
|
|
|
node: node, |
|
|
|
flushPrev: db.newest, |
|
|
|
flushPrev: db.newest, |
|
|
|
} |
|
|
|
} |
|
|
|
entry.forChildren(db.resolver, func(child common.Hash) { |
|
|
|
entry.forChildren(func(child common.Hash) { |
|
|
|
if c := db.dirties[child]; c != nil { |
|
|
|
if c := db.dirties[child]; c != nil { |
|
|
|
c.parents++ |
|
|
|
c.parents++ |
|
|
|
} |
|
|
|
} |
|
|
@ -316,7 +308,7 @@ func (db *Database) dereference(hash common.Hash) { |
|
|
|
db.dirties[node.flushNext].flushPrev = node.flushPrev |
|
|
|
db.dirties[node.flushNext].flushPrev = node.flushPrev |
|
|
|
} |
|
|
|
} |
|
|
|
// Dereference all children and delete the node
|
|
|
|
// Dereference all children and delete the node
|
|
|
|
node.forChildren(db.resolver, func(child common.Hash) { |
|
|
|
node.forChildren(func(child common.Hash) { |
|
|
|
db.dereference(child) |
|
|
|
db.dereference(child) |
|
|
|
}) |
|
|
|
}) |
|
|
|
delete(db.dirties, hash) |
|
|
|
delete(db.dirties, hash) |
|
|
@ -465,7 +457,7 @@ func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleane |
|
|
|
var err error |
|
|
|
var err error |
|
|
|
|
|
|
|
|
|
|
|
// Dereference all children and delete the node
|
|
|
|
// Dereference all children and delete the node
|
|
|
|
node.forChildren(db.resolver, func(child common.Hash) { |
|
|
|
node.forChildren(func(child common.Hash) { |
|
|
|
if err == nil { |
|
|
|
if err == nil { |
|
|
|
err = db.commit(child, batch, uncacher) |
|
|
|
err = db.commit(child, batch, uncacher) |
|
|
|
} |
|
|
|
} |
|
|
|