ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

TinyKV lab2b完成总结

2022-03-19 13:33:04  阅读:187  来源: 互联网

标签:总结 ps nil err Region TinyKV key entries lab2b


lab2b

集群视图下的日志的复制和状态的写入。
与lab2a相比,lab2b需要阅读大量代码了解整个集群是怎么工作的。首先,我们要对整个集群有个大概的了解(可以看文档)。

node和store看作等价的就行

可以看到,一个node上面可以跑多个Raft实例(叫做Peer/RaftGroup),每个Peer属于不同的Region,每个Region管理不同的key。他们之间的关系如下:
一个store可以有多个Region,每个Region之间的key space不重叠
一个store上可以有多个Peer,每个Peer对应一个Region
一个Region可以跨越多个store,可以由多个Peer组成
在lab2b里面,不会有一个store包含多个Region的情况
我们大概了解一下各种各样的key和state,这里官方已经给出了一个很详细的表了。这里需要注意的是写入的是kv还是raft数据库,以及这些state是每次有更新就得去写入。然后是消息写入流程,消息的写入是通过peer读取RawNode返回的Ready的消息封装成peer的消息然后调用Send方法放进了context中的transport接口,然后通过transport的router保存的集群节点信息发送到对应的节点,节点的HandleMsg函数会根据消息类型,如果是Raft消息就调用RawNode的Step函数。如果是RaftCMD消息,比如说是Get/Put/Delete,则调用proposeRaftCMD函数,这个就是我们需要实现的地方。除此之外,我们还要实现HandleRaftReady函数。

proposeRaftCMD函数

这个函数的功能是把客户端的命令的数据写入Raft状态机。我们先看key是不是当前region(只有msg.Request有key,AdminRequest没有),如果不是则返回RegionErr(lab2b还不需要考虑AdminRequest),否则反序列化成Raft状态机消息,并设置d.proposal(我们要通过d.proposal的callback保存响应返回上层,设计成这样子是可以异步返回响应而不会阻塞等待Raft完成日志复制过程),最后调用RawNode.Propose()。

func (d *peerMsgHandler) proposeRaftCommand(msg *raft_cmdpb.RaftCmdRequest, cb *message.Callback) {
	err := d.preProposeRaftCommand(msg)
	if err != nil {
		cb.Done(ErrResp(err))
		return
	}
	// Your Code Here (2B).

	if msg.AdminRequest == nil {
		key := getReqKey(msg.Requests[0])
		if key != nil {
			if err := util.CheckKeyInRegion(key, d.Region()); err != nil {
				cb.Done(ErrResp(err))
				return
			}
		}

		d.proposals = append(d.proposals, &proposal{
			index: d.nextProposalIndex(),
			term:  d.Term(),
			cb:    cb,
		})
	}

	dat, err := msg.Marshal()
	if err != nil {
		panic(err)
	}
	err = d.RaftGroup.Propose(dat)
	if err != nil {
		panic(err)
	}
}

HandleRaftReady函数

HandleRaftReady是集群对Raft的日志进行处理的函数,包括保存Ready的状态到存储器和设置RaftLog的一些值。首先看保存Ready状态。这里需要处理Ready中的HardState(SoftState不需要保存)和追加日志,注意这些日志当中可能有已经保存到存储器的日志了,我们需要删除掉这一部分,然后设置RaftLog的值

// Append the given entries to the raft log and update ps.raftState also delete log entries that will
// never be committed
func (ps *PeerStorage) Append(entries []eraftpb.Entry, raftWB *engine_util.WriteBatch) error {
	// Your Code Here (2B).
	if len(entries) == 0 {
		return nil
	}
	psLast, _ := ps.LastIndex()
	pos := 0
	for _, e := range entries {
		if e.Index > psLast {
			break
		}
		pos++
	}
	entries = entries[pos:]
	if len(entries) == 0 {
		return nil
	}
	for _, e := range entries {
		raftWB.SetMeta(meta.RaftLogKey(ps.region.Id, e.Index), &e)
	}
	ps.raftState.LastIndex = entries[len(entries)-1].Index
	ps.raftState.LastTerm = entries[len(entries)-1].Term
	return nil
}

然后把HardState和日志写到存储器

// Save memory states to disk.
// Do not modify ready in this function, this is a requirement to advance the ready object properly later.
func (ps *PeerStorage) SaveReadyState(ready *raft.Ready) (*ApplySnapResult, error) {
	// Hint: you may call `Append()` and `ApplySnapshot()` in this function
	// Your Code Here (2B/2C).

	wb := &engine_util.WriteBatch{}
	var res *ApplySnapResult
	var err error
	if err = ps.Append(ready.Entries, wb); err != nil {
		return nil, err
	}
	if !raft.IsEmptyHardState(ready.HardState) {
		ps.raftState.HardState = &ready.HardState
	}
	wb.SetMeta(meta.RaftStateKey(ps.region.Id), ps.raftState)
	wb.WriteToDB(ps.Engines.Raft)

	return res, err
}

完成以上部分,再注意细节,我们就可以通过lab2b的测试。

标签:总结,ps,nil,err,Region,TinyKV,key,entries,lab2b
来源: https://www.cnblogs.com/mchxyz/p/16023469.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有