github.com/daethereum/go-dae@v2.2.3+incompatible/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 "errors" 21 "fmt" 22 "io" 23 "reflect" 24 "runtime" 25 "sync" 26 "time" 27 28 "github.com/VictoriaMetrics/fastcache" 29 "github.com/daethereum/go-dae/common" 30 "github.com/daethereum/go-dae/core/rawdb" 31 "github.com/daethereum/go-dae/ethdb" 32 "github.com/daethereum/go-dae/log" 33 "github.com/daethereum/go-dae/metrics" 34 "github.com/daethereum/go-dae/rlp" 35 ) 36 37 var ( 38 memcacheCleanHitMeter = metrics.NewRegisteredMeter("trie/memcache/clean/hit", nil) 39 memcacheCleanMissMeter = metrics.NewRegisteredMeter("trie/memcache/clean/miss", nil) 40 memcacheCleanReadMeter = metrics.NewRegisteredMeter("trie/memcache/clean/read", nil) 41 memcacheCleanWriteMeter = metrics.NewRegisteredMeter("trie/memcache/clean/write", nil) 42 43 memcacheDirtyHitMeter = metrics.NewRegisteredMeter("trie/memcache/dirty/hit", nil) 44 memcacheDirtyMissMeter = metrics.NewRegisteredMeter("trie/memcache/dirty/miss", nil) 45 memcacheDirtyReadMeter = metrics.NewRegisteredMeter("trie/memcache/dirty/read", nil) 46 memcacheDirtyWriteMeter = metrics.NewRegisteredMeter("trie/memcache/dirty/write", nil) 47 48 memcacheFlushTimeTimer = metrics.NewRegisteredResettingTimer("trie/memcache/flush/time", nil) 49 memcacheFlushNodesMeter = metrics.NewRegisteredMeter("trie/memcache/flush/nodes", nil) 50 memcacheFlushSizeMeter = metrics.NewRegisteredMeter("trie/memcache/flush/size", nil) 51 52 memcacheGCTimeTimer = metrics.NewRegisteredResettingTimer("trie/memcache/gc/time", nil) 53 memcacheGCNodesMeter = metrics.NewRegisteredMeter("trie/memcache/gc/nodes", nil) 54 memcacheGCSizeMeter = metrics.NewRegisteredMeter("trie/memcache/gc/size", nil) 55 56 memcacheCommitTimeTimer = metrics.NewRegisteredResettingTimer("trie/memcache/commit/time", nil) 57 memcacheCommitNodesMeter = metrics.NewRegisteredMeter("trie/memcache/commit/nodes", nil) 58 memcacheCommitSizeMeter = metrics.NewRegisteredMeter("trie/memcache/commit/size", nil) 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 // 65 // Note, the trie Database is **not** thread safe in its mutations, but it **is** 66 // thread safe in providing individual, independent node access. The rationale 67 // behind this split design is to provide read access to RPC handlers and sync 68 // servers even while the trie is executing expensive garbage collection. 69 type Database struct { 70 diskdb ethdb.KeyValueStore // Persistent storage for matured trie nodes 71 72 cleans *fastcache.Cache // GC friendly memory cache of clean node RLPs 73 dirties map[common.Hash]*cachedNode // Data and references relationships of dirty trie nodes 74 oldest common.Hash // Oldest tracked node, flush-list head 75 newest common.Hash // Newest tracked node, flush-list tail 76 77 preimages map[common.Hash][]byte // Preimages of nodes from the secure trie 78 79 gctime time.Duration // Time spent on garbage collection since last commit 80 gcnodes uint64 // Nodes garbage collected since last commit 81 gcsize common.StorageSize // Data storage garbage collected since last commit 82 83 flushtime time.Duration // Time spent on data flushing since last commit 84 flushnodes uint64 // Nodes flushed since last commit 85 flushsize common.StorageSize // Data storage flushed since last commit 86 87 dirtiesSize common.StorageSize // Storage size of the dirty node cache (exc. metadata) 88 childrenSize common.StorageSize // Storage size of the external children tracking 89 preimagesSize common.StorageSize // Storage size of the preimages cache 90 91 lock sync.RWMutex 92 } 93 94 // rawNode is a simple binary blob used to differentiate between collapsed trie 95 // nodes and already encoded RLP binary blobs (while at the same time store them 96 // in the same cache fields). 97 type rawNode []byte 98 99 func (n rawNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } 100 func (n rawNode) fstring(ind string) string { panic("this should never end up in a live trie") } 101 102 func (n rawNode) EncodeRLP(w io.Writer) error { 103 _, err := w.Write(n) 104 return err 105 } 106 107 // rawFullNode represents only the useful data content of a full node, with the 108 // caches and flags stripped out to minimize its data storage. This type honors 109 // the same RLP encoding as the original parent. 110 type rawFullNode [17]node 111 112 func (n rawFullNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } 113 func (n rawFullNode) fstring(ind string) string { panic("this should never end up in a live trie") } 114 115 func (n rawFullNode) EncodeRLP(w io.Writer) error { 116 eb := rlp.NewEncoderBuffer(w) 117 n.encode(eb) 118 return eb.Flush() 119 } 120 121 // rawShortNode represents only the useful data content of a short node, with the 122 // caches and flags stripped out to minimize its data storage. This type honors 123 // the same RLP encoding as the original parent. 124 type rawShortNode struct { 125 Key []byte 126 Val node 127 } 128 129 func (n rawShortNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } 130 func (n rawShortNode) fstring(ind string) string { panic("this should never end up in a live trie") } 131 132 // cachedNode is all the information we know about a single cached trie node 133 // in the memory database write layer. 134 type cachedNode struct { 135 node node // Cached collapsed trie node, or raw rlp data 136 size uint16 // Byte size of the useful cached data 137 138 parents uint32 // Number of live nodes referencing this one 139 children map[common.Hash]uint16 // External children referenced by this node 140 141 flushPrev common.Hash // Previous node in the flush-list 142 flushNext common.Hash // Next node in the flush-list 143 } 144 145 // cachedNodeSize is the raw size of a cachedNode data structure without any 146 // node data included. It's an approximate size, but should be a lot better 147 // than not counting them. 148 var cachedNodeSize = int(reflect.TypeOf(cachedNode{}).Size()) 149 150 // cachedNodeChildrenSize is the raw size of an initialized but empty external 151 // reference map. 152 const cachedNodeChildrenSize = 48 153 154 // rlp returns the raw rlp encoded blob of the cached trie node, either directly 155 // from the cache, or by regenerating it from the collapsed node. 156 func (n *cachedNode) rlp() []byte { 157 if node, ok := n.node.(rawNode); ok { 158 return node 159 } 160 return nodeToBytes(n.node) 161 } 162 163 // obj returns the decoded and expanded trie node, either directly from the cache, 164 // or by regenerating it from the rlp encoded blob. 165 func (n *cachedNode) obj(hash common.Hash) node { 166 if node, ok := n.node.(rawNode); ok { 167 return mustDecodeNode(hash[:], node) 168 } 169 return expandNode(hash[:], n.node) 170 } 171 172 // forChilds invokes the callback for all the tracked children of this node, 173 // both the implicit ones from inside the node as well as the explicit ones 174 // from outside the node. 175 func (n *cachedNode) forChilds(onChild func(hash common.Hash)) { 176 for child := range n.children { 177 onChild(child) 178 } 179 if _, ok := n.node.(rawNode); !ok { 180 forGatherChildren(n.node, onChild) 181 } 182 } 183 184 // forGatherChildren traverses the node hierarchy of a collapsed storage node and 185 // invokes the callback for all the hashnode children. 186 func forGatherChildren(n node, onChild func(hash common.Hash)) { 187 switch n := n.(type) { 188 case *rawShortNode: 189 forGatherChildren(n.Val, onChild) 190 case rawFullNode: 191 for i := 0; i < 16; i++ { 192 forGatherChildren(n[i], onChild) 193 } 194 case hashNode: 195 onChild(common.BytesToHash(n)) 196 case valueNode, nil, rawNode: 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) 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), 237 flags: nodeFlag{ 238 hash: hash, 239 }, 240 } 241 242 case rawFullNode: 243 // Full nodes need child expansion 244 node := &fullNode{ 245 flags: nodeFlag{ 246 hash: hash, 247 }, 248 } 249 for i := 0; i < len(node.Children); i++ { 250 if n[i] != nil { 251 node.Children[i] = expandNode(nil, n[i]) 252 } 253 } 254 return node 255 256 case valueNode, hashNode: 257 return n 258 259 default: 260 panic(fmt.Sprintf("unknown node type: %T", n)) 261 } 262 } 263 264 // Config defines all necessary options for database. 265 type Config struct { 266 Cache int // Memory allowance (MB) to use for caching trie nodes in memory 267 Journal string // Journal of clean cache to survive node restarts 268 Preimages bool // Flag whether the preimage of trie key is recorded 269 } 270 271 // NewDatabase creates a new trie database to store ephemeral trie content before 272 // its written out to disk or garbage collected. No read cache is created, so all 273 // data retrievals will hit the underlying disk database. 274 func NewDatabase(diskdb ethdb.KeyValueStore) *Database { 275 return NewDatabaseWithConfig(diskdb, nil) 276 } 277 278 // NewDatabaseWithConfig creates a new trie database to store ephemeral trie content 279 // before its written out to disk or garbage collected. It also acts as a read cache 280 // for nodes loaded from disk. 281 func NewDatabaseWithConfig(diskdb ethdb.KeyValueStore, config *Config) *Database { 282 var cleans *fastcache.Cache 283 if config != nil && config.Cache > 0 { 284 if config.Journal == "" { 285 cleans = fastcache.New(config.Cache * 1024 * 1024) 286 } else { 287 cleans = fastcache.LoadFromFileOrNew(config.Journal, config.Cache*1024*1024) 288 } 289 } 290 db := &Database{ 291 diskdb: diskdb, 292 cleans: cleans, 293 dirties: map[common.Hash]*cachedNode{{}: { 294 children: make(map[common.Hash]uint16), 295 }}, 296 } 297 if config == nil || config.Preimages { // TODO(karalabe): Flip to default off in the future 298 db.preimages = make(map[common.Hash][]byte) 299 } 300 return db 301 } 302 303 // DiskDB retrieves the persistent storage backing the trie database. 304 func (db *Database) DiskDB() ethdb.KeyValueStore { 305 return db.diskdb 306 } 307 308 // insert inserts a collapsed trie node into the memory database. 309 // The blob size must be specified to allow proper size tracking. 310 // All nodes inserted by this function will be reference tracked 311 // and in theory should only used for **trie nodes** insertion. 312 func (db *Database) insert(hash common.Hash, size int, node node) { 313 db.lock.Lock() 314 defer db.lock.Unlock() 315 316 // If the node's already cached, skip 317 if _, ok := db.dirties[hash]; ok { 318 return 319 } 320 memcacheDirtyWriteMeter.Mark(int64(size)) 321 322 // Create the cached entry for this node 323 entry := &cachedNode{ 324 node: simplifyNode(node), 325 size: uint16(size), 326 flushPrev: db.newest, 327 } 328 entry.forChilds(func(child common.Hash) { 329 if c := db.dirties[child]; c != nil { 330 c.parents++ 331 } 332 }) 333 db.dirties[hash] = entry 334 335 // Update the flush-list endpoints 336 if db.oldest == (common.Hash{}) { 337 db.oldest, db.newest = hash, hash 338 } else { 339 db.dirties[db.newest].flushNext, db.newest = hash, hash 340 } 341 db.dirtiesSize += common.StorageSize(common.HashLength + entry.size) 342 } 343 344 // insertPreimage writes a new trie node pre-image to the memory database if it's 345 // yet unknown. The method will NOT make a copy of the slice, 346 // only use if the preimage will NOT be changed later on. 347 // 348 // Note, this method assumes that the database's lock is held! 349 func (db *Database) insertPreimage(hash common.Hash, preimage []byte) { 350 // Short circuit if preimage collection is disabled 351 if db.preimages == nil { 352 return 353 } 354 // Track the preimage if a yet unknown one 355 if _, ok := db.preimages[hash]; ok { 356 return 357 } 358 db.preimages[hash] = preimage 359 db.preimagesSize += common.StorageSize(common.HashLength + len(preimage)) 360 } 361 362 // node retrieves a cached trie node from memory, or returns nil if none can be 363 // found in the memory cache. 364 func (db *Database) node(hash common.Hash) node { 365 // Retrieve the node from the clean cache if available 366 if db.cleans != nil { 367 if enc := db.cleans.Get(nil, hash[:]); enc != nil { 368 memcacheCleanHitMeter.Mark(1) 369 memcacheCleanReadMeter.Mark(int64(len(enc))) 370 return mustDecodeNode(hash[:], enc) 371 } 372 } 373 // Retrieve the node from the dirty cache if available 374 db.lock.RLock() 375 dirty := db.dirties[hash] 376 db.lock.RUnlock() 377 378 if dirty != nil { 379 memcacheDirtyHitMeter.Mark(1) 380 memcacheDirtyReadMeter.Mark(int64(dirty.size)) 381 return dirty.obj(hash) 382 } 383 memcacheDirtyMissMeter.Mark(1) 384 385 // Content unavailable in memory, attempt to retrieve from disk 386 enc, err := db.diskdb.Get(hash[:]) 387 if err != nil || enc == nil { 388 return nil 389 } 390 if db.cleans != nil { 391 db.cleans.Set(hash[:], enc) 392 memcacheCleanMissMeter.Mark(1) 393 memcacheCleanWriteMeter.Mark(int64(len(enc))) 394 } 395 return mustDecodeNode(hash[:], enc) 396 } 397 398 // Node retrieves an encoded cached trie node from memory. If it cannot be found 399 // cached, the method queries the persistent database for the content. 400 func (db *Database) Node(hash common.Hash) ([]byte, error) { 401 // It doesn't make sense to retrieve the metaroot 402 if hash == (common.Hash{}) { 403 return nil, errors.New("not found") 404 } 405 // Retrieve the node from the clean cache if available 406 if db.cleans != nil { 407 if enc := db.cleans.Get(nil, hash[:]); enc != nil { 408 memcacheCleanHitMeter.Mark(1) 409 memcacheCleanReadMeter.Mark(int64(len(enc))) 410 return enc, nil 411 } 412 } 413 // Retrieve the node from the dirty cache if available 414 db.lock.RLock() 415 dirty := db.dirties[hash] 416 db.lock.RUnlock() 417 418 if dirty != nil { 419 memcacheDirtyHitMeter.Mark(1) 420 memcacheDirtyReadMeter.Mark(int64(dirty.size)) 421 return dirty.rlp(), nil 422 } 423 memcacheDirtyMissMeter.Mark(1) 424 425 // Content unavailable in memory, attempt to retrieve from disk 426 enc := rawdb.ReadTrieNode(db.diskdb, hash) 427 if len(enc) != 0 { 428 if db.cleans != nil { 429 db.cleans.Set(hash[:], enc) 430 memcacheCleanMissMeter.Mark(1) 431 memcacheCleanWriteMeter.Mark(int64(len(enc))) 432 } 433 return enc, nil 434 } 435 return nil, errors.New("not found") 436 } 437 438 // preimage retrieves a cached trie node pre-image from memory. If it cannot be 439 // found cached, the method queries the persistent database for the content. 440 func (db *Database) preimage(hash common.Hash) []byte { 441 // Short circuit if preimage collection is disabled 442 if db.preimages == nil { 443 return nil 444 } 445 // Retrieve the node from cache if available 446 db.lock.RLock() 447 preimage := db.preimages[hash] 448 db.lock.RUnlock() 449 450 if preimage != nil { 451 return preimage 452 } 453 return rawdb.ReadPreimage(db.diskdb, hash) 454 } 455 456 // Nodes retrieves the hashes of all the nodes cached within the memory database. 457 // This method is extremely expensive and should only be used to validate internal 458 // states in test code. 459 func (db *Database) Nodes() []common.Hash { 460 db.lock.RLock() 461 defer db.lock.RUnlock() 462 463 var hashes = make([]common.Hash, 0, len(db.dirties)) 464 for hash := range db.dirties { 465 if hash != (common.Hash{}) { // Special case for "root" references/nodes 466 hashes = append(hashes, hash) 467 } 468 } 469 return hashes 470 } 471 472 // Reference adds a new reference from a parent node to a child node. 473 // This function is used to add reference between internal trie node 474 // and external node(e.g. storage trie root), all internal trie nodes 475 // are referenced together by database itself. 476 func (db *Database) Reference(child common.Hash, parent common.Hash) { 477 db.lock.Lock() 478 defer db.lock.Unlock() 479 480 db.reference(child, parent) 481 } 482 483 // reference is the private locked version of Reference. 484 func (db *Database) reference(child common.Hash, parent common.Hash) { 485 // If the node does not exist, it's a node pulled from disk, skip 486 node, ok := db.dirties[child] 487 if !ok { 488 return 489 } 490 // If the reference already exists, only duplicate for roots 491 if db.dirties[parent].children == nil { 492 db.dirties[parent].children = make(map[common.Hash]uint16) 493 db.childrenSize += cachedNodeChildrenSize 494 } else if _, ok = db.dirties[parent].children[child]; ok && parent != (common.Hash{}) { 495 return 496 } 497 node.parents++ 498 db.dirties[parent].children[child]++ 499 if db.dirties[parent].children[child] == 1 { 500 db.childrenSize += common.HashLength + 2 // uint16 counter 501 } 502 } 503 504 // Dereference removes an existing reference from a root node. 505 func (db *Database) Dereference(root common.Hash) { 506 // Sanity check to ensure that the meta-root is not removed 507 if root == (common.Hash{}) { 508 log.Error("Attempted to dereference the trie cache meta root") 509 return 510 } 511 db.lock.Lock() 512 defer db.lock.Unlock() 513 514 nodes, storage, start := len(db.dirties), db.dirtiesSize, time.Now() 515 db.dereference(root, common.Hash{}) 516 517 db.gcnodes += uint64(nodes - len(db.dirties)) 518 db.gcsize += storage - db.dirtiesSize 519 db.gctime += time.Since(start) 520 521 memcacheGCTimeTimer.Update(time.Since(start)) 522 memcacheGCSizeMeter.Mark(int64(storage - db.dirtiesSize)) 523 memcacheGCNodesMeter.Mark(int64(nodes - len(db.dirties))) 524 525 log.Debug("Dereferenced trie from memory database", "nodes", nodes-len(db.dirties), "size", storage-db.dirtiesSize, "time", time.Since(start), 526 "gcnodes", db.gcnodes, "gcsize", db.gcsize, "gctime", db.gctime, "livenodes", len(db.dirties), "livesize", db.dirtiesSize) 527 } 528 529 // dereference is the private locked version of Dereference. 530 func (db *Database) dereference(child common.Hash, parent common.Hash) { 531 // Dereference the parent-child 532 node := db.dirties[parent] 533 534 if node.children != nil && node.children[child] > 0 { 535 node.children[child]-- 536 if node.children[child] == 0 { 537 delete(node.children, child) 538 db.childrenSize -= (common.HashLength + 2) // uint16 counter 539 } 540 } 541 // If the child does not exist, it's a previously committed node. 542 node, ok := db.dirties[child] 543 if !ok { 544 return 545 } 546 // If there are no more references to the child, delete it and cascade 547 if node.parents > 0 { 548 // This is a special cornercase where a node loaded from disk (i.e. not in the 549 // memcache any more) gets reinjected as a new node (short node split into full, 550 // then reverted into short), causing a cached node to have no parents. That is 551 // no problem in itself, but don't make maxint parents out of it. 552 node.parents-- 553 } 554 if node.parents == 0 { 555 // Remove the node from the flush-list 556 switch child { 557 case db.oldest: 558 db.oldest = node.flushNext 559 db.dirties[node.flushNext].flushPrev = common.Hash{} 560 case db.newest: 561 db.newest = node.flushPrev 562 db.dirties[node.flushPrev].flushNext = common.Hash{} 563 default: 564 db.dirties[node.flushPrev].flushNext = node.flushNext 565 db.dirties[node.flushNext].flushPrev = node.flushPrev 566 } 567 // Dereference all children and delete the node 568 node.forChilds(func(hash common.Hash) { 569 db.dereference(hash, child) 570 }) 571 delete(db.dirties, child) 572 db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size)) 573 if node.children != nil { 574 db.childrenSize -= cachedNodeChildrenSize 575 } 576 } 577 } 578 579 // Cap iteratively flushes old but still referenced trie nodes until the total 580 // memory usage goes below the given threshold. 581 // 582 // Note, this method is a non-synchronized mutator. It is unsafe to call this 583 // concurrently with other mutators. 584 func (db *Database) Cap(limit common.StorageSize) error { 585 // Create a database batch to flush persistent data out. It is important that 586 // outside code doesn't see an inconsistent state (referenced data removed from 587 // memory cache during commit but not yet in persistent storage). This is ensured 588 // by only uncaching existing data when the database write finalizes. 589 nodes, storage, start := len(db.dirties), db.dirtiesSize, time.Now() 590 batch := db.diskdb.NewBatch() 591 592 // db.dirtiesSize only contains the useful data in the cache, but when reporting 593 // the total memory consumption, the maintenance metadata is also needed to be 594 // counted. 595 size := db.dirtiesSize + common.StorageSize((len(db.dirties)-1)*cachedNodeSize) 596 size += db.childrenSize - common.StorageSize(len(db.dirties[common.Hash{}].children)*(common.HashLength+2)) 597 598 // If the preimage cache got large enough, push to disk. If it's still small 599 // leave for later to deduplicate writes. 600 flushPreimages := db.preimagesSize > 4*1024*1024 601 if flushPreimages { 602 if db.preimages == nil { 603 log.Error("Attempted to write preimages whilst disabled") 604 } else { 605 rawdb.WritePreimages(batch, db.preimages) 606 if batch.ValueSize() > ethdb.IdealBatchSize { 607 if err := batch.Write(); err != nil { 608 return err 609 } 610 batch.Reset() 611 } 612 } 613 } 614 // Keep committing nodes from the flush-list until we're below allowance 615 oldest := db.oldest 616 for size > limit && oldest != (common.Hash{}) { 617 // Fetch the oldest referenced node and push into the batch 618 node := db.dirties[oldest] 619 rawdb.WriteTrieNode(batch, oldest, node.rlp()) 620 621 // If we exceeded the ideal batch size, commit and reset 622 if batch.ValueSize() >= ethdb.IdealBatchSize { 623 if err := batch.Write(); err != nil { 624 log.Error("Failed to write flush list to disk", "err", err) 625 return err 626 } 627 batch.Reset() 628 } 629 // Iterate to the next flush item, or abort if the size cap was achieved. Size 630 // is the total size, including the useful cached data (hash -> blob), the 631 // cache item metadata, as well as external children mappings. 632 size -= common.StorageSize(common.HashLength + int(node.size) + cachedNodeSize) 633 if node.children != nil { 634 size -= common.StorageSize(cachedNodeChildrenSize + len(node.children)*(common.HashLength+2)) 635 } 636 oldest = node.flushNext 637 } 638 // Flush out any remainder data from the last batch 639 if err := batch.Write(); err != nil { 640 log.Error("Failed to write flush list to disk", "err", err) 641 return err 642 } 643 // Write successful, clear out the flushed data 644 db.lock.Lock() 645 defer db.lock.Unlock() 646 647 if flushPreimages { 648 if db.preimages == nil { 649 log.Error("Attempted to reset preimage cache whilst disabled") 650 } else { 651 db.preimages, db.preimagesSize = make(map[common.Hash][]byte), 0 652 } 653 } 654 for db.oldest != oldest { 655 node := db.dirties[db.oldest] 656 delete(db.dirties, db.oldest) 657 db.oldest = node.flushNext 658 659 db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size)) 660 if node.children != nil { 661 db.childrenSize -= common.StorageSize(cachedNodeChildrenSize + len(node.children)*(common.HashLength+2)) 662 } 663 } 664 if db.oldest != (common.Hash{}) { 665 db.dirties[db.oldest].flushPrev = common.Hash{} 666 } 667 db.flushnodes += uint64(nodes - len(db.dirties)) 668 db.flushsize += storage - db.dirtiesSize 669 db.flushtime += time.Since(start) 670 671 memcacheFlushTimeTimer.Update(time.Since(start)) 672 memcacheFlushSizeMeter.Mark(int64(storage - db.dirtiesSize)) 673 memcacheFlushNodesMeter.Mark(int64(nodes - len(db.dirties))) 674 675 log.Debug("Persisted nodes from memory database", "nodes", nodes-len(db.dirties), "size", storage-db.dirtiesSize, "time", time.Since(start), 676 "flushnodes", db.flushnodes, "flushsize", db.flushsize, "flushtime", db.flushtime, "livenodes", len(db.dirties), "livesize", db.dirtiesSize) 677 678 return nil 679 } 680 681 // Commit iterates over all the children of a particular node, writes them out 682 // to disk, forcefully tearing down all references in both directions. As a side 683 // effect, all pre-images accumulated up to this point are also written. 684 // 685 // Note, this method is a non-synchronized mutator. It is unsafe to call this 686 // concurrently with other mutators. 687 func (db *Database) Commit(node common.Hash, report bool, callback func(common.Hash)) error { 688 // Create a database batch to flush persistent data out. It is important that 689 // outside code doesn't see an inconsistent state (referenced data removed from 690 // memory cache during commit but not yet in persistent storage). This is ensured 691 // by only uncaching existing data when the database write finalizes. 692 start := time.Now() 693 batch := db.diskdb.NewBatch() 694 695 // Move all of the accumulated preimages into a write batch 696 if db.preimages != nil { 697 rawdb.WritePreimages(batch, db.preimages) 698 // Since we're going to replay trie node writes into the clean cache, flush out 699 // any batched pre-images before continuing. 700 if err := batch.Write(); err != nil { 701 return err 702 } 703 batch.Reset() 704 } 705 // Move the trie itself into the batch, flushing if enough data is accumulated 706 nodes, storage := len(db.dirties), db.dirtiesSize 707 708 uncacher := &cleaner{db} 709 if err := db.commit(node, batch, uncacher, callback); err != nil { 710 log.Error("Failed to commit trie from trie database", "err", err) 711 return err 712 } 713 // Trie mostly committed to disk, flush any batch leftovers 714 if err := batch.Write(); err != nil { 715 log.Error("Failed to write trie to disk", "err", err) 716 return err 717 } 718 // Uncache any leftovers in the last batch 719 db.lock.Lock() 720 defer db.lock.Unlock() 721 722 batch.Replay(uncacher) 723 batch.Reset() 724 725 // Reset the storage counters and bumped metrics 726 if db.preimages != nil { 727 db.preimages, db.preimagesSize = make(map[common.Hash][]byte), 0 728 } 729 memcacheCommitTimeTimer.Update(time.Since(start)) 730 memcacheCommitSizeMeter.Mark(int64(storage - db.dirtiesSize)) 731 memcacheCommitNodesMeter.Mark(int64(nodes - len(db.dirties))) 732 733 logger := log.Info 734 if !report { 735 logger = log.Debug 736 } 737 logger("Persisted trie from memory database", "nodes", nodes-len(db.dirties)+int(db.flushnodes), "size", storage-db.dirtiesSize+db.flushsize, "time", time.Since(start)+db.flushtime, 738 "gcnodes", db.gcnodes, "gcsize", db.gcsize, "gctime", db.gctime, "livenodes", len(db.dirties), "livesize", db.dirtiesSize) 739 740 // Reset the garbage collection statistics 741 db.gcnodes, db.gcsize, db.gctime = 0, 0, 0 742 db.flushnodes, db.flushsize, db.flushtime = 0, 0, 0 743 744 return nil 745 } 746 747 // commit is the private locked version of Commit. 748 func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleaner, callback func(common.Hash)) error { 749 // If the node does not exist, it's a previously committed node 750 node, ok := db.dirties[hash] 751 if !ok { 752 return nil 753 } 754 var err error 755 node.forChilds(func(child common.Hash) { 756 if err == nil { 757 err = db.commit(child, batch, uncacher, callback) 758 } 759 }) 760 if err != nil { 761 return err 762 } 763 // If we've reached an optimal batch size, commit and start over 764 rawdb.WriteTrieNode(batch, hash, node.rlp()) 765 if callback != nil { 766 callback(hash) 767 } 768 if batch.ValueSize() >= ethdb.IdealBatchSize { 769 if err := batch.Write(); err != nil { 770 return err 771 } 772 db.lock.Lock() 773 batch.Replay(uncacher) 774 batch.Reset() 775 db.lock.Unlock() 776 } 777 return nil 778 } 779 780 // cleaner is a database batch replayer that takes a batch of write operations 781 // and cleans up the trie database from anything written to disk. 782 type cleaner struct { 783 db *Database 784 } 785 786 // Put reacts to database writes and implements dirty data uncaching. This is the 787 // post-processing step of a commit operation where the already persisted trie is 788 // removed from the dirty cache and moved into the clean cache. The reason behind 789 // the two-phase commit is to ensure data availability while moving from memory 790 // to disk. 791 func (c *cleaner) Put(key []byte, rlp []byte) error { 792 hash := common.BytesToHash(key) 793 794 // If the node does not exist, we're done on this path 795 node, ok := c.db.dirties[hash] 796 if !ok { 797 return nil 798 } 799 // Node still exists, remove it from the flush-list 800 switch hash { 801 case c.db.oldest: 802 c.db.oldest = node.flushNext 803 c.db.dirties[node.flushNext].flushPrev = common.Hash{} 804 case c.db.newest: 805 c.db.newest = node.flushPrev 806 c.db.dirties[node.flushPrev].flushNext = common.Hash{} 807 default: 808 c.db.dirties[node.flushPrev].flushNext = node.flushNext 809 c.db.dirties[node.flushNext].flushPrev = node.flushPrev 810 } 811 // Remove the node from the dirty cache 812 delete(c.db.dirties, hash) 813 c.db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size)) 814 if node.children != nil { 815 c.db.childrenSize -= common.StorageSize(cachedNodeChildrenSize + len(node.children)*(common.HashLength+2)) 816 } 817 // Move the flushed node into the clean cache to prevent insta-reloads 818 if c.db.cleans != nil { 819 c.db.cleans.Set(hash[:], rlp) 820 memcacheCleanWriteMeter.Mark(int64(len(rlp))) 821 } 822 return nil 823 } 824 825 func (c *cleaner) Delete(key []byte) error { 826 panic("not implemented") 827 } 828 829 // Size returns the current storage size of the memory cache in front of the 830 // persistent database layer. 831 func (db *Database) Size() (common.StorageSize, common.StorageSize) { 832 db.lock.RLock() 833 defer db.lock.RUnlock() 834 835 // db.dirtiesSize only contains the useful data in the cache, but when reporting 836 // the total memory consumption, the maintenance metadata is also needed to be 837 // counted. 838 var metadataSize = common.StorageSize((len(db.dirties) - 1) * cachedNodeSize) 839 var metarootRefs = common.StorageSize(len(db.dirties[common.Hash{}].children) * (common.HashLength + 2)) 840 return db.dirtiesSize + db.childrenSize + metadataSize - metarootRefs, db.preimagesSize 841 } 842 843 // saveCache saves clean state cache to given directory path 844 // using specified CPU cores. 845 func (db *Database) saveCache(dir string, threads int) error { 846 if db.cleans == nil { 847 return nil 848 } 849 log.Info("Writing clean trie cache to disk", "path", dir, "threads", threads) 850 851 start := time.Now() 852 err := db.cleans.SaveToFileConcurrent(dir, threads) 853 if err != nil { 854 log.Error("Failed to persist clean trie cache", "error", err) 855 return err 856 } 857 log.Info("Persisted the clean trie cache", "path", dir, "elapsed", common.PrettyDuration(time.Since(start))) 858 return nil 859 } 860 861 // SaveCache atomically saves fast cache data to the given dir using all 862 // available CPU cores. 863 func (db *Database) SaveCache(dir string) error { 864 return db.saveCache(dir, runtime.GOMAXPROCS(0)) 865 } 866 867 // SaveCachePeriodically atomically saves fast cache data to the given dir with 868 // the specified interval. All dump operation will only use a single CPU core. 869 func (db *Database) SaveCachePeriodically(dir string, interval time.Duration, stopCh <-chan struct{}) { 870 ticker := time.NewTicker(interval) 871 defer ticker.Stop() 872 873 for { 874 select { 875 case <-ticker.C: 876 db.saveCache(dir, 1) 877 case <-stopCh: 878 return 879 } 880 } 881 }