master: sync hashicorp raft leadership with seaweedfs/raft leader

When seaweedfs/raft elects a new leader, transfer hashicorp raft leadership
to the same node. This ensures both raft systems always have the same leader,
allowing dual-write to work correctly.

Changes:
- Add SyncHashicorpRaftLeadership() to transfer hashicorp raft leadership
- Call sync on seaweedfs/raft leader change event
- Only the current hashicorp raft leader can initiate transfer
This commit is contained in:
chrislu
2025-12-18 22:33:19 -08:00
parent cad5b8b281
commit bf04ddcae8
2 changed files with 37 additions and 0 deletions

View File

@@ -209,6 +209,8 @@ func (ms *MasterServer) SetRaftServer(raftServer *RaftServer) {
if ms.Topo.RaftServer.Leader() != "" {
glog.V(0).Infof("[%s] %s becomes leader.", ms.Topo.RaftServer.Name(), ms.Topo.RaftServer.Leader())
ms.Topo.LastLeaderChangeTime = time.Now()
// Sync hashicorp raft leadership to match seaweedfs/raft leader for dual-write
raftServer.SyncHashicorpRaftLeadership(ms.Topo.RaftServer.Leader())
}
})
raftServerName = fmt.Sprintf("[%s]", ms.Topo.RaftServer.Name())

View File

@@ -279,3 +279,38 @@ func (s *RaftServer) initHashicorpRaftForDualWrite(option *RaftServerOption) err
return nil
}
// SyncHashicorpRaftLeadership transfers hashicorp raft leadership to match seaweedfs/raft leader.
// This ensures both raft systems have the same leader for dual-write to work correctly.
func (s *RaftServer) SyncHashicorpRaftLeadership(seaweedfsRaftLeader string) {
if s.RaftHashicorp == nil || seaweedfsRaftLeader == "" {
return
}
hashicorpLeader, _ := s.RaftHashicorp.LeaderWithID()
targetLeader := pb.ServerAddress(seaweedfsRaftLeader)
// If hashicorp raft already has the same leader, nothing to do
if string(hashicorpLeader) == targetLeader.ToGrpcAddress() {
glog.V(1).Infof("Dual-write: hashicorp raft leader already matches seaweedfs/raft leader: %s", seaweedfsRaftLeader)
return
}
// Only the current hashicorp raft leader can transfer leadership
if s.RaftHashicorp.State() != hashicorpRaft.Leader {
glog.V(1).Infof("Dual-write: not hashicorp raft leader, cannot transfer leadership to %s", seaweedfsRaftLeader)
return
}
// Transfer leadership to the seaweedfs/raft leader
glog.V(0).Infof("Dual-write: transferring hashicorp raft leadership to match seaweedfs/raft leader: %s", seaweedfsRaftLeader)
future := s.RaftHashicorp.LeadershipTransferToServer(
hashicorpRaft.ServerID(targetLeader),
hashicorpRaft.ServerAddress(targetLeader.ToGrpcAddress()),
)
if err := future.Error(); err != nil {
glog.Warningf("Dual-write: failed to transfer hashicorp raft leadership to %s: %v", seaweedfsRaftLeader, err)
} else {
glog.V(0).Infof("Dual-write: hashicorp raft leadership transferred to %s", seaweedfsRaftLeader)
}
}