Unverified Commit 21a49bad authored by Jay Guo's avatar Jay Guo Committed by Artem Barger
Browse files

[FAB-13438] Store raft SoftState



Store raft SoftState in raft chain so it returns error
while election is ongoing. This prevents a disconnected
follower from returning success on Broadcast API.

Change-Id: Ib6619b230938f0d6c10240b8cd8e34e346056145
Signed-off-by: default avatarJay Guo <guojiannan1101@gmail.com>
parent 657b8095
......@@ -399,7 +399,7 @@ func (c *Chain) serveRequest() {
ticking = false
}
var leader uint64
var soft raft.SoftState
submitC := c.submitC
var bc *blockCreator
......@@ -434,8 +434,13 @@ func (c *Chain) serveRequest() {
continue
}
if soft.RaftState == raft.StatePreCandidate || soft.RaftState == raft.StateCandidate {
s.errC <- errors.Errorf("no Raft leader")
continue
}
var err error
switch leader {
switch soft.Lead {
case raft.None: // no Raft leader
c.logger.Debugf("Request is dropped because there is no Raft leader")
err = errors.Errorf("no Raft leader")
......@@ -457,8 +462,8 @@ func (c *Chain) serveRequest() {
}
default: // this is follower
c.logger.Debugf("Forwarding submit request to raft leader %d", leader)
err = c.rpc.SendSubmit(leader, s.req)
c.logger.Debugf("Forwarding submit request to raft leader %d", soft.Lead)
err = c.rpc.SendSubmit(soft.Lead, s.req)
}
s.errC <- err // send error back to submitter
......@@ -466,23 +471,23 @@ func (c *Chain) serveRequest() {
case app := <-c.applyC:
if app.soft != nil {
newLeader := atomic.LoadUint64(&app.soft.Lead) // etcdraft requires atomic access
if newLeader != leader {
c.logger.Infof("Raft leader changed: %d -> %d", leader, newLeader)
if newLeader != soft.Lead {
c.logger.Infof("Raft leader changed: %d -> %d", soft.Lead, newLeader)
if newLeader == c.raftID {
becomeLeader()
}
if leader == c.raftID {
if soft.Lead == c.raftID {
becomeFollower()
}
leader = newLeader
}
soft = raft.SoftState{Lead: newLeader, RaftState: app.soft.RaftState}
// notify external observer
select {
case c.observeC <- raft.SoftState{Lead: leader, RaftState: app.soft.RaftState}:
case c.observeC <- soft:
default:
}
}
......
......@@ -1828,6 +1828,21 @@ var _ = Describe("Chain", func() {
})
})
When("follower is disconnected", func() {
It("should return error when receiving an env", func() {
network.disconnect(2)
By("Ticking node 2 until it becomes pre-candidate")
Eventually(func() <-chan raft.SoftState {
c2.clock.Increment(interval)
return c2.observe
}, LongEventualTimeout).Should(Receive(Equal(raft.SoftState{Lead: 1, RaftState: raft.StatePreCandidate})))
err := c2.Order(env, 0)
Expect(err).To(HaveOccurred())
})
})
It("leader retransmits lost messages", func() {
// This tests that heartbeats will trigger leader to retransmit lost MsgApp
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment