github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/protocols/reporter.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:41</date>
    10  //</624450106082463744>
    11  
    12  
    13  package protocols
    14  
    15  import (
    16  	"encoding/binary"
    17  	"time"
    18  
    19  	"github.com/ethereum/go-ethereum/log"
    20  	"github.com/ethereum/go-ethereum/metrics"
    21  
    22  	"github.com/syndtr/goleveldb/leveldb"
    23  )
    24  
    25  //AccountMetrics提取了度量数据库,并
    26  //报告者坚持标准
    27  type AccountingMetrics struct {
    28  	reporter *reporter
    29  }
    30  
    31  //关闭节点时将调用Close。
    32  //为了优雅的清理
    33  func (am *AccountingMetrics) Close() {
    34  	close(am.reporter.quit)
    35  	am.reporter.db.Close()
    36  }
    37  
    38  //Reporter是一种内部结构,用于编写与P2P会计相关的
    39  //指标达到了B级。它将定期向数据库写入应计指标。
    40  type reporter struct {
    41  reg      metrics.Registry //这些度量的注册表(独立于其他度量)
    42  interval time.Duration    //报告者将保持度量的持续时间
    43  db       *leveldb.DB      //实际数据库
    44  quit     chan struct{}    //退出Reporter循环
    45  }
    46  
    47  //NewMetricsDB创建一个新的LevelDB实例,用于持久化定义的度量
    48  //在p2p/protocols/accounting.go中
    49  func NewAccountingMetrics(r metrics.Registry, d time.Duration, path string) *AccountingMetrics {
    50  	var val = make([]byte, 8)
    51  	var err error
    52  
    53  //创建级别数据库
    54  	db, err := leveldb.OpenFile(path, nil)
    55  	if err != nil {
    56  		log.Error(err.Error())
    57  		return nil
    58  	}
    59  
    60  //检查数据库中是否存在值的所有已定义度量
    61  //如果存在,请将其分配给度量。这意味着节点
    62  //以前一直在运行,并且该度量值已被持久化。
    63  	metricsMap := map[string]metrics.Counter{
    64  		"account.balance.credit": mBalanceCredit,
    65  		"account.balance.debit":  mBalanceDebit,
    66  		"account.bytes.credit":   mBytesCredit,
    67  		"account.bytes.debit":    mBytesDebit,
    68  		"account.msg.credit":     mMsgCredit,
    69  		"account.msg.debit":      mMsgDebit,
    70  		"account.peerdrops":      mPeerDrops,
    71  		"account.selfdrops":      mSelfDrops,
    72  	}
    73  //迭代映射并获取值
    74  	for key, metric := range metricsMap {
    75  		val, err = db.Get([]byte(key), nil)
    76  //直到第一次写入值,
    77  //这将返回一个错误。
    78  //尽管以后记录错误是有益的,
    79  //但这需要一个不同的逻辑
    80  		if err == nil {
    81  			metric.Inc(int64(binary.BigEndian.Uint64(val)))
    82  		}
    83  	}
    84  
    85  //创建报告人
    86  	rep := &reporter{
    87  		reg:      r,
    88  		interval: d,
    89  		db:       db,
    90  		quit:     make(chan struct{}),
    91  	}
    92  
    93  //执行执行例行程序
    94  	go rep.run()
    95  
    96  	m := &AccountingMetrics{
    97  		reporter: rep,
    98  	}
    99  
   100  	return m
   101  }
   102  
   103  //运行是一个goroutine,它定期将度量发送到配置的级别db
   104  func (r *reporter) run() {
   105  	intervalTicker := time.NewTicker(r.interval)
   106  
   107  	for {
   108  		select {
   109  		case <-intervalTicker.C:
   110  //在每个勾选处发送指标
   111  			if err := r.save(); err != nil {
   112  				log.Error("unable to send metrics to LevelDB", "err", err)
   113  //如果在写入过程中出现错误,请退出该例程;我们在此假定错误为
   114  //严重,不要再尝试写入。
   115  //此外,这应该可以防止节点停止时发生泄漏。
   116  				return
   117  			}
   118  		case <-r.quit:
   119  //正常关机
   120  			return
   121  		}
   122  	}
   123  }
   124  
   125  //将指标发送到数据库
   126  func (r *reporter) save() error {
   127  //创建一个级别数据库批处理
   128  	batch := leveldb.Batch{}
   129  //对于注册表中的每个指标(独立的)
   130  	r.reg.Each(func(name string, i interface{}) {
   131  		metric, ok := i.(metrics.Counter)
   132  		if ok {
   133  //假设这里的每个度量都是一个计数器(单独的注册表)
   134  //…创建快照…
   135  			ms := metric.Snapshot()
   136  			byteVal := make([]byte, 8)
   137  			binary.BigEndian.PutUint64(byteVal, uint64(ms.Count()))
   138  //…并将值保存到数据库
   139  			batch.Put([]byte(name), byteVal)
   140  		}
   141  	})
   142  	return r.db.Write(&batch, nil)
   143  }
   144