github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/core/tx_journal.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 12:09:34</date> 10 //</624342618704187392> 11 12 13 package core 14 15 import ( 16 "errors" 17 "io" 18 "os" 19 20 "github.com/ethereum/go-ethereum/common" 21 "github.com/ethereum/go-ethereum/core/types" 22 "github.com/ethereum/go-ethereum/log" 23 "github.com/ethereum/go-ethereum/rlp" 24 ) 25 26 //如果试图插入事务,则返回errnoaactivejournal 27 //进入日志,但当前没有打开该文件。 28 var errNoActiveJournal = errors.New("no active journal") 29 30 //devnull是一个只丢弃写入其中的任何内容的writecloser。它的 31 //目标是允许事务日记帐在以下情况下写入假日记帐: 32 //由于没有文件,在启动时加载事务,但不打印警告 33 //正在准备写入。 34 type devNull struct{} 35 36 func (*devNull) Write(p []byte) (n int, err error) { return len(p), nil } 37 func (*devNull) Close() error { return nil } 38 39 //txjournal是一个旋转的事务日志,目的是在本地存储 40 //创建的事务允许未执行的事务在节点重新启动后继续存在。 41 type txJournal struct { 42 path string //存储事务的文件系统路径 43 writer io.WriteCloser //将新事务写入的输出流 44 } 45 46 //newtxjournal创建新的交易日记帐到 47 func newTxJournal(path string) *txJournal { 48 return &txJournal{ 49 path: path, 50 } 51 } 52 53 //LOAD分析事务日志从磁盘转储,将其内容加载到 54 //指定的池。 55 func (journal *txJournal) load(add func([]*types.Transaction) []error) error { 56 //如果日志文件根本不存在,则跳过分析 57 if _, err := os.Stat(journal.path); os.IsNotExist(err) { 58 return nil 59 } 60 //打开日记帐以加载任何过去的交易记录 61 input, err := os.Open(journal.path) 62 if err != nil { 63 return err 64 } 65 defer input.Close() 66 67 //暂时丢弃任何日志添加(加载时不要重复添加) 68 journal.writer = new(devNull) 69 defer func() { journal.writer = nil }() 70 71 //将日记帐中的所有交易记录插入池 72 stream := rlp.NewStream(input, 0) 73 total, dropped := 0, 0 74 75 //创建一个方法来加载有限批事务并 76 //适当的进度计数器。然后使用此方法加载 77 //以小批量记录交易。 78 loadBatch := func(txs types.Transactions) { 79 for _, err := range add(txs) { 80 if err != nil { 81 log.Debug("Failed to add journaled transaction", "err", err) 82 dropped++ 83 } 84 } 85 } 86 var ( 87 failure error 88 batch types.Transactions 89 ) 90 for { 91 //分析下一个事务并在出错时终止 92 tx := new(types.Transaction) 93 if err = stream.Decode(tx); err != nil { 94 if err != io.EOF { 95 failure = err 96 } 97 if batch.Len() > 0 { 98 loadBatch(batch) 99 } 100 break 101 } 102 //已分析新事务,排队等待稍后,如果达到threnshold,则导入 103 total++ 104 105 if batch = append(batch, tx); batch.Len() > 1024 { 106 loadBatch(batch) 107 batch = batch[:0] 108 } 109 } 110 log.Info("Loaded local transaction journal", "transactions", total, "dropped", dropped) 111 112 return failure 113 } 114 115 //insert将指定的事务添加到本地磁盘日志。 116 func (journal *txJournal) insert(tx *types.Transaction) error { 117 if journal.writer == nil { 118 return errNoActiveJournal 119 } 120 if err := rlp.Encode(journal.writer, tx); err != nil { 121 return err 122 } 123 return nil 124 } 125 126 //Rotate根据当前的内容重新生成事务日记帐 127 //事务池。 128 func (journal *txJournal) rotate(all map[common.Address]types.Transactions) error { 129 //关闭当前日记帐(如果有打开的日记帐) 130 if journal.writer != nil { 131 if err := journal.writer.Close(); err != nil { 132 return err 133 } 134 journal.writer = nil 135 } 136 //生成包含当前池内容的新日记 137 replacement, err := os.OpenFile(journal.path+".new", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755) 138 if err != nil { 139 return err 140 } 141 journaled := 0 142 for _, txs := range all { 143 for _, tx := range txs { 144 if err = rlp.Encode(replacement, tx); err != nil { 145 replacement.Close() 146 return err 147 } 148 } 149 journaled += len(txs) 150 } 151 replacement.Close() 152 153 //用新生成的日志替换活日志 154 if err = os.Rename(journal.path+".new", journal.path); err != nil { 155 return err 156 } 157 sink, err := os.OpenFile(journal.path, os.O_WRONLY|os.O_APPEND, 0755) 158 if err != nil { 159 return err 160 } 161 journal.writer = sink 162 log.Info("Regenerated local transaction journal", "transactions", journaled, "accounts", len(all)) 163 164 return nil 165 } 166 167 //close将事务日志内容刷新到磁盘并关闭文件。 168 func (journal *txJournal) close() error { 169 var err error 170 171 if journal.writer != nil { 172 err = journal.writer.Close() 173 journal.writer = nil 174 } 175 return err 176 } 177