78 lines
2.2 KiB
Go
78 lines
2.2 KiB
Go
|
package raft
|
||
|
|
||
|
import (
|
||
|
"encoding/binary"
|
||
|
"io"
|
||
|
)
|
||
|
|
||
|
const requestVoteRequestHeaderSize = 4 + 8 + 8 + 8 + 4
|
||
|
|
||
|
// The request sent to a server to vote for a candidate to become a leader.
|
||
|
type RequestVoteRequest struct {
|
||
|
peer *Peer
|
||
|
Term uint64
|
||
|
LastLogIndex uint64
|
||
|
LastLogTerm uint64
|
||
|
CandidateName string
|
||
|
}
|
||
|
|
||
|
// Creates a new RequestVote request.
|
||
|
func newRequestVoteRequest(term uint64, candidateName string, lastLogIndex uint64, lastLogTerm uint64) *RequestVoteRequest {
|
||
|
return &RequestVoteRequest{
|
||
|
Term: term,
|
||
|
LastLogIndex: lastLogIndex,
|
||
|
LastLogTerm: lastLogTerm,
|
||
|
CandidateName: candidateName,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (req *RequestVoteRequest) encode(w io.Writer) (int, error) {
|
||
|
candidateNameSize := len(req.CandidateName)
|
||
|
b := make([]byte, requestVoteRequestHeaderSize + candidateNameSize)
|
||
|
|
||
|
// Write request.
|
||
|
binary.BigEndian.PutUint32(b[0:4], protocolVersion)
|
||
|
binary.BigEndian.PutUint64(b[4:12], req.Term)
|
||
|
binary.BigEndian.PutUint64(b[12:20], req.LastLogIndex)
|
||
|
binary.BigEndian.PutUint64(b[20:28], req.LastLogTerm)
|
||
|
binary.BigEndian.PutUint32(b[28:32], uint32(candidateNameSize))
|
||
|
copy(b[32:], []byte(req.CandidateName))
|
||
|
|
||
|
return w.Write(b)
|
||
|
}
|
||
|
|
||
|
func (req *RequestVoteRequest) decode(r io.Reader) (int, error) {
|
||
|
var eof error
|
||
|
header := make([]byte, requestVoteRequestHeaderSize)
|
||
|
if n, err := r.Read(header); err == io.EOF {
|
||
|
return n, io.ErrUnexpectedEOF
|
||
|
} else if err != nil {
|
||
|
return n, err
|
||
|
}
|
||
|
|
||
|
// Read candidate name.
|
||
|
candidateName := make([]byte, binary.BigEndian.Uint32(header[28:32]))
|
||
|
if n, err := r.Read(candidateName); err == io.EOF {
|
||
|
if err == io.EOF && n != len(candidateName) {
|
||
|
return requestVoteRequestHeaderSize+n, io.ErrUnexpectedEOF
|
||
|
} else {
|
||
|
eof = io.EOF
|
||
|
}
|
||
|
} else if err != nil {
|
||
|
return requestVoteRequestHeaderSize+n, err
|
||
|
}
|
||
|
totalBytes := requestVoteRequestHeaderSize + len(candidateName)
|
||
|
|
||
|
// Verify that the encoding format can be read.
|
||
|
if version := binary.BigEndian.Uint32(header[0:4]); version != protocolVersion {
|
||
|
return totalBytes, errUnsupportedLogVersion
|
||
|
}
|
||
|
|
||
|
req.Term = binary.BigEndian.Uint64(header[4:12])
|
||
|
req.LastLogIndex = binary.BigEndian.Uint64(header[12:20])
|
||
|
req.LastLogTerm = binary.BigEndian.Uint64(header[20:28])
|
||
|
req.CandidateName = string(candidateName)
|
||
|
|
||
|
return totalBytes, eof
|
||
|
}
|