commit
b67b95a296
48
peer.go
48
peer.go
|
@ -89,14 +89,14 @@ func (p *Peer) startHeartbeat() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stops the peer heartbeat.
|
// Stops the peer heartbeat.
|
||||||
func (p *Peer) stopHeartbeat() {
|
func (p *Peer) stopHeartbeat(flush bool) {
|
||||||
// here is a problem
|
// here is a problem
|
||||||
// the previous stop is no buffer leader may get blocked
|
// the previous stop is no buffer leader may get blocked
|
||||||
// when heartbeat returns at line 132
|
// when heartbeat returns
|
||||||
// I make the channel with 1 buffer
|
// I make the channel with 1 buffer
|
||||||
// and try to panic here
|
// and try to panic here
|
||||||
select {
|
select {
|
||||||
case p.stopChan <- true:
|
case p.stopChan <- flush:
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("[" + p.server.Name() + "] cannot stop [" + p.Name() + "] heartbeat")
|
panic("[" + p.server.Name() + "] cannot stop [" + p.Name() + "] heartbeat")
|
||||||
|
@ -132,28 +132,40 @@ func (p *Peer) heartbeat(c chan bool) {
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-stopChan:
|
case flush := <-stopChan:
|
||||||
debugln("peer.heartbeat.stop: ", p.Name())
|
if !flush {
|
||||||
return
|
debugln("peer.heartbeat.stop: ", p.Name())
|
||||||
|
return
|
||||||
case <-time.After(p.heartbeatTimeout):
|
} else {
|
||||||
debugln("peer.heartbeat.run: ", p.Name())
|
// before we can safely remove a node
|
||||||
prevLogIndex := p.getPrevLogIndex()
|
// we must flush the remove command to the node first
|
||||||
entries, prevLogTerm := p.server.log.getEntriesAfter(prevLogIndex, p.server.maxLogEntriesPerRequest)
|
p.flush()
|
||||||
|
debugln("peer.heartbeat.stop: ", p.Name())
|
||||||
if p.server.State() != Leader {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if entries != nil {
|
case <-time.After(p.heartbeatTimeout):
|
||||||
p.sendAppendEntriesRequest(newAppendEntriesRequest(p.server.currentTerm, prevLogIndex, prevLogTerm, p.server.log.CommitIndex(), p.server.name, entries))
|
p.flush()
|
||||||
} else {
|
|
||||||
p.sendSnapshotRequest(newSnapshotRequest(p.server.name, p.server.lastSnapshot))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Peer) flush() {
|
||||||
|
debugln("peer.heartbeat.run: ", p.Name())
|
||||||
|
prevLogIndex := p.getPrevLogIndex()
|
||||||
|
entries, prevLogTerm := p.server.log.getEntriesAfter(prevLogIndex, p.server.maxLogEntriesPerRequest)
|
||||||
|
|
||||||
|
if p.server.State() != Leader {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if entries != nil {
|
||||||
|
p.sendAppendEntriesRequest(newAppendEntriesRequest(p.server.currentTerm, prevLogIndex, prevLogTerm, p.server.log.CommitIndex(), p.server.name, entries))
|
||||||
|
} else {
|
||||||
|
p.sendSnapshotRequest(newSnapshotRequest(p.server.name, p.server.lastSnapshot))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------
|
//--------------------------------------
|
||||||
// Append Entries
|
// Append Entries
|
||||||
//--------------------------------------
|
//--------------------------------------
|
||||||
|
|
21
server.go
21
server.go
|
@ -719,7 +719,7 @@ func (s *Server) leaderLoop() {
|
||||||
|
|
||||||
// Stop all peers.
|
// Stop all peers.
|
||||||
for _, peer := range s.peers {
|
for _, peer := range s.peers {
|
||||||
peer.stopHeartbeat()
|
peer.stopHeartbeat(false)
|
||||||
}
|
}
|
||||||
s.syncedPeer = nil
|
s.syncedPeer = nil
|
||||||
}
|
}
|
||||||
|
@ -1009,10 +1009,6 @@ func (s *Server) AddPeer(name string) error {
|
||||||
func (s *Server) RemovePeer(name string) error {
|
func (s *Server) RemovePeer(name string) error {
|
||||||
s.debugln("server.peer.remove: ", name, len(s.peers))
|
s.debugln("server.peer.remove: ", name, len(s.peers))
|
||||||
|
|
||||||
// Ignore removal of the server itself.
|
|
||||||
if s.name == name {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// Return error if peer doesn't exist.
|
// Return error if peer doesn't exist.
|
||||||
peer := s.peers[name]
|
peer := s.peers[name]
|
||||||
if peer == nil {
|
if peer == nil {
|
||||||
|
@ -1022,7 +1018,9 @@ func (s *Server) RemovePeer(name string) error {
|
||||||
// TODO: Flush entries to the peer first.
|
// TODO: Flush entries to the peer first.
|
||||||
|
|
||||||
// Stop peer and remove it.
|
// Stop peer and remove it.
|
||||||
peer.stopHeartbeat()
|
if s.State() == Leader {
|
||||||
|
peer.stopHeartbeat(true)
|
||||||
|
}
|
||||||
|
|
||||||
delete(s.peers, name)
|
delete(s.peers, name)
|
||||||
|
|
||||||
|
@ -1043,16 +1041,7 @@ func (s *Server) RemovePeer(name string) error {
|
||||||
// Log compaction
|
// Log compaction
|
||||||
//--------------------------------------
|
//--------------------------------------
|
||||||
|
|
||||||
// The background snapshot function
|
func (s *Server) TakeSnapshot() error {
|
||||||
func (s *Server) Snapshot() {
|
|
||||||
for {
|
|
||||||
// TODO: change this... to something reasonable
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
s.takeSnapshot()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) takeSnapshot() error {
|
|
||||||
//TODO put a snapshot mutex
|
//TODO put a snapshot mutex
|
||||||
s.debugln("take Snapshot")
|
s.debugln("take Snapshot")
|
||||||
if s.currentSnapshot != nil {
|
if s.currentSnapshot != nil {
|
||||||
|
|
Loading…
Reference in New Issue