github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/trie/database.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:45</date> 10 //</624450122729656320> 11 12 13 package trie 14 15 import ( 16 "fmt" 17 "io" 18 "sync" 19 "time" 20 21 "github.com/allegro/bigcache" 22 "github.com/ethereum/go-ethereum/common" 23 "github.com/ethereum/go-ethereum/ethdb" 24 "github.com/ethereum/go-ethereum/log" 25 "github.com/ethereum/go-ethereum/metrics" 26 "github.com/ethereum/go-ethereum/rlp" 27 ) 28 29 var ( 30 memcacheCleanHitMeter = metrics.NewRegisteredMeter("trie/memcache/clean/hit", nil) 31 memcacheCleanMissMeter = metrics.NewRegisteredMeter("trie/memcache/clean/miss", nil) 32 memcacheCleanReadMeter = metrics.NewRegisteredMeter("trie/memcache/clean/read", nil) 33 memcacheCleanWriteMeter = metrics.NewRegisteredMeter("trie/memcache/clean/write", nil) 34 35 memcacheFlushTimeTimer = metrics.NewRegisteredResettingTimer("trie/memcache/flush/time", nil) 36 memcacheFlushNodesMeter = metrics.NewRegisteredMeter("trie/memcache/flush/nodes", nil) 37 memcacheFlushSizeMeter = metrics.NewRegisteredMeter("trie/memcache/flush/size", nil) 38 39 memcacheGCTimeTimer = metrics.NewRegisteredResettingTimer("trie/memcache/gc/time", nil) 40 memcacheGCNodesMeter = metrics.NewRegisteredMeter("trie/memcache/gc/nodes", nil) 41 memcacheGCSizeMeter = metrics.NewRegisteredMeter("trie/memcache/gc/size", nil) 42 43 memcacheCommitTimeTimer = metrics.NewRegisteredResettingTimer("trie/memcache/commit/time", nil) 44 memcacheCommitNodesMeter = metrics.NewRegisteredMeter("trie/memcache/commit/nodes", nil) 45 memcacheCommitSizeMeter = metrics.NewRegisteredMeter("trie/memcache/commit/size", nil) 46 ) 47 48 //SecureKeyPrefix是用于存储trie节点预映像的数据库密钥前缀。 49 var secureKeyPrefix = []byte("secure-key-") 50 51 //SecureKeyLength是上述前缀的长度+32字节哈希。 52 const secureKeyLength = 11 + 32 53 54 //DatabaseReader包装get并具有trie的后备存储方法。 55 type DatabaseReader interface { 56 //get从数据库中检索与键关联的值。 57 Get(key []byte) (value []byte, err error) 58 59 //获取数据库中是否存在键。 60 Has(key []byte) (bool, error) 61 } 62 63 //数据库是Trie数据结构和 64 //磁盘数据库。其目的是在内存中积累trie写入 65 //定期刷新一对夫妇试图磁盘,垃圾收集剩余。 66 type Database struct { 67 diskdb ethdb.Database //成熟trie节点的持久存储 68 69 cleans *bigcache.BigCache //干净节点rlps的GC友好内存缓存 70 dirties map[common.Hash]*cachedNode //脏节点的数据和引用关系 71 oldest common.Hash //最旧的跟踪节点,刷新列表头 72 newest common.Hash //最新跟踪节点,刷新列表尾部 73 74 preimages map[common.Hash][]byte //安全trie中节点的预映像 75 seckeybuf [secureKeyLength]byte //用于计算预映像密钥的临时缓冲区 76 77 gctime time.Duration //自上次提交以来在垃圾收集上花费的时间 78 gcnodes uint64 //自上次提交以来收集的节点垃圾 79 gcsize common.StorageSize //自上次提交以来收集的数据存储垃圾 80 81 flushtime time.Duration //自上次提交以来在数据刷新上花费的时间 82 flushnodes uint64 //自上次提交以来刷新的节点 83 flushsize common.StorageSize //自上次提交以来刷新的数据存储 84 85 dirtiesSize common.StorageSize //脏节点缓存的存储大小(不包括FlushList) 86 preimagesSize common.StorageSize //预映像缓存的存储大小 87 88 lock sync.RWMutex 89 } 90 91 //rawnode是一个简单的二进制blob,用于区分折叠的trie 92 //节点和已经编码的rlp二进制blob(同时存储它们 93 //在相同的缓存字段中)。 94 type rawNode []byte 95 96 func (n rawNode) canUnload(uint16, uint16) bool { panic("this should never end up in a live trie") } 97 func (n rawNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } 98 func (n rawNode) fstring(ind string) string { panic("this should never end up in a live trie") } 99 100 //rawfullnode仅表示完整节点的有用数据内容,其中 101 //去除缓存和标志以最小化其数据存储。这类荣誉 102 //与原始父级相同的RLP编码。 103 type rawFullNode [17]node 104 105 func (n rawFullNode) canUnload(uint16, uint16) bool { panic("this should never end up in a live trie") } 106 func (n rawFullNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } 107 func (n rawFullNode) fstring(ind string) string { panic("this should never end up in a live trie") } 108 109 func (n rawFullNode) EncodeRLP(w io.Writer) error { 110 var nodes [17]node 111 112 for i, child := range n { 113 if child != nil { 114 nodes[i] = child 115 } else { 116 nodes[i] = nilValueNode 117 } 118 } 119 return rlp.Encode(w, nodes) 120 } 121 122 //rawshortnode仅表示短节点的有用数据内容,其中 123 //去除缓存和标志以最小化其数据存储。这类荣誉 124 //与原始父级相同的RLP编码。 125 type rawShortNode struct { 126 Key []byte 127 Val node 128 } 129 130 func (n rawShortNode) canUnload(uint16, uint16) bool { panic("this should never end up in a live trie") } 131 func (n rawShortNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } 132 func (n rawShortNode) fstring(ind string) string { panic("this should never end up in a live trie") } 133 134 //cached node是我们所知道的关于 135 //内存数据库写入层。 136 type cachedNode struct { 137 node node //缓存的折叠的trie节点或原始rlp数据 138 size uint16 //有用缓存数据的字节大小 139 140 parents uint32 //引用此节点的活动节点数 141 children map[common.Hash]uint16 //此节点引用的外部子级 142 143 flushPrev common.Hash //刷新列表中的上一个节点 144 flushNext common.Hash //刷新列表中的下一个节点 145 } 146 147 //rlp返回缓存节点的原始rlp编码blob,可以直接从 148 //缓存,或者从折叠的节点重新生成缓存。 149 func (n *cachedNode) rlp() []byte { 150 if node, ok := n.node.(rawNode); ok { 151 return node 152 } 153 blob, err := rlp.EncodeToBytes(n.node) 154 if err != nil { 155 panic(err) 156 } 157 return blob 158 } 159 160 //obj直接从缓存返回解码和扩展的trie节点, 161 //或者从rlp编码的blob中重新生成它。 162 func (n *cachedNode) obj(hash common.Hash, cachegen uint16) node { 163 if node, ok := n.node.(rawNode); ok { 164 return mustDecodeNode(hash[:], node, cachegen) 165 } 166 return expandNode(hash[:], n.node, cachegen) 167 } 168 169 //childs返回此节点的所有被跟踪子节点,包括隐式子节点 170 //从节点内部以及节点外部的显式节点。 171 func (n *cachedNode) childs() []common.Hash { 172 children := make([]common.Hash, 0, 16) 173 for child := range n.children { 174 children = append(children, child) 175 } 176 if _, ok := n.node.(rawNode); !ok { 177 gatherChildren(n.node, &children) 178 } 179 return children 180 } 181 182 //GatherChildren遍历折叠存储节点的节点层次结构,并 183 //检索所有哈希节点子级。 184 func gatherChildren(n node, children *[]common.Hash) { 185 switch n := n.(type) { 186 case *rawShortNode: 187 gatherChildren(n.Val, children) 188 189 case rawFullNode: 190 for i := 0; i < 16; i++ { 191 gatherChildren(n[i], children) 192 } 193 case hashNode: 194 *children = append(*children, common.BytesToHash(n)) 195 196 case valueNode, nil: 197 198 default: 199 panic(fmt.Sprintf("unknown node type: %T", n)) 200 } 201 } 202 203 //SimplifyNode遍历扩展内存节点的层次结构并丢弃 204 //所有内部缓存,返回只包含原始数据的节点。 205 func simplifyNode(n node) node { 206 switch n := n.(type) { 207 case *shortNode: 208 //短节点丢弃标志并层叠 209 return &rawShortNode{Key: n.Key, Val: simplifyNode(n.Val)} 210 211 case *fullNode: 212 //完整节点丢弃标志并层叠 213 node := rawFullNode(n.Children) 214 for i := 0; i < len(node); i++ { 215 if node[i] != nil { 216 node[i] = simplifyNode(node[i]) 217 } 218 } 219 return node 220 221 case valueNode, hashNode, rawNode: 222 return n 223 224 default: 225 panic(fmt.Sprintf("unknown node type: %T", n)) 226 } 227 } 228 229 //expandnode遍历折叠存储节点的节点层次结构并转换 230 //将所有字段和键转换为扩展内存形式。 231 func expandNode(hash hashNode, n node, cachegen uint16) node { 232 switch n := n.(type) { 233 case *rawShortNode: 234 //短节点需要密钥和子扩展 235 return &shortNode{ 236 Key: compactToHex(n.Key), 237 Val: expandNode(nil, n.Val, cachegen), 238 flags: nodeFlag{ 239 hash: hash, 240 gen: cachegen, 241 }, 242 } 243 244 case rawFullNode: 245 //完整节点需要子扩展 246 node := &fullNode{ 247 flags: nodeFlag{ 248 hash: hash, 249 gen: cachegen, 250 }, 251 } 252 for i := 0; i < len(node.Children); i++ { 253 if n[i] != nil { 254 node.Children[i] = expandNode(nil, n[i], cachegen) 255 } 256 } 257 return node 258 259 case valueNode, hashNode: 260 return n 261 262 default: 263 panic(fmt.Sprintf("unknown node type: %T", n)) 264 } 265 } 266 267 //new database创建一个新的trie数据库来存储之前的临时trie内容 268 //它被写入磁盘或垃圾收集。没有创建读缓存,因此 269 //数据检索将命中基础磁盘数据库。 270 func NewDatabase(diskdb ethdb.Database) *Database { 271 return NewDatabaseWithCache(diskdb, 0) 272 } 273 274 //newdatabasewithcache创建新的trie数据库以存储临时trie内容 275 //在写入磁盘或垃圾收集之前。它还充当读缓存 276 //用于从磁盘加载的节点。 277 func NewDatabaseWithCache(diskdb ethdb.Database, cache int) *Database { 278 var cleans *bigcache.BigCache 279 if cache > 0 { 280 cleans, _ = bigcache.NewBigCache(bigcache.Config{ 281 Shards: 1024, 282 LifeWindow: time.Hour, 283 MaxEntriesInWindow: cache * 1024, 284 MaxEntrySize: 512, 285 HardMaxCacheSize: cache, 286 }) 287 } 288 return &Database{ 289 diskdb: diskdb, 290 cleans: cleans, 291 dirties: map[common.Hash]*cachedNode{{}: {}}, 292 preimages: make(map[common.Hash][]byte), 293 } 294 } 295 296 //diskdb检索支持trie数据库的持久存储。 297 func (db *Database) DiskDB() DatabaseReader { 298 return db.diskdb 299 } 300 301 //insertblob将新的引用跟踪blob写入内存数据库 302 //但未知。此方法只能用于需要 303 //引用计数,因为trie节点直接通过 304 //他们的孩子。 305 func (db *Database) InsertBlob(hash common.Hash, blob []byte) { 306 db.lock.Lock() 307 defer db.lock.Unlock() 308 309 db.insert(hash, blob, rawNode(blob)) 310 } 311 312 //插入将折叠的trie节点插入内存数据库。这种方法是 313 //更通用的insertblob版本,支持原始blob插入 314 //例如三节点插入。必须始终指定blob以允许 315 //尺寸跟踪。 316 func (db *Database) insert(hash common.Hash, blob []byte, node node) { 317 //如果节点已缓存,则跳过 318 if _, ok := db.dirties[hash]; ok { 319 return 320 } 321 //为此节点创建缓存项 322 entry := &cachedNode{ 323 node: simplifyNode(node), 324 size: uint16(len(blob)), 325 flushPrev: db.newest, 326 } 327 for _, child := range entry.childs() { 328 if c := db.dirties[child]; c != nil { 329 c.parents++ 330 } 331 } 332 db.dirties[hash] = entry 333 334 //更新刷新列表端点 335 if db.oldest == (common.Hash{}) { 336 db.oldest, db.newest = hash, hash 337 } else { 338 db.dirties[db.newest].flushNext, db.newest = hash, hash 339 } 340 db.dirtiesSize += common.StorageSize(common.HashLength + entry.size) 341 } 342 343 //insertpreimage将新的trie节点pre映像写入内存数据库(如果是) 344 //但未知。该方法将复制切片。 345 // 346 //注意,此方法假定数据库的锁被持有! 347 func (db *Database) insertPreimage(hash common.Hash, preimage []byte) { 348 if _, ok := db.preimages[hash]; ok { 349 return 350 } 351 db.preimages[hash] = common.CopyBytes(preimage) 352 db.preimagesSize += common.StorageSize(common.HashLength + len(preimage)) 353 } 354 355 //节点从内存中检索缓存的trie节点,或者如果没有节点,则返回nil 356 //在内存缓存中找到。 357 func (db *Database) node(hash common.Hash, cachegen uint16) node { 358 //从干净缓存中检索节点(如果可用) 359 if db.cleans != nil { 360 if enc, err := db.cleans.Get(string(hash[:])); err == nil && enc != nil { 361 memcacheCleanHitMeter.Mark(1) 362 memcacheCleanReadMeter.Mark(int64(len(enc))) 363 return mustDecodeNode(hash[:], enc, cachegen) 364 } 365 } 366 //从脏缓存中检索节点(如果可用) 367 db.lock.RLock() 368 dirty := db.dirties[hash] 369 db.lock.RUnlock() 370 371 if dirty != nil { 372 return dirty.obj(hash, cachegen) 373 } 374 //内容在内存中不可用,请尝试从磁盘检索 375 enc, err := db.diskdb.Get(hash[:]) 376 if err != nil || enc == nil { 377 return nil 378 } 379 if db.cleans != nil { 380 db.cleans.Set(string(hash[:]), enc) 381 memcacheCleanMissMeter.Mark(1) 382 memcacheCleanWriteMeter.Mark(int64(len(enc))) 383 } 384 return mustDecodeNode(hash[:], enc, cachegen) 385 } 386 387 //节点从内存中检索编码缓存的trie节点。如果找不到 388 //缓存后,该方法查询持久数据库中的内容。 389 func (db *Database) Node(hash common.Hash) ([]byte, error) { 390 //从干净缓存中检索节点(如果可用) 391 if db.cleans != nil { 392 if enc, err := db.cleans.Get(string(hash[:])); err == nil && enc != nil { 393 memcacheCleanHitMeter.Mark(1) 394 memcacheCleanReadMeter.Mark(int64(len(enc))) 395 return enc, nil 396 } 397 } 398 //从脏缓存中检索节点(如果可用) 399 db.lock.RLock() 400 dirty := db.dirties[hash] 401 db.lock.RUnlock() 402 403 if dirty != nil { 404 return dirty.rlp(), nil 405 } 406 //内容在内存中不可用,请尝试从磁盘检索 407 enc, err := db.diskdb.Get(hash[:]) 408 if err == nil && enc != nil { 409 if db.cleans != nil { 410 db.cleans.Set(string(hash[:]), enc) 411 memcacheCleanMissMeter.Mark(1) 412 memcacheCleanWriteMeter.Mark(int64(len(enc))) 413 } 414 } 415 return enc, err 416 } 417 418 //pre image从内存中检索缓存的trie节点pre映像。如果不能 419 //找到缓存的,该方法查询持久数据库中的内容。 420 func (db *Database) preimage(hash common.Hash) ([]byte, error) { 421 //从缓存中检索节点(如果可用) 422 db.lock.RLock() 423 preimage := db.preimages[hash] 424 db.lock.RUnlock() 425 426 if preimage != nil { 427 return preimage, nil 428 } 429 //内容在内存中不可用,请尝试从磁盘检索 430 return db.diskdb.Get(db.secureKey(hash[:])) 431 } 432 433 //securekey返回密钥的预映像的数据库密钥,作为临时的 434 //缓冲器。调用方不能保留返回值,因为它将成为 435 //下次呼叫无效。 436 func (db *Database) secureKey(key []byte) []byte { 437 buf := append(db.seckeybuf[:0], secureKeyPrefix...) 438 buf = append(buf, key...) 439 return buf 440 } 441 442 //节点检索内存数据库中缓存的所有节点的哈希值。 443 //此方法非常昂贵,只应用于验证内部 444 //测试代码中的状态。 445 func (db *Database) Nodes() []common.Hash { 446 db.lock.RLock() 447 defer db.lock.RUnlock() 448 449 var hashes = make([]common.Hash, 0, len(db.dirties)) 450 for hash := range db.dirties { 451 if hash != (common.Hash{}) { //“根”引用/节点的特殊情况 452 hashes = append(hashes, hash) 453 } 454 } 455 return hashes 456 } 457 458 //引用将新引用从父节点添加到子节点。 459 func (db *Database) Reference(child common.Hash, parent common.Hash) { 460 db.lock.RLock() 461 defer db.lock.RUnlock() 462 463 db.reference(child, parent) 464 } 465 466 //引用是引用的私有锁定版本。 467 func (db *Database) reference(child common.Hash, parent common.Hash) { 468 //如果节点不存在,它是从磁盘中提取的节点,跳过 469 node, ok := db.dirties[child] 470 if !ok { 471 return 472 } 473 //如果引用已存在,则只为根复制 474 if db.dirties[parent].children == nil { 475 db.dirties[parent].children = make(map[common.Hash]uint16) 476 } else if _, ok = db.dirties[parent].children[child]; ok && parent != (common.Hash{}) { 477 return 478 } 479 node.parents++ 480 db.dirties[parent].children[child]++ 481 } 482 483 //取消引用从根节点删除现有引用。 484 func (db *Database) Dereference(root common.Hash) { 485 //健全性检查以确保元根目录未被删除 486 if root == (common.Hash{}) { 487 log.Error("Attempted to dereference the trie cache meta root") 488 return 489 } 490 db.lock.Lock() 491 defer db.lock.Unlock() 492 493 nodes, storage, start := len(db.dirties), db.dirtiesSize, time.Now() 494 db.dereference(root, common.Hash{}) 495 496 db.gcnodes += uint64(nodes - len(db.dirties)) 497 db.gcsize += storage - db.dirtiesSize 498 db.gctime += time.Since(start) 499 500 memcacheGCTimeTimer.Update(time.Since(start)) 501 memcacheGCSizeMeter.Mark(int64(storage - db.dirtiesSize)) 502 memcacheGCNodesMeter.Mark(int64(nodes - len(db.dirties))) 503 504 log.Debug("Dereferenced trie from memory database", "nodes", nodes-len(db.dirties), "size", storage-db.dirtiesSize, "time", time.Since(start), 505 "gcnodes", db.gcnodes, "gcsize", db.gcsize, "gctime", db.gctime, "livenodes", len(db.dirties), "livesize", db.dirtiesSize) 506 } 507 508 //解引用是解引用的私有锁定版本。 509 func (db *Database) dereference(child common.Hash, parent common.Hash) { 510 //取消对父子关系的引用 511 node := db.dirties[parent] 512 513 if node.children != nil && node.children[child] > 0 { 514 node.children[child]-- 515 if node.children[child] == 0 { 516 delete(node.children, child) 517 } 518 } 519 //如果子节点不存在,则它是以前提交的节点。 520 node, ok := db.dirties[child] 521 if !ok { 522 return 523 } 524 //如果没有对该子级的引用,请将其删除并层叠 525 if node.parents > 0 { 526 //这是一种特殊的情况,其中从磁盘加载的节点(即不在 527 //memcache)作为新节点(短节点拆分为完整节点, 528 //然后恢复为短),导致缓存节点没有父节点。那就是 529 //这本身没问题,但不要让最大的父母离开。 530 node.parents-- 531 } 532 if node.parents == 0 { 533 //从刷新列表中删除节点 534 switch child { 535 case db.oldest: 536 db.oldest = node.flushNext 537 db.dirties[node.flushNext].flushPrev = common.Hash{} 538 case db.newest: 539 db.newest = node.flushPrev 540 db.dirties[node.flushPrev].flushNext = common.Hash{} 541 default: 542 db.dirties[node.flushPrev].flushNext = node.flushNext 543 db.dirties[node.flushNext].flushPrev = node.flushPrev 544 } 545 //取消引用所有子节点并删除节点 546 for _, hash := range node.childs() { 547 db.dereference(hash, child) 548 } 549 delete(db.dirties, child) 550 db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size)) 551 } 552 } 553 554 //cap循环刷新旧的但仍引用的trie节点,直到总数 555 //内存使用率低于给定阈值。 556 func (db *Database) Cap(limit common.StorageSize) error { 557 //创建一个数据库批处理以将持久性数据清除。重要的是 558 //外部代码没有看到不一致的状态(引用的数据从 559 //提交期间内存缓存,但尚未在持久存储中)。这是保证的。 560 //只有在数据库写入完成时才取消对现有数据的缓存。 561 db.lock.RLock() 562 563 nodes, storage, start := len(db.dirties), db.dirtiesSize, time.Now() 564 batch := db.diskdb.NewBatch() 565 566 //db.dirtiessize只包含缓存中的有用数据,但在报告时 567 //总的内存消耗,维护元数据也需要 568 //计数。对于每个有用的节点,我们跟踪2个额外的散列作为flushlist。 569 size := db.dirtiesSize + common.StorageSize((len(db.dirties)-1)*2*common.HashLength) 570 571 //如果预映像缓存足够大,请推到磁盘。如果它还小的话 572 //留待以后删除重复写入。 573 flushPreimages := db.preimagesSize > 4*1024*1024 574 if flushPreimages { 575 for hash, preimage := range db.preimages { 576 if err := batch.Put(db.secureKey(hash[:]), preimage); err != nil { 577 log.Error("Failed to commit preimage from trie database", "err", err) 578 db.lock.RUnlock() 579 return err 580 } 581 if batch.ValueSize() > ethdb.IdealBatchSize { 582 if err := batch.Write(); err != nil { 583 db.lock.RUnlock() 584 return err 585 } 586 batch.Reset() 587 } 588 } 589 } 590 //保持提交刷新列表中的节点,直到低于允许值为止 591 oldest := db.oldest 592 for size > limit && oldest != (common.Hash{}) { 593 //获取最旧的引用节点并推入批处理 594 node := db.dirties[oldest] 595 if err := batch.Put(oldest[:], node.rlp()); err != nil { 596 db.lock.RUnlock() 597 return err 598 } 599 //如果超出了理想的批处理大小,请提交并重置 600 if batch.ValueSize() >= ethdb.IdealBatchSize { 601 if err := batch.Write(); err != nil { 602 log.Error("Failed to write flush list to disk", "err", err) 603 db.lock.RUnlock() 604 return err 605 } 606 batch.Reset() 607 } 608 //迭代到下一个刷新项,或者在达到大小上限时中止。尺寸 609 //是总大小,包括有用的缓存数据(hash->blob),作为 610 //以及flushlist元数据(2*hash)。从缓存刷新项目时, 611 //我们需要两者都减少。 612 size -= common.StorageSize(3*common.HashLength + int(node.size)) 613 oldest = node.flushNext 614 } 615 //从上一批中清除所有剩余数据 616 if err := batch.Write(); err != nil { 617 log.Error("Failed to write flush list to disk", "err", err) 618 db.lock.RUnlock() 619 return err 620 } 621 db.lock.RUnlock() 622 623 //写入成功,清除刷新的数据 624 db.lock.Lock() 625 defer db.lock.Unlock() 626 627 if flushPreimages { 628 db.preimages = make(map[common.Hash][]byte) 629 db.preimagesSize = 0 630 } 631 for db.oldest != oldest { 632 node := db.dirties[db.oldest] 633 delete(db.dirties, db.oldest) 634 db.oldest = node.flushNext 635 636 db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size)) 637 } 638 if db.oldest != (common.Hash{}) { 639 db.dirties[db.oldest].flushPrev = common.Hash{} 640 } 641 db.flushnodes += uint64(nodes - len(db.dirties)) 642 db.flushsize += storage - db.dirtiesSize 643 db.flushtime += time.Since(start) 644 645 memcacheFlushTimeTimer.Update(time.Since(start)) 646 memcacheFlushSizeMeter.Mark(int64(storage - db.dirtiesSize)) 647 memcacheFlushNodesMeter.Mark(int64(nodes - len(db.dirties))) 648 649 log.Debug("Persisted nodes from memory database", "nodes", nodes-len(db.dirties), "size", storage-db.dirtiesSize, "time", time.Since(start), 650 "flushnodes", db.flushnodes, "flushsize", db.flushsize, "flushtime", db.flushtime, "livenodes", len(db.dirties), "livesize", db.dirtiesSize) 651 652 return nil 653 } 654 655 //commit迭代特定节点的所有子节点,并将其写出 656 //在磁盘上,强制删除两个方向上的所有引用。 657 // 658 //作为一个副作用,所有的预图像积累到这一点也写。 659 func (db *Database) Commit(node common.Hash, report bool) error { 660 //创建一个数据库批处理以将持久性数据清除。重要的是 661 //外部代码没有看到不一致的状态(引用的数据从 662 //提交期间内存缓存,但尚未在持久存储中)。这是保证的。 663 //只有在数据库写入完成时才取消对现有数据的缓存。 664 db.lock.RLock() 665 666 start := time.Now() 667 batch := db.diskdb.NewBatch() 668 669 //将所有累积的预映像移到一个写入批处理中 670 for hash, preimage := range db.preimages { 671 if err := batch.Put(db.secureKey(hash[:]), preimage); err != nil { 672 log.Error("Failed to commit preimage from trie database", "err", err) 673 db.lock.RUnlock() 674 return err 675 } 676 if batch.ValueSize() > ethdb.IdealBatchSize { 677 if err := batch.Write(); err != nil { 678 return err 679 } 680 batch.Reset() 681 } 682 } 683 //将trie本身移到批处理中,如果积累了足够的数据,则进行刷新。 684 nodes, storage := len(db.dirties), db.dirtiesSize 685 if err := db.commit(node, batch); err != nil { 686 log.Error("Failed to commit trie from trie database", "err", err) 687 db.lock.RUnlock() 688 return err 689 } 690 //编写批处理就绪,在持久性期间为读卡器解锁 691 if err := batch.Write(); err != nil { 692 log.Error("Failed to write trie to disk", "err", err) 693 db.lock.RUnlock() 694 return err 695 } 696 db.lock.RUnlock() 697 698 //写入成功,清除刷新的数据 699 db.lock.Lock() 700 defer db.lock.Unlock() 701 702 db.preimages = make(map[common.Hash][]byte) 703 db.preimagesSize = 0 704 705 db.uncache(node) 706 707 memcacheCommitTimeTimer.Update(time.Since(start)) 708 memcacheCommitSizeMeter.Mark(int64(storage - db.dirtiesSize)) 709 memcacheCommitNodesMeter.Mark(int64(nodes - len(db.dirties))) 710 711 logger := log.Info 712 if !report { 713 logger = log.Debug 714 } 715 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, 716 "gcnodes", db.gcnodes, "gcsize", db.gcsize, "gctime", db.gctime, "livenodes", len(db.dirties), "livesize", db.dirtiesSize) 717 718 //重置垃圾收集统计信息 719 db.gcnodes, db.gcsize, db.gctime = 0, 0, 0 720 db.flushnodes, db.flushsize, db.flushtime = 0, 0, 0 721 722 return nil 723 } 724 725 //commit是commit的私有锁定版本。 726 func (db *Database) commit(hash common.Hash, batch ethdb.Batch) error { 727 //如果该节点不存在,则它是以前提交的节点 728 node, ok := db.dirties[hash] 729 if !ok { 730 return nil 731 } 732 for _, child := range node.childs() { 733 if err := db.commit(child, batch); err != nil { 734 return err 735 } 736 } 737 if err := batch.Put(hash[:], node.rlp()); err != nil { 738 return err 739 } 740 //如果我们已经达到了最佳的批处理大小,请提交并重新开始 741 if batch.ValueSize() >= ethdb.IdealBatchSize { 742 if err := batch.Write(); err != nil { 743 return err 744 } 745 batch.Reset() 746 } 747 return nil 748 } 749 750 //uncache是提交操作的后处理步骤,其中 751 //保留的trie将从缓存中删除。两阶段背后的原因 752 //提交是为了在从内存移动时确保一致的数据可用性。 753 //到磁盘。 754 func (db *Database) uncache(hash common.Hash) { 755 //如果节点不存在,我们就在这条路径上完成了 756 node, ok := db.dirties[hash] 757 if !ok { 758 return 759 } 760 //节点仍然存在,请将其从刷新列表中删除 761 switch hash { 762 case db.oldest: 763 db.oldest = node.flushNext 764 db.dirties[node.flushNext].flushPrev = common.Hash{} 765 case db.newest: 766 db.newest = node.flushPrev 767 db.dirties[node.flushPrev].flushNext = common.Hash{} 768 default: 769 db.dirties[node.flushPrev].flushNext = node.flushNext 770 db.dirties[node.flushNext].flushPrev = node.flushPrev 771 } 772 //打开节点的子文件并移除节点本身 773 for _, child := range node.childs() { 774 db.uncache(child) 775 } 776 delete(db.dirties, hash) 777 db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size)) 778 } 779 780 //大小返回在 781 //持久数据库层。 782 func (db *Database) Size() (common.StorageSize, common.StorageSize) { 783 db.lock.RLock() 784 defer db.lock.RUnlock() 785 786 //db.dirtiessize只包含缓存中的有用数据,但在报告时 787 //总的内存消耗,维护元数据也需要 788 //计数。对于每个有用的节点,我们跟踪2个额外的散列作为flushlist。 789 var flushlistSize = common.StorageSize((len(db.dirties) - 1) * 2 * common.HashLength) 790 return db.dirtiesSize + flushlistSize, db.preimagesSize 791 } 792 793 //VerifyIntegrity是一种调试方法,用于在存储在 794 //内存并检查每个节点是否可以从元根访问。目标 795 //查找可能导致内存泄漏和/或trie节点丢失的任何错误 796 //失踪。 797 // 798 //这种方法非常占用CPU和内存,只能在必要时使用。 799 func (db *Database) verifyIntegrity() { 800 //循环访问所有缓存节点并将它们累积到一个集合中 801 reachable := map[common.Hash]struct{}{{}: {}} 802 803 for child := range db.dirties[common.Hash{}].children { 804 db.accumulate(child, reachable) 805 } 806 //查找任何不可访问但缓存的节点 807 unreachable := []string{} 808 for hash, node := range db.dirties { 809 if _, ok := reachable[hash]; !ok { 810 unreachable = append(unreachable, fmt.Sprintf("%x: {Node: %v, Parents: %d, Prev: %x, Next: %x}", 811 hash, node.node, node.parents, node.flushPrev, node.flushNext)) 812 } 813 } 814 if len(unreachable) != 0 { 815 panic(fmt.Sprintf("trie cache memory leak: %v", unreachable)) 816 } 817 } 818 819 //对哈希定义的trie进行累加迭代,并将所有 820 //在内存中找到缓存的子级。 821 func (db *Database) accumulate(hash common.Hash, reachable map[common.Hash]struct{}) { 822 //将节点标记为可访问(如果存在于内存缓存中) 823 node, ok := db.dirties[hash] 824 if !ok { 825 return 826 } 827 reachable[hash] = struct{}{} 828 829 //遍历所有子级并对其进行累积 830 for _, child := range node.childs() { 831 db.accumulate(child, reachable) 832 } 833 } 834