github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/shed/db.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:44</date>
    10  //</624450117457416192>
    11  
    12  
    13  //包棚提供了一个简单的抽象组件来组成
    14  //对按字段和索引组织的存储数据进行更复杂的操作。
    15  //
    16  //唯一保存有关群存储块数据的逻辑信息的类型
    17  //元数据是项。这一部分主要不是为了
    18  //性能原因。
    19  package shed
    20  
    21  import (
    22  	"errors"
    23  	"fmt"
    24  	"strconv"
    25  	"strings"
    26  	"time"
    27  
    28  	"github.com/ethereum/go-ethereum/metrics"
    29  	"github.com/ethereum/go-ethereum/swarm/log"
    30  	"github.com/syndtr/goleveldb/leveldb"
    31  	"github.com/syndtr/goleveldb/leveldb/iterator"
    32  	"github.com/syndtr/goleveldb/leveldb/opt"
    33  )
    34  
    35  const (
    36  openFileLimit              = 128 //级别ldb openfilescachecapacity的限制。
    37  	writePauseWarningThrottler = 1 * time.Minute
    38  )
    39  
    40  //DB在级别数据库上提供抽象,以便
    41  //使用字段和有序索引实现复杂结构。
    42  //它提供了一个模式功能来存储字段和索引
    43  //有关命名和类型的信息。
    44  type DB struct {
    45  	ldb *leveldb.DB
    46  
    47  compTimeMeter    metrics.Meter //用于测量数据库压缩所花费的总时间的仪表
    48  compReadMeter    metrics.Meter //测量压实过程中读取数据的仪表
    49  compWriteMeter   metrics.Meter //测量压实过程中写入数据的仪表
    50  writeDelayNMeter metrics.Meter //用于测量数据库压缩导致的写入延迟数的仪表
    51  writeDelayMeter  metrics.Meter //用于测量数据库压缩导致的写入延迟持续时间的仪表
    52  diskReadMeter    metrics.Meter //测量有效数据读取量的仪表
    53  diskWriteMeter   metrics.Meter //测量写入数据有效量的仪表
    54  
    55  quitChan chan chan error //退出通道以在关闭数据库之前停止度量集合
    56  }
    57  
    58  //new db构造新的db并验证架构
    59  //如果它存在于给定路径上的数据库中。
    60  //metricsPrefix用于为给定数据库收集度量。
    61  func NewDB(path string, metricsPrefix string) (db *DB, err error) {
    62  	ldb, err := leveldb.OpenFile(path, &opt.Options{
    63  		OpenFilesCacheCapacity: openFileLimit,
    64  	})
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  	db = &DB{
    69  		ldb: ldb,
    70  	}
    71  
    72  	if _, err = db.getSchema(); err != nil {
    73  		if err == leveldb.ErrNotFound {
    74  //用已初始化的默认字段保存架构
    75  			if err = db.putSchema(schema{
    76  				Fields:  make(map[string]fieldSpec),
    77  				Indexes: make(map[byte]indexSpec),
    78  			}); err != nil {
    79  				return nil, err
    80  			}
    81  		} else {
    82  			return nil, err
    83  		}
    84  	}
    85  
    86  //为DB配置仪表
    87  	db.configure(metricsPrefix)
    88  
    89  //为定期度量收集器创建退出通道并运行它
    90  	db.quitChan = make(chan chan error)
    91  
    92  	go db.meter(10 * time.Second)
    93  
    94  	return db, nil
    95  }
    96  
    97  //将Wrapps-LevelDB-Put方法添加到增量度量计数器。
    98  func (db *DB) Put(key []byte, value []byte) (err error) {
    99  	err = db.ldb.Put(key, value, nil)
   100  	if err != nil {
   101  		metrics.GetOrRegisterCounter("DB.putFail", nil).Inc(1)
   102  		return err
   103  	}
   104  	metrics.GetOrRegisterCounter("DB.put", nil).Inc(1)
   105  	return nil
   106  }
   107  
   108  //get wrapps leveldb get方法以增加度量计数器。
   109  func (db *DB) Get(key []byte) (value []byte, err error) {
   110  	value, err = db.ldb.Get(key, nil)
   111  	if err != nil {
   112  		if err == leveldb.ErrNotFound {
   113  			metrics.GetOrRegisterCounter("DB.getNotFound", nil).Inc(1)
   114  		} else {
   115  			metrics.GetOrRegisterCounter("DB.getFail", nil).Inc(1)
   116  		}
   117  		return nil, err
   118  	}
   119  	metrics.GetOrRegisterCounter("DB.get", nil).Inc(1)
   120  	return value, nil
   121  }
   122  
   123  //DELETE包装级别DB DELETE方法以增加度量计数器。
   124  func (db *DB) Delete(key []byte) (err error) {
   125  	err = db.ldb.Delete(key, nil)
   126  	if err != nil {
   127  		metrics.GetOrRegisterCounter("DB.deleteFail", nil).Inc(1)
   128  		return err
   129  	}
   130  	metrics.GetOrRegisterCounter("DB.delete", nil).Inc(1)
   131  	return nil
   132  }
   133  
   134  //NewIterator将LevelDB NewIterator方法包装为增量度量计数器。
   135  func (db *DB) NewIterator() iterator.Iterator {
   136  	metrics.GetOrRegisterCounter("DB.newiterator", nil).Inc(1)
   137  
   138  	return db.ldb.NewIterator(nil, nil)
   139  }
   140  
   141  //WRITEBATCH将LEVELDB WRITE方法包装为增量度量计数器。
   142  func (db *DB) WriteBatch(batch *leveldb.Batch) (err error) {
   143  	err = db.ldb.Write(batch, nil)
   144  	if err != nil {
   145  		metrics.GetOrRegisterCounter("DB.writebatchFail", nil).Inc(1)
   146  		return err
   147  	}
   148  	metrics.GetOrRegisterCounter("DB.writebatch", nil).Inc(1)
   149  	return nil
   150  }
   151  
   152  //关闭关闭级别数据库。
   153  func (db *DB) Close() (err error) {
   154  	close(db.quitChan)
   155  	return db.ldb.Close()
   156  }
   157  
   158  //配置配置数据库度量收集器
   159  func (db *DB) configure(prefix string) {
   160  //在请求的前缀处初始化所有度量收集器
   161  	db.compTimeMeter = metrics.NewRegisteredMeter(prefix+"compact/time", nil)
   162  	db.compReadMeter = metrics.NewRegisteredMeter(prefix+"compact/input", nil)
   163  	db.compWriteMeter = metrics.NewRegisteredMeter(prefix+"compact/output", nil)
   164  	db.diskReadMeter = metrics.NewRegisteredMeter(prefix+"disk/read", nil)
   165  	db.diskWriteMeter = metrics.NewRegisteredMeter(prefix+"disk/write", nil)
   166  	db.writeDelayMeter = metrics.NewRegisteredMeter(prefix+"compact/writedelay/duration", nil)
   167  	db.writeDelayNMeter = metrics.NewRegisteredMeter(prefix+"compact/writedelay/counter", nil)
   168  }
   169  
   170  func (db *DB) meter(refresh time.Duration) {
   171  //创建计数器以存储当前和以前的压缩值
   172  	compactions := make([][]float64, 2)
   173  	for i := 0; i < 2; i++ {
   174  		compactions[i] = make([]float64, 3)
   175  	}
   176  //为iostats创建存储。
   177  	var iostats [2]float64
   178  
   179  //为写入延迟创建存储和警告日志跟踪程序。
   180  	var (
   181  		delaystats      [2]int64
   182  		lastWritePaused time.Time
   183  	)
   184  
   185  	var (
   186  		errc chan error
   187  		merr error
   188  	)
   189  
   190  //无限迭代并收集统计信息
   191  	for i := 1; errc == nil && merr == nil; i++ {
   192  //检索数据库状态
   193  		stats, err := db.ldb.GetProperty("leveldb.stats")
   194  		if err != nil {
   195  			log.Error("Failed to read database stats", "err", err)
   196  			merr = err
   197  			continue
   198  		}
   199  //找到压缩表,跳过标题
   200  		lines := strings.Split(stats, "\n")
   201  		for len(lines) > 0 && strings.TrimSpace(lines[0]) != "Compactions" {
   202  			lines = lines[1:]
   203  		}
   204  		if len(lines) <= 3 {
   205  			log.Error("Compaction table not found")
   206  			merr = errors.New("compaction table not found")
   207  			continue
   208  		}
   209  		lines = lines[3:]
   210  
   211  //遍历所有表行,并累积条目
   212  		for j := 0; j < len(compactions[i%2]); j++ {
   213  			compactions[i%2][j] = 0
   214  		}
   215  		for _, line := range lines {
   216  			parts := strings.Split(line, "|")
   217  			if len(parts) != 6 {
   218  				break
   219  			}
   220  			for idx, counter := range parts[3:] {
   221  				value, err := strconv.ParseFloat(strings.TrimSpace(counter), 64)
   222  				if err != nil {
   223  					log.Error("Compaction entry parsing failed", "err", err)
   224  					merr = err
   225  					continue
   226  				}
   227  				compactions[i%2][idx] += value
   228  			}
   229  		}
   230  //更新所有要求的仪表
   231  		if db.compTimeMeter != nil {
   232  			db.compTimeMeter.Mark(int64((compactions[i%2][0] - compactions[(i-1)%2][0]) * 1000 * 1000 * 1000))
   233  		}
   234  		if db.compReadMeter != nil {
   235  			db.compReadMeter.Mark(int64((compactions[i%2][1] - compactions[(i-1)%2][1]) * 1024 * 1024))
   236  		}
   237  		if db.compWriteMeter != nil {
   238  			db.compWriteMeter.Mark(int64((compactions[i%2][2] - compactions[(i-1)%2][2]) * 1024 * 1024))
   239  		}
   240  
   241  //检索写入延迟统计信息
   242  		writedelay, err := db.ldb.GetProperty("leveldb.writedelay")
   243  		if err != nil {
   244  			log.Error("Failed to read database write delay statistic", "err", err)
   245  			merr = err
   246  			continue
   247  		}
   248  		var (
   249  			delayN        int64
   250  			delayDuration string
   251  			duration      time.Duration
   252  			paused        bool
   253  		)
   254  		if n, err := fmt.Sscanf(writedelay, "DelayN:%d Delay:%s Paused:%t", &delayN, &delayDuration, &paused); n != 3 || err != nil {
   255  			log.Error("Write delay statistic not found")
   256  			merr = err
   257  			continue
   258  		}
   259  		duration, err = time.ParseDuration(delayDuration)
   260  		if err != nil {
   261  			log.Error("Failed to parse delay duration", "err", err)
   262  			merr = err
   263  			continue
   264  		}
   265  		if db.writeDelayNMeter != nil {
   266  			db.writeDelayNMeter.Mark(delayN - delaystats[0])
   267  		}
   268  		if db.writeDelayMeter != nil {
   269  			db.writeDelayMeter.Mark(duration.Nanoseconds() - delaystats[1])
   270  		}
   271  //如果显示了数据库正在执行压缩的警告,则
   272  //警告将被保留一分钟,以防压倒用户。
   273  		if paused && delayN-delaystats[0] == 0 && duration.Nanoseconds()-delaystats[1] == 0 &&
   274  			time.Now().After(lastWritePaused.Add(writePauseWarningThrottler)) {
   275  			log.Warn("Database compacting, degraded performance")
   276  			lastWritePaused = time.Now()
   277  		}
   278  		delaystats[0], delaystats[1] = delayN, duration.Nanoseconds()
   279  
   280  //检索数据库iostats。
   281  		ioStats, err := db.ldb.GetProperty("leveldb.iostats")
   282  		if err != nil {
   283  			log.Error("Failed to read database iostats", "err", err)
   284  			merr = err
   285  			continue
   286  		}
   287  		var nRead, nWrite float64
   288  		parts := strings.Split(ioStats, " ")
   289  		if len(parts) < 2 {
   290  			log.Error("Bad syntax of ioStats", "ioStats", ioStats)
   291  			merr = fmt.Errorf("bad syntax of ioStats %s", ioStats)
   292  			continue
   293  		}
   294  		if n, err := fmt.Sscanf(parts[0], "Read(MB):%f", &nRead); n != 1 || err != nil {
   295  			log.Error("Bad syntax of read entry", "entry", parts[0])
   296  			merr = err
   297  			continue
   298  		}
   299  		if n, err := fmt.Sscanf(parts[1], "Write(MB):%f", &nWrite); n != 1 || err != nil {
   300  			log.Error("Bad syntax of write entry", "entry", parts[1])
   301  			merr = err
   302  			continue
   303  		}
   304  		if db.diskReadMeter != nil {
   305  			db.diskReadMeter.Mark(int64((nRead - iostats[0]) * 1024 * 1024))
   306  		}
   307  		if db.diskWriteMeter != nil {
   308  			db.diskWriteMeter.Mark(int64((nWrite - iostats[1]) * 1024 * 1024))
   309  		}
   310  		iostats[0], iostats[1] = nRead, nWrite
   311  
   312  //睡一会儿,然后重复统计数据收集
   313  		select {
   314  		case errc = <-db.quitChan:
   315  //停止请求,停止锤击数据库
   316  		case <-time.After(refresh):
   317  //超时,收集一组新的统计信息
   318  		}
   319  	}
   320  
   321  	if errc == nil {
   322  		errc = <-db.quitChan
   323  	}
   324  	errc <- merr
   325  }
   326