hashicorp/raft-boltdb源码解读

本意是想解读Hashicorp Raft,看了一下,发现其引用了一些包,也是这个组织开源的模块,所以干脆先看看这些模块是如何实现的,就当是为了Hashicorp Raft做前期的了解



hashicorp/raft-boltdb

该库引用了BoltDBBoltDB受到LMDB的启发,是一个纯Go实现的简易key/value存储库。



目录结构

以下基于tag:v2.2.0
https://github.com/hashicorp/raft-boltdb/tree/v2.2.0

既然我们是从源码的角度去学习,那么就要先了解清楚这个包的目录结构是如何的。

├── bench_test.go
├── bolt_store.go
├── bolt_store_test.go
├── go.mod
├── go.sum
├── LICENSE
├── Makefile
├── metrics.go
├── README.md
├── util.go
└── v2
    ├── bench_test.go
    ├── bolt_store.go
    ├── bolt_store_test.go
    ├── go.mod
    ├── go.sum
    ├── metrics.go
    ├── README.md
    └── util.go
  • bolt_store.go:该库的主要实现地方
  • bench_test.go:压测文件
  • metrics.go:指标收集
  • util.go:工具类库
  • v2目录:v2是对go.etcd.io/bbolt的实现,没有破坏性的API更改。然而,可能存在磁盘格式不兼容的问题,因此保守地将其设置为单独的导入路径。这是’ raft-boltdb '的主要版本,应该尽可能使用v2。



util.go

先看看util文件做了什么,整个文件都不到50行,很简单,就是对库方法的加了一层封装

package raftboltdb

import (
	"bytes"
	"encoding/binary"

	"github.com/hashicorp/go-msgpack/codec"
)

// msg信息解码
func decodeMsgPack(buf []byte, out interface{
   }) error {
   
	r := bytes.NewBuffer(buf)
	hd := codec.MsgpackHandle{
   }
	dec := codec.NewDecoder(r, &hd)
	return dec.Decode(out)
}

// 将已编码的对象写入新字节缓冲区
func encodeMsgPack(in interface{
   }) (*bytes.Buffer, error) {
   
	buf := bytes.NewBuffer(nil)
	hd := codec.MsgpackHandle{
   }
	enc := codec.NewEncoder(buf, &hd)
	err := enc.Encode(in)
	return buf, err
}

// 将字节进行大端序转换为整数
func bytesToUint64(b []byte) uint64 {
   
	return binary.BigEndian.Uint64(b)
}

// 把数字转换为大端序写入字节切片
func uint64ToBytes(u uint64) []byte {
   
	buf := make([]byte, 8)
	binary.BigEndian.PutUint64(buf, u)
	return buf
}



metrics.go

该文件是对指标的收集,可根据需要去采集数据,在工程实践上指标数据还是十分重要的,监控项目的运行情况

import (
	"context"
	"time"

	metrics "github.com/armon/go-metrics"
	"github.com/boltdb/bolt"
)

const (
	defaultMetricsInterval = 5 * time.Second
)

// RunMetrics should be executed in a go routine and will periodically emit
// metrics on the given interval until the context has been cancelled.
func (b *BoltStore) RunMetrics(ctx context.Context, interval time.Duration) {
   
	if interval == 0 {
   
		interval = defaultMetricsInterval
	}

	tick := time.NewTicker(interval)
	defer tick.Stop()

	stats := b.emitMetrics(nil)
	for {
   
		select {
   
		case <-ctx.Done():
			return
		case <-tick.C:
			stats = b.emitMetrics(stats)
		}
	}
}

func (b *BoltStore) emitMetrics(prev *bolt.Stats) *bolt.Stats {
   
	newStats := b.conn.Stats()

	stats := newStats
	if prev != nil {
   
		stats = newStats.Sub(prev)
	}

	// freelist metrics
	metrics.SetGauge([]string{
   "raft", "boltdb", "numFreePages"}, float32(newStats.FreePageN))
	metrics.SetGauge([]string{
   "raft", "boltdb", "numPendingPages"}, float32(newStats.PendingPageN))
	metrics.SetGauge([]string{
   "raft", "boltdb", "freePageBytes"}, float32(newStats.FreeAlloc))
	metrics.SetGauge([]string{
   "raft", "boltdb", "freelistBytes"}, float32(newStats.FreelistInuse))

	// txn metrics
	metrics.IncrCounter([]string{
   "raft", "boltdb", "totalReadTxn"}, float32(stats.TxN))
	metrics.SetGauge([]string{
   "raft", "boltdb", "openReadTxn"}, float32(newStats.OpenTxN))

	// tx 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值