summaryrefslogtreecommitdiff
path: root/ovsdb/raft.c
diff options
context:
space:
mode:
authorHan Zhou <hzhou@ovn.org>2020-03-05 23:48:45 -0800
committerBen Pfaff <blp@ovn.org>2020-03-06 14:32:32 -0800
commit93ee420935547da00de54d70efe4f4f02a36e8b3 (patch)
tree94baa502ff538447636936b728c25f83618252fc /ovsdb/raft.c
parent315e88cb4dd9c524ac111323f9d064678cf06a5e (diff)
downloadopenvswitch-93ee420935547da00de54d70efe4f4f02a36e8b3.tar.gz
raft: Fix the problem of stuck in candidate role forever.
Sometimes a server can stay in candidate role forever, even if the server already see the new leader and handles append-requests normally. However, because of the wrong role, it appears as disconnected from cluster and so the clients are disconnected. This problem happens when 2 servers become candidates in the same term, and one of them is elected as leader in that term. It can be reproduced by the test cases added in this patch. The root cause is that the current implementation only changes role to follower when a bigger term is observed (in raft_receive_term__()). According to the RAFT paper, if another candidate becomes leader with the same term, the candidate should change to follower. This patch fixes it by changing the role to follower when leader is being updated in raft_update_leader(). Signed-off-by: Han Zhou <hzhou@ovn.org> Signed-off-by: Ben Pfaff <blp@ovn.org>
Diffstat (limited to 'ovsdb/raft.c')
-rw-r--r--ovsdb/raft.c19
1 files changed, 17 insertions, 2 deletions
diff --git a/ovsdb/raft.c b/ovsdb/raft.c
index 161273487..3dfef8245 100644
--- a/ovsdb/raft.c
+++ b/ovsdb/raft.c
@@ -73,7 +73,8 @@ enum raft_failure_test {
FT_CRASH_BEFORE_SEND_EXEC_REQ,
FT_CRASH_AFTER_SEND_EXEC_REQ,
FT_CRASH_AFTER_RECV_APPEND_REQ_UPDATE,
- FT_DELAY_ELECTION
+ FT_DELAY_ELECTION,
+ FT_DONT_SEND_VOTE_REQUEST
};
static enum raft_failure_test failure_test;
@@ -1647,6 +1648,7 @@ raft_start_election(struct raft *raft, bool leadership_transfer)
}
ovs_assert(raft->role != RAFT_LEADER);
+
raft->role = RAFT_CANDIDATE;
/* If there was no leader elected since last election, we know we are
* retrying now. */
@@ -1690,7 +1692,9 @@ raft_start_election(struct raft *raft, bool leadership_transfer)
.leadership_transfer = leadership_transfer,
},
};
- raft_send(raft, &rq);
+ if (failure_test != FT_DONT_SEND_VOTE_REQUEST) {
+ raft_send(raft, &rq);
+ }
}
/* Vote for ourselves. */
@@ -2965,6 +2969,15 @@ raft_update_leader(struct raft *raft, const struct uuid *sid)
};
ignore(ovsdb_log_write_and_free(raft->log, raft_record_to_json(&r)));
}
+ if (raft->role == RAFT_CANDIDATE) {
+ /* Section 3.4: While waiting for votes, a candidate may
+ * receive an AppendEntries RPC from another server claiming to
+ * be leader. If the leader’s term (included in its RPC) is at
+ * least as large as the candidate’s current term, then the
+ * candidate recognizes the leader as legitimate and returns to
+ * follower state. */
+ raft->role = RAFT_FOLLOWER;
+ }
return true;
}
@@ -4673,6 +4686,8 @@ raft_unixctl_failure_test(struct unixctl_conn *conn OVS_UNUSED,
raft_reset_election_timer(raft);
}
}
+ } else if (!strcmp(test, "dont-send-vote-request")) {
+ failure_test = FT_DONT_SEND_VOTE_REQUEST;
} else if (!strcmp(test, "clear")) {
failure_test = FT_NO_TEST;
unixctl_command_reply(conn, "test dismissed");