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