弄到凌晨1点钟,才算可以稳稳地跑Lab2A的测试。一共花了好几天来实现,Raft的论文并没有完全指明所有细节,还得自己考虑,另外因为只是做选举部分,因为先看了后面的选举限制部分,还有log部分,选举等到2B实验做完应该还要调整一些地方。

Lab2A实验比我预想花的时间要长,论文那一小段也反反复复扣了N遍。

数据竞争

昨天晚上的大部分时间是在处理data race问题,开始给忘了,后来在网上搜到有别人做的实验的总结,看到他用-race进行了检查,我就想起来在Hint里确实看到了,然后自己检查,结果一大堆数据竞争问题,看到golang的Data Race Detector,然后对比我的情况,全都按照atomic包的方法来处理了,解决了所有检测到的情况。其实一开始写的时候,我就能感受到这种问题,当初也没再仔细深入,只是觉得即使有竞争,造成off by one之类的问题,也并不会对整体有啥破坏,一类没啥影响,一类也就是延迟到下一个循环恢复正确。

发现自己的Bug

开始测试时,全部PASS之后以为自己的没问题。后来又有测试结果是FAIL了,说检测到2个leader,开log检查,定位到voteFor不符合预期,具体错误是:当收到新的RequestVote时,如果请求的term值比当前的高,那么接收方要切换成follower状态,并将响应的VoteGranted置为true。问题出在我将VoteGranted置为true,但我没有将raft节点的VoteFor更新为发起请求节点,导致VoteFor仍保持最初的-1(paper中的null),如果收到term相同的其他节点发来的RequestVote,这个刚才投过票的节点会再次把票投给这个后发请求的节点,从而造成同term两个leader的情况。

换种角度来说,就是一个在当期投过票的人,投完之后没记住,当期又有其他候选人跟他要票,他以为自己没投过(因为没记),所以又投出第二张票,导致他一个人投了两个候选人,两个候选人最后都因此成为了leader。