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