当前位置:网站首页>ETCD数据库源码分析——rawnode简单封装
ETCD数据库源码分析——rawnode简单封装
2022-07-05 13:36:00 【肥叔菌】
在etcd 3.6.0之前是没有rawnode模块,现在出现的rawnode.go仅仅是raft模块的简单封装,并将raft.Node run协程中每轮循环需要保存的raft的前一次硬软状态prevSoftSt和prevHardSt保存到rawnode结构体中。如下为rawnode结构体的定义:
// RawNode is a thread-unsafe Node. The methods of this struct correspond to the methods of Node and are described more fully there.
type RawNode struct {
raft *raft
prevSoftSt *SoftState
prevHardSt pb.HardState
}
rawnode提供的接口如下所示,粗体的函数会被其他模块调用,从这些接口函数我们可以看到作为raft模块的封装需要提供哪些接口:
NewRawNode实例化给定配置中的RawNode。有关引导初始状态的信息,请参阅Bootstrap();这取代了该方法的前“peers”参数(具有相同的行为)。但是,建议应用程序不调用引导,而是通过设置第一个索引大于1且将所需ConfState存储为其初始状态的存储器来手动引导其状态。这部分可以看node.go中的startNode和RestartNode函数。
// NewRawNode instantiates a RawNode from the given configuration. See Bootstrap() for bootstrapping an initial state; this replaces the former 'peers' argument to this method (with identical behavior). However, It is recommended that instead of calling Bootstrap, applications bootstrap their state manually by setting up a Storage that has a first index > 1 and which stores the desired ConfState as its InitialState.
func NewRawNode(config *Config) (*RawNode, error) {
r := newRaft(config)
rn := &RawNode{
raft: r, }
rn.prevSoftSt = r.softState()
rn.prevHardSt = r.hardState()
return rn, nil
}
Tick将内部逻辑时钟提前一个Tick,可以查看ETCD数据库源码分析——从raftNode的start函数说起文章看查看逻辑时钟调用链原理。
func (rn *RawNode) Tick() {
rn.raft.tick() } // Tick advances the internal logical clock by a single tick.
acceptReady:当RawNode的使用者决定继续处理Ready时,调用acceptReady。在这个调用和之前对Ready()的调用之间,任何东西都不能改变RawNode的状态。
// acceptReady is called when the consumer of the RawNode has decided to go
// ahead and handle a Ready. Nothing must alter the state of the RawNode between
// this call and the prior call to Ready().
func (rn *RawNode) acceptReady(rd Ready) {
if rd.SoftState != nil {
rn.prevSoftSt = rd.SoftState }
if len(rd.ReadStates) != 0 {
rn.raft.readStates = nil }
rn.raft.msgs = nil
}
readyWithoutAccept返回Ready实例。这是一个只读操作,即没有必须处理就绪的义务。
// readyWithoutAccept returns a Ready. This is a read-only operation, i.e. there
// is no obligation that the Ready must be handled.
func (rn *RawNode) readyWithoutAccept() Ready {
return newReady(rn.raft, rn.prevSoftSt, rn.prevHardSt)
}
HasReady在RawNode用户需要检查是否有任何准备就绪挂起时调用。此方法中的检查逻辑应与Ready.containsUpdates()一致。
// HasReady called when RawNode user need to check if any Ready pending.
// Checking logic in this method should be consistent with Ready.containsUpdates().
func (rn *RawNode) HasReady() bool {
r := rn.raft
if !r.softState().equal(rn.prevSoftSt) {
return true }
if hardSt := r.hardState(); !IsEmptyHardState(hardSt) && !isHardStateEqual(hardSt, rn.prevHardSt) {
return true }
if r.raftLog.hasPendingSnapshot() {
return true }
if len(r.msgs) > 0 || len(r.raftLog.unstableEntries()) > 0 || r.raftLog.hasNextEnts() {
return true }
if len(r.readStates) != 0 {
return true }
return false
}
Advance通知RawNode应用程序已应用并保存最后就绪结果中的进度。
// Advance notifies the RawNode that the application has applied and saved progress in the
// last Ready results.
func (rn *RawNode) Advance(rd Ready) {
if !IsEmptyHardState(rd.HardState) {
rn.prevHardSt = rd.HardState }
rn.raft.advance(rd)
}
TickQuiesced将内部逻辑时钟提前一个滴答,而不执行任何其他状态机处理。当已知Raft组中的所有对等点处于同一状态时,调用方可以避免周期性心跳和选举。预期用法是根据组是“活动”还是“静止”定期调用Tick或tickquiesed。警告:使用此方法时要非常小心,因为它会破坏Raft状态机。你可能应该改用Tick。
// TickQuiesced advances the internal logical clock by a single tick without
// performing any other state machine processing. It allows the caller to avoid
// periodic heartbeats and elections when all of the peers in a Raft group are
// known to be at the same state. Expected usage is to periodically invoke Tick
// or TickQuiesced depending on whether the group is "active" or "quiesced".
//
// WARNING: Be very careful about using this method as it subverts the Raft
// state machine. You should probably be using Tick instead.
func (rn *RawNode) TickQuiesced() {
rn.raft.electionElapsed++ }
Campaign导致此RawNode转换为候选状态。
// Campaign causes this RawNode to transition to candidate state.
func (rn *RawNode) Campaign() error {
return rn.raft.Step(pb.Message{
Type: pb.MsgHup, }) }
Propose将数据附加到筏形日志中。
// Propose proposes data be appended to the raft log.
func (rn *RawNode) Propose(data []byte) error {
return rn.raft.Step(pb.Message{
Type: pb.MsgProp,From: rn.raft.id,Entries: []pb.Entry{
{
Data: data},}}) }
ProposeConfChange提出配置更改。
// ProposeConfChange proposes a config change. See (Node).ProposeConfChange for details.
func (rn *RawNode) ProposeConfChange(cc pb.ConfChangeI) error {
m, err := confChangeToMsg(cc)
if err != nil {
return err }
return rn.raft.Step(m)
}
ApplyConfChange将配置更改应用于本地节点。应用程序在应用配置更改时必须调用此选项,除非它决定拒绝配置更改,在这种情况下,不得调用。
// ApplyConfChange applies a config change to the local node. The app must call
// this when it applies a configuration change, except when it decides to reject
// the configuration change, in which case no call must take place.
func (rn *RawNode) ApplyConfChange(cc pb.ConfChangeI) *pb.ConfState {
cs := rn.raft.applyConfChange(cc.AsV2())
return &cs
}
Step使用给定消息推进状态机。
// Step advances the state machine using the given message.
func (rn *RawNode) Step(m pb.Message) error {
// ignore unexpected local messages receiving over network
if IsLocalMsg(m.Type) {
return ErrStepLocalMsg }
if pr := rn.raft.prs.Progress[m.From]; pr != nil || !IsResponseMsg(m.Type) {
return rn.raft.Step(m) }
return ErrStepPeerNotFound
}
ReportUnreachable报告上次发送时无法访问给定节点。ReportSnapshot报告已发送快照的状态。TransferLeader尝试将领导权转移给给定的受让人。ReadIndex请求读取状态。读取状态将设置为就绪。读取状态具有读取索引。一旦应用程序的进程超过读取索引,则可以安全地处理在读取请求之前发出的任何可线性化的读取请求。读取状态将连接相同的rctx。
// ReportUnreachable reports the given node is not reachable for the last send.
func (rn *RawNode) ReportUnreachable(id uint64) {
_ = rn.raft.Step(pb.Message{
Type: pb.MsgUnreachable, From: id}) }
// ReportSnapshot reports the status of the sent snapshot.
func (rn *RawNode) ReportSnapshot(id uint64, status SnapshotStatus) {
rej := status == SnapshotFailure
_ = rn.raft.Step(pb.Message{
Type: pb.MsgSnapStatus, From: id, Reject: rej})
}
// TransferLeader tries to transfer leadership to the given transferee.
func (rn *RawNode) TransferLeader(transferee uint64) {
_ = rn.raft.Step(pb.Message{
Type: pb.MsgTransferLeader, From: transferee}) }
// ReadIndex requests a read state. The read state will be set in ready.
// Read State has a read index. Once the application advances further than the read
// index, any linearizable read requests issued before the read request can be
// processed safely. The read state will have the same rctx attached.
func (rn *RawNode) ReadIndex(rctx []byte) {
_ = rn.raft.Step(pb.Message{
Type: pb.MsgReadIndex, Entries: []pb.Entry{
{
Data: rctx}}}) }
Ready返回应用程序需要处理的未完成工作。这包括附加和应用条目或快照、更新硬状态和发送消息。返回的Ready()必须处理,然后通过Advance()传回。
// Ready returns the outstanding work that the application needs to handle. This
// includes appending and applying entries or a snapshot, updating the HardState,
// and sending messages. The returned Ready() *must* be handled and subsequently
// passed back via Advance().
func (rn *RawNode) Ready() Ready {
rd := rn.readyWithoutAccept()
rn.acceptReady(rd)
return rd
}
Status返回给定组的当前状态。这将进行分配,请参阅BasicStatus和WithProgress以获得更友好的分配选择。BasicStatus返回BasicStatus。值得注意的是,这并不包含进度图;请参阅WithProgress,了解无需分配的检查方法。
// Status returns the current status of the given group. This allocates, see
// BasicStatus and WithProgress for allocation-friendlier choices.
func (rn *RawNode) Status() Status {
status := getStatus(rn.raft)
return status
}
// BasicStatus returns a BasicStatus. Notably this does not contain the
// Progress map; see WithProgress for an allocation-free way to inspect it.
func (rn *RawNode) BasicStatus() BasicStatus {
return getBasicStatus(rn.raft) }
WithProgress是一个帮助器,用于反思此节点及其对等节点的进度。
type ProgressType byte // ProgressType indicates the type of replica a Progress corresponds to.
const (
ProgressTypePeer ProgressType = iota // ProgressTypePeer accompanies a Progress for a regular peer replica.
ProgressTypeLearner // ProgressTypeLearner accompanies a Progress for a learner replica.
)
// WithProgress is a helper to introspect the Progress for this node and its peers.
func (rn *RawNode) WithProgress(visitor func(id uint64, typ ProgressType, pr tracker.Progress)) {
rn.raft.prs.Visit(func(id uint64, pr *tracker.Progress) {
typ := ProgressTypePeer
if pr.IsLearner {
typ = ProgressTypeLearner
}
p := *pr
p.Inflights = nil
visitor(id, typ, p)
})
}
边栏推荐
- "Baidu Cup" CTF competition in September, web:upload
- [深度学习论文笔记]使用多模态MR成像分割脑肿瘤的HNF-Netv2
- MySQL - database query - sort query, paging query
- 【MySQL 使用秘籍】一网打尽 MySQL 时间和日期类型与相关操作函数(三)
- Basic characteristics and isolation level of transactions
- Jenkins installation
- Write API documents first or code first?
- Programmer growth Chapter 8: do a good job of testing
- Reflection and imagination on the notation like tool
- zabbix 监控
猜你喜欢

内网穿透工具 netapp

运筹说 第68期|2022年最新影响因子正式发布 快看管科领域期刊的变化

Flutter 3.0更新后如何应用到小程序开发中

Could not set property 'ID' of 'class xx' with value 'XX' argument type mismatch solution

Huawei push service content, read notes

jenkins安装

一网打尽异步神器CompletableFuture

FPGA learning notes: vivado 2019.1 add IP MicroBlaze

Intranet penetration tool NetApp

When using Tencent cloud for the first time, you can only use webshell connection instead of SSH connection.
随机推荐
Difference between avc1 and H264
一网打尽异步神器CompletableFuture
Flutter draws animation effects of wave movement, curves and line graphs
Could not set property ‘id‘ of ‘class XX‘ with value ‘XX‘ argument type mismatch 解决办法
Rocky basic command 3
Shu tianmeng map × Weiyan technology - Dream map database circle of friends + 1
今年上半年,通信行业发生了哪些事?
时钟周期
Mmseg - Mutli view time series data inspection and visualization
Programmer growth Chapter 8: do a good job of testing
C object storage
[深度学习论文笔记]使用多模态MR成像分割脑肿瘤的HNF-Netv2
Datapipeline was selected into the 2022 digital intelligence atlas and database development report of China Academy of communications and communications
redis6数据类型及操作总结
Idea set method annotation and class annotation
Cloudcompare - point cloud slice
Basic characteristics and isolation level of transactions
Data Lake (VII): Iceberg concept and review what is a data Lake
The development of speech recognition app with uni app is simple and fast.
Go array and slice