core, trie: fix duplicate references, sanity check on shutdown

This commit is contained in:
Péter Szilágyi 2018-01-24 16:31:26 +02:00
parent b46b291742
commit 4315480e09
No known key found for this signature in database
GPG key ID: E9AE538CEDF8293D
2 changed files with 19 additions and 13 deletions

View file

@ -669,6 +669,9 @@ func (bc *BlockChain) Stop() {
for !bc.triegc.Empty() { for !bc.triegc.Empty() {
bc.triedb.Dereference(bc.triegc.PopItem().(common.Hash), common.Hash{}) bc.triedb.Dereference(bc.triegc.PopItem().(common.Hash), common.Hash{})
} }
if size := bc.triedb.Size(); size != 0 {
log.Error("Dangling trie nodes after full cleanup")
}
log.Info("Blockchain manager stopped") log.Info("Blockchain manager stopped")
} }

View file

@ -61,9 +61,9 @@ type Database struct {
// cachedNode is all the information we know about a single cached node in the // cachedNode is all the information we know about a single cached node in the
// memory database write layer. // memory database write layer.
type cachedNode struct { type cachedNode struct {
blob []byte // Cached data block of the trie node blob []byte // Cached data block of the trie node
parents int // Number of live nodes referencing this one parents int // Number of live nodes referencing this one
children map[common.Hash]int // Children referenced by this nodes children map[common.Hash]struct{} // Children referenced by this nodes
} }
// NewDatabase creates a new trie database to store ephemeral trie content before // NewDatabase creates a new trie database to store ephemeral trie content before
@ -72,7 +72,7 @@ func NewDatabase(diskdb ethdb.Database) *Database {
return &Database{ return &Database{
diskdb: diskdb, diskdb: diskdb,
nodes: map[common.Hash]*cachedNode{ nodes: map[common.Hash]*cachedNode{
common.Hash{}: {children: make(map[common.Hash]int)}, common.Hash{}: {children: make(map[common.Hash]struct{})},
}, },
preimages: make(map[common.Hash][]byte), preimages: make(map[common.Hash][]byte),
} }
@ -99,7 +99,7 @@ func (db *Database) insert(hash common.Hash, blob []byte) {
} }
db.nodes[hash] = &cachedNode{ db.nodes[hash] = &cachedNode{
blob: common.CopyBytes(blob), blob: common.CopyBytes(blob),
children: make(map[common.Hash]int), children: make(map[common.Hash]struct{}),
} }
db.size += common.StorageSize(common.HashLength + len(blob)) db.size += common.StorageSize(common.HashLength + len(blob))
} }
@ -185,8 +185,12 @@ func (db *Database) reference(child common.Hash, parent common.Hash) {
if !ok { if !ok {
return return
} }
// If the reference already exists, don't duplicate it
if _, ok = db.nodes[parent].children[child]; ok {
return
}
node.parents++ node.parents++
db.nodes[parent].children[child]++ db.nodes[parent].children[child] = struct{}{}
} }
// Dereference removes an existing reference from a parent node to a child node. // Dereference removes an existing reference from a parent node to a child node.
@ -200,17 +204,16 @@ func (db *Database) Dereference(child common.Hash, parent common.Hash) {
db.gcnodes += uint64(nodes - len(db.nodes)) db.gcnodes += uint64(nodes - len(db.nodes))
db.gcsize += storage - db.size db.gcsize += storage - db.size
db.gctime += time.Since(start) db.gctime += time.Since(start)
log.Debug("Dereferenced trie from memory database", "nodes", nodes-len(db.nodes), "size", storage-db.size, "time", time.Since(start),
"gcnodes", db.gcnodes, "gcsize", db.gcsize, "gctime", db.gctime, "livenodes", len(db.nodes), "livesize", db.size)
} }
// dereference is the private locked version of Dereference. // dereference is the private locked version of Dereference.
func (db *Database) dereference(child common.Hash, parent common.Hash) { func (db *Database) dereference(child common.Hash, parent common.Hash) {
// Dereference the parent-child // Dereference the parent-child relationship
node := db.nodes[parent] delete(db.nodes[parent].children, child)
node.children[child]--
if node.children[child] == 0 {
delete(node.children, child)
}
// If the node does not exist, it's a previously comitted node. // If the node does not exist, it's a previously comitted node.
node, ok := db.nodes[child] node, ok := db.nodes[child]
if !ok { if !ok {
@ -271,7 +274,7 @@ func (db *Database) Commit(node common.Hash) error {
db.preimages = make(map[common.Hash][]byte) db.preimages = make(map[common.Hash][]byte)
db.uncache(node) db.uncache(node)
log.Debug("Persisted trie from memory database", "nodes", nodes-len(db.nodes), "size", storage-db.size, "time", time.Since(start), log.Info("Persisted trie from memory database", "nodes", nodes-len(db.nodes), "size", storage-db.size, "time", time.Since(start),
"gcnodes", db.gcnodes, "gcsize", db.gcsize, "gctime", db.gctime, "livenodes", len(db.nodes), "livesize", db.size) "gcnodes", db.gcnodes, "gcsize", db.gcsize, "gctime", db.gctime, "livenodes", len(db.nodes), "livesize", db.size)
// Reset the garbage collection statistics // Reset the garbage collection statistics