github.com/luckypickle/go-ethereum-vet@v1.14.2/trie/database.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package trie 18 19 import ( 20 "fmt" 21 "io" 22 "sync" 23 "time" 24 25 "github.com/luckypickle/go-ethereum-vet/common" 26 "github.com/luckypickle/go-ethereum-vet/ethdb" 27 "github.com/luckypickle/go-ethereum-vet/log" 28 "github.com/luckypickle/go-ethereum-vet/metrics" 29 "github.com/luckypickle/go-ethereum-vet/rlp" 30 ) 31 32 var ( 33 memcacheFlushTimeTimer = metrics.NewRegisteredResettingTimer("trie/memcache/flush/time", nil) 34 memcacheFlushNodesMeter = metrics.NewRegisteredMeter("trie/memcache/flush/nodes", nil) 35 memcacheFlushSizeMeter = metrics.NewRegisteredMeter("trie/memcache/flush/size", nil) 36 37 memcacheGCTimeTimer = metrics.NewRegisteredResettingTimer("trie/memcache/gc/time", nil) 38 memcacheGCNodesMeter = metrics.NewRegisteredMeter("trie/memcache/gc/nodes", nil) 39 memcacheGCSizeMeter = metrics.NewRegisteredMeter("trie/memcache/gc/size", nil) 40 41 memcacheCommitTimeTimer = metrics.NewRegisteredResettingTimer("trie/memcache/commit/time", nil) 42 memcacheCommitNodesMeter = metrics.NewRegisteredMeter("trie/memcache/commit/nodes", nil) 43 memcacheCommitSizeMeter = metrics.NewRegisteredMeter("trie/memcache/commit/size", nil) 44 ) 45 46 // secureKeyPrefix is the database key prefix used to store trie node preimages. 47 var secureKeyPrefix = []byte("secure-key-") 48 49 // secureKeyLength is the length of the above prefix + 32byte hash. 50 const secureKeyLength = 11 + 32 51 52 // DatabaseReader wraps the Get and Has method of a backing store for the trie. 53 type DatabaseReader interface { 54 // Get retrieves the value associated with key from the database. 55 Get(key []byte) (value []byte, err error) 56 57 // Has retrieves whether a key is present in the database. 58 Has(key []byte) (bool, error) 59 } 60 61 // Database is an intermediate write layer between the trie data structures and 62 // the disk database. The aim is to accumulate trie writes in-memory and only 63 // periodically flush a couple tries to disk, garbage collecting the remainder. 64 type Database struct { 65 diskdb ethdb.Database // Persistent storage for matured trie nodes 66 67 nodes map[common.Hash]*cachedNode // Data and references relationships of a node 68 oldest common.Hash // Oldest tracked node, flush-list head 69 newest common.Hash // Newest tracked node, flush-list tail 70 71 preimages map[common.Hash][]byte // Preimages of nodes from the secure trie 72 seckeybuf [secureKeyLength]byte // Ephemeral buffer for calculating preimage keys 73 74 gctime time.Duration // Time spent on garbage collection since last commit 75 gcnodes uint64 // Nodes garbage collected since last commit 76 gcsize common.StorageSize // Data storage garbage collected since last commit 77 78 flushtime time.Duration // Time spent on data flushing since last commit 79 flushnodes uint64 // Nodes flushed since last commit 80 flushsize common.StorageSize // Data storage flushed since last commit 81 82 nodesSize common.StorageSize // Storage size of the nodes cache (exc. flushlist) 83 preimagesSize common.StorageSize // Storage size of the preimages cache 84 85 lock sync.RWMutex 86 } 87 88 // rawNode is a simple binary blob used to differentiate between collapsed trie 89 // nodes and already encoded RLP binary blobs (while at the same time store them 90 // in the same cache fields). 91 type rawNode []byte 92 93 func (n rawNode) canUnload(uint16, uint16) bool { panic("this should never end up in a live trie") } 94 func (n rawNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } 95 func (n rawNode) fstring(ind string) string { panic("this should never end up in a live trie") } 96 97 // rawFullNode represents only the useful data content of a full node, with the 98 // caches and flags stripped out to minimize its data storage. This type honors 99 // the same RLP encoding as the original parent. 100 type rawFullNode [17]node 101 102 func (n rawFullNode) canUnload(uint16, uint16) bool { panic("this should never end up in a live trie") } 103 func (n rawFullNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } 104 func (n rawFullNode) fstring(ind string) string { panic("this should never end up in a live trie") } 105 106 func (n rawFullNode) EncodeRLP(w io.Writer) error { 107 var nodes [17]node 108 109 for i, child := range n { 110 if child != nil { 111 nodes[i] = child 112 } else { 113 nodes[i] = nilValueNode 114 } 115 } 116 return rlp.Encode(w, nodes) 117 } 118 119 // rawShortNode represents only the useful data content of a short node, with the 120 // caches and flags stripped out to minimize its data storage. This type honors 121 // the same RLP encoding as the original parent. 122 type rawShortNode struct { 123 Key []byte 124 Val node 125 } 126 127 func (n rawShortNode) canUnload(uint16, uint16) bool { 128 panic("this should never end up in a live trie") 129 } 130 func (n rawShortNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } 131 func (n rawShortNode) fstring(ind string) string { panic("this should never end up in a live trie") } 132 133 // cachedNode is all the information we know about a single cached node in the 134 // memory database write layer. 135 type cachedNode struct { 136 node node // Cached collapsed trie node, or raw rlp data 137 size uint16 // Byte size of the useful cached data 138 139 parents uint16 // Number of live nodes referencing this one 140 children map[common.Hash]uint16 // External children referenced by this node 141 142 flushPrev common.Hash // Previous node in the flush-list 143 flushNext common.Hash // Next node in the flush-list 144 } 145 146 // rlp returns the raw rlp encoded blob of the cached node, either directly from 147 // the cache, or by regenerating it from the collapsed node. 148 func (n *cachedNode) rlp() []byte { 149 if node, ok := n.node.(rawNode); ok { 150 return node 151 } 152 blob, err := rlp.EncodeToBytes(n.node) 153 if err != nil { 154 panic(err) 155 } 156 return blob 157 } 158 159 // obj returns the decoded and expanded trie node, either directly from the cache, 160 // or by regenerating it from the rlp encoded blob. 161 func (n *cachedNode) obj(hash common.Hash, cachegen uint16) node { 162 if node, ok := n.node.(rawNode); ok { 163 return mustDecodeNode(hash[:], node, cachegen) 164 } 165 return expandNode(hash[:], n.node, cachegen) 166 } 167 168 // childs returns all the tracked children of this node, both the implicit ones 169 // from inside the node as well as the explicit ones from outside the node. 170 func (n *cachedNode) childs() []common.Hash { 171 children := make([]common.Hash, 0, 16) 172 for child := range n.children { 173 children = append(children, child) 174 } 175 if _, ok := n.node.(rawNode); !ok { 176 gatherChildren(n.node, &children) 177 } 178 return children 179 } 180 181 // gatherChildren traverses the node hierarchy of a collapsed storage node and 182 // retrieves all the hashnode children. 183 func gatherChildren(n node, children *[]common.Hash) { 184 switch n := n.(type) { 185 case *rawShortNode: 186 gatherChildren(n.Val, children) 187 188 case rawFullNode: 189 for i := 0; i < 16; i++ { 190 gatherChildren(n[i], children) 191 } 192 case hashNode: 193 *children = append(*children, common.BytesToHash(n)) 194 195 case valueNode, nil: 196 197 default: 198 panic(fmt.Sprintf("unknown node type: %T", n)) 199 } 200 } 201 202 // simplifyNode traverses the hierarchy of an expanded memory node and discards 203 // all the internal caches, returning a node that only contains the raw data. 204 func simplifyNode(n node) node { 205 switch n := n.(type) { 206 case *shortNode: 207 // Short nodes discard the flags and cascade 208 return &rawShortNode{Key: n.Key, Val: simplifyNode(n.Val)} 209 210 case *fullNode: 211 // Full nodes discard the flags and cascade 212 node := rawFullNode(n.Children) 213 for i := 0; i < len(node); i++ { 214 if node[i] != nil { 215 node[i] = simplifyNode(node[i]) 216 } 217 } 218 return node 219 220 case valueNode, hashNode, rawNode: 221 return n 222 223 default: 224 panic(fmt.Sprintf("unknown node type: %T", n)) 225 } 226 } 227 228 // expandNode traverses the node hierarchy of a collapsed storage node and converts 229 // all fields and keys into expanded memory form. 230 func expandNode(hash hashNode, n node, cachegen uint16) node { 231 switch n := n.(type) { 232 case *rawShortNode: 233 // Short nodes need key and child expansion 234 return &shortNode{ 235 Key: compactToHex(n.Key), 236 Val: expandNode(nil, n.Val, cachegen), 237 flags: nodeFlag{ 238 hash: hash, 239 gen: cachegen, 240 }, 241 } 242 243 case rawFullNode: 244 // Full nodes need child expansion 245 node := &fullNode{ 246 flags: nodeFlag{ 247 hash: hash, 248 gen: cachegen, 249 }, 250 } 251 for i := 0; i < len(node.Children); i++ { 252 if n[i] != nil { 253 node.Children[i] = expandNode(nil, n[i], cachegen) 254 } 255 } 256 return node 257 258 case valueNode, hashNode: 259 return n 260 261 default: 262 panic(fmt.Sprintf("unknown node type: %T", n)) 263 } 264 } 265 266 // NewDatabase creates a new trie database to store ephemeral trie content before 267 // its written out to disk or garbage collected. 268 func NewDatabase(diskdb ethdb.Database) *Database { 269 return &Database{ 270 diskdb: diskdb, 271 nodes: map[common.Hash]*cachedNode{{}: {}}, 272 preimages: make(map[common.Hash][]byte), 273 } 274 } 275 276 // DiskDB retrieves the persistent storage backing the trie database. 277 func (db *Database) DiskDB() DatabaseReader { 278 return db.diskdb 279 } 280 281 // InsertBlob writes a new reference tracked blob to the memory database if it's 282 // yet unknown. This method should only be used for non-trie nodes that require 283 // reference counting, since trie nodes are garbage collected directly through 284 // their embedded children. 285 func (db *Database) InsertBlob(hash common.Hash, blob []byte) { 286 db.lock.Lock() 287 defer db.lock.Unlock() 288 289 db.insert(hash, blob, rawNode(blob)) 290 } 291 292 // insert inserts a collapsed trie node into the memory database. This method is 293 // a more generic version of InsertBlob, supporting both raw blob insertions as 294 // well ex trie node insertions. The blob must always be specified to allow proper 295 // size tracking. 296 func (db *Database) insert(hash common.Hash, blob []byte, node node) { 297 // If the node's already cached, skip 298 if _, ok := db.nodes[hash]; ok { 299 return 300 } 301 // Create the cached entry for this node 302 entry := &cachedNode{ 303 node: simplifyNode(node), 304 size: uint16(len(blob)), 305 flushPrev: db.newest, 306 } 307 for _, child := range entry.childs() { 308 if c := db.nodes[child]; c != nil { 309 c.parents++ 310 } 311 } 312 db.nodes[hash] = entry 313 314 // Update the flush-list endpoints 315 if db.oldest == (common.Hash{}) { 316 db.oldest, db.newest = hash, hash 317 } else { 318 db.nodes[db.newest].flushNext, db.newest = hash, hash 319 } 320 db.nodesSize += common.StorageSize(common.HashLength + entry.size) 321 } 322 323 // insertPreimage writes a new trie node pre-image to the memory database if it's 324 // yet unknown. The method will make a copy of the slice. 325 // 326 // Note, this method assumes that the database's lock is held! 327 func (db *Database) insertPreimage(hash common.Hash, preimage []byte) { 328 if _, ok := db.preimages[hash]; ok { 329 return 330 } 331 db.preimages[hash] = common.CopyBytes(preimage) 332 db.preimagesSize += common.StorageSize(common.HashLength + len(preimage)) 333 } 334 335 // node retrieves a cached trie node from memory, or returns nil if none can be 336 // found in the memory cache. 337 func (db *Database) node(hash common.Hash, cachegen uint16) node { 338 // Retrieve the node from cache if available 339 db.lock.RLock() 340 node := db.nodes[hash] 341 db.lock.RUnlock() 342 343 if node != nil { 344 return node.obj(hash, cachegen) 345 } 346 // Content unavailable in memory, attempt to retrieve from disk 347 enc, err := db.diskdb.Get(hash[:]) 348 if err != nil || enc == nil { 349 return nil 350 } 351 return mustDecodeNode(hash[:], enc, cachegen) 352 } 353 354 // Node retrieves an encoded cached trie node from memory. If it cannot be found 355 // cached, the method queries the persistent database for the content. 356 func (db *Database) Node(hash common.Hash) ([]byte, error) { 357 // Retrieve the node from cache if available 358 db.lock.RLock() 359 node := db.nodes[hash] 360 db.lock.RUnlock() 361 362 if node != nil { 363 return node.rlp(), nil 364 } 365 // Content unavailable in memory, attempt to retrieve from disk 366 return db.diskdb.Get(hash[:]) 367 } 368 369 // preimage retrieves a cached trie node pre-image from memory. If it cannot be 370 // found cached, the method queries the persistent database for the content. 371 func (db *Database) preimage(hash common.Hash) ([]byte, error) { 372 // Retrieve the node from cache if available 373 db.lock.RLock() 374 preimage := db.preimages[hash] 375 db.lock.RUnlock() 376 377 if preimage != nil { 378 return preimage, nil 379 } 380 // Content unavailable in memory, attempt to retrieve from disk 381 return db.diskdb.Get(db.secureKey(hash[:])) 382 } 383 384 // secureKey returns the database key for the preimage of key, as an ephemeral 385 // buffer. The caller must not hold onto the return value because it will become 386 // invalid on the next call. 387 func (db *Database) secureKey(key []byte) []byte { 388 buf := append(db.seckeybuf[:0], secureKeyPrefix...) 389 buf = append(buf, key...) 390 return buf 391 } 392 393 // Nodes retrieves the hashes of all the nodes cached within the memory database. 394 // This method is extremely expensive and should only be used to validate internal 395 // states in test code. 396 func (db *Database) Nodes() []common.Hash { 397 db.lock.RLock() 398 defer db.lock.RUnlock() 399 400 var hashes = make([]common.Hash, 0, len(db.nodes)) 401 for hash := range db.nodes { 402 if hash != (common.Hash{}) { // Special case for "root" references/nodes 403 hashes = append(hashes, hash) 404 } 405 } 406 return hashes 407 } 408 409 // Reference adds a new reference from a parent node to a child node. 410 func (db *Database) Reference(child common.Hash, parent common.Hash) { 411 db.lock.RLock() 412 defer db.lock.RUnlock() 413 414 db.reference(child, parent) 415 } 416 417 // reference is the private locked version of Reference. 418 func (db *Database) reference(child common.Hash, parent common.Hash) { 419 // If the node does not exist, it's a node pulled from disk, skip 420 node, ok := db.nodes[child] 421 if !ok { 422 return 423 } 424 // If the reference already exists, only duplicate for roots 425 if db.nodes[parent].children == nil { 426 db.nodes[parent].children = make(map[common.Hash]uint16) 427 } else if _, ok = db.nodes[parent].children[child]; ok && parent != (common.Hash{}) { 428 return 429 } 430 node.parents++ 431 db.nodes[parent].children[child]++ 432 } 433 434 // Dereference removes an existing reference from a root node. 435 func (db *Database) Dereference(root common.Hash) { 436 // Sanity check to ensure that the meta-root is not removed 437 if root == (common.Hash{}) { 438 log.Error("Attempted to dereference the trie cache meta root") 439 return 440 } 441 db.lock.Lock() 442 defer db.lock.Unlock() 443 444 nodes, storage, start := len(db.nodes), db.nodesSize, time.Now() 445 db.dereference(root, common.Hash{}) 446 447 db.gcnodes += uint64(nodes - len(db.nodes)) 448 db.gcsize += storage - db.nodesSize 449 db.gctime += time.Since(start) 450 451 memcacheGCTimeTimer.Update(time.Since(start)) 452 memcacheGCSizeMeter.Mark(int64(storage - db.nodesSize)) 453 memcacheGCNodesMeter.Mark(int64(nodes - len(db.nodes))) 454 455 log.Debug("Dereferenced trie from memory database", "nodes", nodes-len(db.nodes), "size", storage-db.nodesSize, "time", time.Since(start), 456 "gcnodes", db.gcnodes, "gcsize", db.gcsize, "gctime", db.gctime, "livenodes", len(db.nodes), "livesize", db.nodesSize) 457 } 458 459 // dereference is the private locked version of Dereference. 460 func (db *Database) dereference(child common.Hash, parent common.Hash) { 461 // Dereference the parent-child 462 node := db.nodes[parent] 463 464 if node.children != nil && node.children[child] > 0 { 465 node.children[child]-- 466 if node.children[child] == 0 { 467 delete(node.children, child) 468 } 469 } 470 // If the child does not exist, it's a previously committed node. 471 node, ok := db.nodes[child] 472 if !ok { 473 return 474 } 475 // If there are no more references to the child, delete it and cascade 476 if node.parents > 0 { 477 // This is a special cornercase where a node loaded from disk (i.e. not in the 478 // memcache any more) gets reinjected as a new node (short node split into full, 479 // then reverted into short), causing a cached node to have no parents. That is 480 // no problem in itself, but don't make maxint parents out of it. 481 node.parents-- 482 } 483 if node.parents == 0 { 484 // Remove the node from the flush-list 485 switch child { 486 case db.oldest: 487 db.oldest = node.flushNext 488 db.nodes[node.flushNext].flushPrev = common.Hash{} 489 case db.newest: 490 db.newest = node.flushPrev 491 db.nodes[node.flushPrev].flushNext = common.Hash{} 492 default: 493 db.nodes[node.flushPrev].flushNext = node.flushNext 494 db.nodes[node.flushNext].flushPrev = node.flushPrev 495 } 496 // Dereference all children and delete the node 497 for _, hash := range node.childs() { 498 db.dereference(hash, child) 499 } 500 delete(db.nodes, child) 501 db.nodesSize -= common.StorageSize(common.HashLength + int(node.size)) 502 } 503 } 504 505 // Cap iteratively flushes old but still referenced trie nodes until the total 506 // memory usage goes below the given threshold. 507 func (db *Database) Cap(limit common.StorageSize) error { 508 // Create a database batch to flush persistent data out. It is important that 509 // outside code doesn't see an inconsistent state (referenced data removed from 510 // memory cache during commit but not yet in persistent storage). This is ensured 511 // by only uncaching existing data when the database write finalizes. 512 db.lock.RLock() 513 514 nodes, storage, start := len(db.nodes), db.nodesSize, time.Now() 515 batch := db.diskdb.NewBatch() 516 517 // db.nodesSize only contains the useful data in the cache, but when reporting 518 // the total memory consumption, the maintenance metadata is also needed to be 519 // counted. For every useful node, we track 2 extra hashes as the flushlist. 520 size := db.nodesSize + common.StorageSize((len(db.nodes)-1)*2*common.HashLength) 521 522 // If the preimage cache got large enough, push to disk. If it's still small 523 // leave for later to deduplicate writes. 524 flushPreimages := db.preimagesSize > 4*1024*1024 525 if flushPreimages { 526 for hash, preimage := range db.preimages { 527 if err := batch.Put(db.secureKey(hash[:]), preimage); err != nil { 528 log.Error("Failed to commit preimage from trie database", "err", err) 529 db.lock.RUnlock() 530 return err 531 } 532 if batch.ValueSize() > ethdb.IdealBatchSize { 533 if err := batch.Write(); err != nil { 534 db.lock.RUnlock() 535 return err 536 } 537 batch.Reset() 538 } 539 } 540 } 541 // Keep committing nodes from the flush-list until we're below allowance 542 oldest := db.oldest 543 for size > limit && oldest != (common.Hash{}) { 544 // Fetch the oldest referenced node and push into the batch 545 node := db.nodes[oldest] 546 if err := batch.Put(oldest[:], node.rlp()); err != nil { 547 db.lock.RUnlock() 548 return err 549 } 550 // If we exceeded the ideal batch size, commit and reset 551 if batch.ValueSize() >= ethdb.IdealBatchSize { 552 if err := batch.Write(); err != nil { 553 log.Error("Failed to write flush list to disk", "err", err) 554 db.lock.RUnlock() 555 return err 556 } 557 batch.Reset() 558 } 559 // Iterate to the next flush item, or abort if the size cap was achieved. Size 560 // is the total size, including both the useful cached data (hash -> blob), as 561 // well as the flushlist metadata (2*hash). When flushing items from the cache, 562 // we need to reduce both. 563 size -= common.StorageSize(3*common.HashLength + int(node.size)) 564 oldest = node.flushNext 565 } 566 // Flush out any remainder data from the last batch 567 if err := batch.Write(); err != nil { 568 log.Error("Failed to write flush list to disk", "err", err) 569 db.lock.RUnlock() 570 return err 571 } 572 db.lock.RUnlock() 573 574 // Write successful, clear out the flushed data 575 db.lock.Lock() 576 defer db.lock.Unlock() 577 578 if flushPreimages { 579 db.preimages = make(map[common.Hash][]byte) 580 db.preimagesSize = 0 581 } 582 for db.oldest != oldest { 583 node := db.nodes[db.oldest] 584 delete(db.nodes, db.oldest) 585 db.oldest = node.flushNext 586 587 db.nodesSize -= common.StorageSize(common.HashLength + int(node.size)) 588 } 589 if db.oldest != (common.Hash{}) { 590 db.nodes[db.oldest].flushPrev = common.Hash{} 591 } 592 db.flushnodes += uint64(nodes - len(db.nodes)) 593 db.flushsize += storage - db.nodesSize 594 db.flushtime += time.Since(start) 595 596 memcacheFlushTimeTimer.Update(time.Since(start)) 597 memcacheFlushSizeMeter.Mark(int64(storage - db.nodesSize)) 598 memcacheFlushNodesMeter.Mark(int64(nodes - len(db.nodes))) 599 600 log.Debug("Persisted nodes from memory database", "nodes", nodes-len(db.nodes), "size", storage-db.nodesSize, "time", time.Since(start), 601 "flushnodes", db.flushnodes, "flushsize", db.flushsize, "flushtime", db.flushtime, "livenodes", len(db.nodes), "livesize", db.nodesSize) 602 603 return nil 604 } 605 606 // Commit iterates over all the children of a particular node, writes them out 607 // to disk, forcefully tearing down all references in both directions. 608 // 609 // As a side effect, all pre-images accumulated up to this point are also written. 610 func (db *Database) Commit(node common.Hash, report bool) error { 611 // Create a database batch to flush persistent data out. It is important that 612 // outside code doesn't see an inconsistent state (referenced data removed from 613 // memory cache during commit but not yet in persistent storage). This is ensured 614 // by only uncaching existing data when the database write finalizes. 615 db.lock.RLock() 616 617 start := time.Now() 618 batch := db.diskdb.NewBatch() 619 620 // Move all of the accumulated preimages into a write batch 621 for hash, preimage := range db.preimages { 622 if err := batch.Put(db.secureKey(hash[:]), preimage); err != nil { 623 log.Error("Failed to commit preimage from trie database", "err", err) 624 db.lock.RUnlock() 625 return err 626 } 627 if batch.ValueSize() > ethdb.IdealBatchSize { 628 if err := batch.Write(); err != nil { 629 return err 630 } 631 batch.Reset() 632 } 633 } 634 // Move the trie itself into the batch, flushing if enough data is accumulated 635 nodes, storage := len(db.nodes), db.nodesSize 636 if err := db.commit(node, batch); err != nil { 637 log.Error("Failed to commit trie from trie database", "err", err) 638 db.lock.RUnlock() 639 return err 640 } 641 // Write batch ready, unlock for readers during persistence 642 if err := batch.Write(); err != nil { 643 log.Error("Failed to write trie to disk", "err", err) 644 db.lock.RUnlock() 645 return err 646 } 647 db.lock.RUnlock() 648 649 // Write successful, clear out the flushed data 650 db.lock.Lock() 651 defer db.lock.Unlock() 652 653 db.preimages = make(map[common.Hash][]byte) 654 db.preimagesSize = 0 655 656 db.uncache(node) 657 658 memcacheCommitTimeTimer.Update(time.Since(start)) 659 memcacheCommitSizeMeter.Mark(int64(storage - db.nodesSize)) 660 memcacheCommitNodesMeter.Mark(int64(nodes - len(db.nodes))) 661 662 logger := log.Info 663 if !report { 664 logger = log.Debug 665 } 666 logger("Persisted trie from memory database", "nodes", nodes-len(db.nodes)+int(db.flushnodes), "size", storage-db.nodesSize+db.flushsize, "time", time.Since(start)+db.flushtime, 667 "gcnodes", db.gcnodes, "gcsize", db.gcsize, "gctime", db.gctime, "livenodes", len(db.nodes), "livesize", db.nodesSize) 668 669 // Reset the garbage collection statistics 670 db.gcnodes, db.gcsize, db.gctime = 0, 0, 0 671 db.flushnodes, db.flushsize, db.flushtime = 0, 0, 0 672 673 return nil 674 } 675 676 // commit is the private locked version of Commit. 677 func (db *Database) commit(hash common.Hash, batch ethdb.Batch) error { 678 // If the node does not exist, it's a previously committed node 679 node, ok := db.nodes[hash] 680 if !ok { 681 return nil 682 } 683 for _, child := range node.childs() { 684 if err := db.commit(child, batch); err != nil { 685 return err 686 } 687 } 688 if err := batch.Put(hash[:], node.rlp()); err != nil { 689 return err 690 } 691 // If we've reached an optimal batch size, commit and start over 692 if batch.ValueSize() >= ethdb.IdealBatchSize { 693 if err := batch.Write(); err != nil { 694 return err 695 } 696 batch.Reset() 697 } 698 return nil 699 } 700 701 // uncache is the post-processing step of a commit operation where the already 702 // persisted trie is removed from the cache. The reason behind the two-phase 703 // commit is to ensure consistent data availability while moving from memory 704 // to disk. 705 func (db *Database) uncache(hash common.Hash) { 706 // If the node does not exist, we're done on this path 707 node, ok := db.nodes[hash] 708 if !ok { 709 return 710 } 711 // Node still exists, remove it from the flush-list 712 switch hash { 713 case db.oldest: 714 db.oldest = node.flushNext 715 db.nodes[node.flushNext].flushPrev = common.Hash{} 716 case db.newest: 717 db.newest = node.flushPrev 718 db.nodes[node.flushPrev].flushNext = common.Hash{} 719 default: 720 db.nodes[node.flushPrev].flushNext = node.flushNext 721 db.nodes[node.flushNext].flushPrev = node.flushPrev 722 } 723 // Uncache the node's subtries and remove the node itself too 724 for _, child := range node.childs() { 725 db.uncache(child) 726 } 727 delete(db.nodes, hash) 728 db.nodesSize -= common.StorageSize(common.HashLength + int(node.size)) 729 } 730 731 // Size returns the current storage size of the memory cache in front of the 732 // persistent database layer. 733 func (db *Database) Size() (common.StorageSize, common.StorageSize) { 734 db.lock.RLock() 735 defer db.lock.RUnlock() 736 737 // db.nodesSize only contains the useful data in the cache, but when reporting 738 // the total memory consumption, the maintenance metadata is also needed to be 739 // counted. For every useful node, we track 2 extra hashes as the flushlist. 740 var flushlistSize = common.StorageSize((len(db.nodes) - 1) * 2 * common.HashLength) 741 return db.nodesSize + flushlistSize, db.preimagesSize 742 } 743 744 // verifyIntegrity is a debug method to iterate over the entire trie stored in 745 // memory and check whether every node is reachable from the meta root. The goal 746 // is to find any errors that might cause memory leaks and or trie nodes to go 747 // missing. 748 // 749 // This method is extremely CPU and memory intensive, only use when must. 750 func (db *Database) verifyIntegrity() { 751 // Iterate over all the cached nodes and accumulate them into a set 752 reachable := map[common.Hash]struct{}{{}: {}} 753 754 for child := range db.nodes[common.Hash{}].children { 755 db.accumulate(child, reachable) 756 } 757 // Find any unreachable but cached nodes 758 unreachable := []string{} 759 for hash, node := range db.nodes { 760 if _, ok := reachable[hash]; !ok { 761 unreachable = append(unreachable, fmt.Sprintf("%x: {Node: %v, Parents: %d, Prev: %x, Next: %x}", 762 hash, node.node, node.parents, node.flushPrev, node.flushNext)) 763 } 764 } 765 if len(unreachable) != 0 { 766 panic(fmt.Sprintf("trie cache memory leak: %v", unreachable)) 767 } 768 } 769 770 // accumulate iterates over the trie defined by hash and accumulates all the 771 // cached children found in memory. 772 func (db *Database) accumulate(hash common.Hash, reachable map[common.Hash]struct{}) { 773 // Mark the node reachable if present in the memory cache 774 node, ok := db.nodes[hash] 775 if !ok { 776 return 777 } 778 reachable[hash] = struct{}{} 779 780 // Iterate over all the children and accumulate them too 781 for _, child := range node.childs() { 782 db.accumulate(child, reachable) 783 } 784 }