influxdb/raft/encoder.go

80 lines
1.8 KiB
Go

package raft
import (
"encoding/binary"
"io"
)
// LogEntryEncoder encodes entries to a writer.
type LogEntryEncoder struct {
w io.Writer
}
// NewLogEntryEncoder returns a new instance of the LogEntryEncoder that
// will encode to a writer.
func NewLogEntryEncoder(w io.Writer) *LogEntryEncoder {
return &LogEntryEncoder{w: w}
}
// Encode writes a log entry to the encoder's writer.
func (enc *LogEntryEncoder) Encode(e *LogEntry) error {
// Write header.
if _, err := enc.w.Write(e.encodedHeader()); err != nil {
return err
}
// Write data.
if _, err := enc.w.Write(e.Data); err != nil {
return err
}
return nil
}
// LogEntryDecoder decodes entries from a reader.
type LogEntryDecoder struct {
r io.Reader
}
// NewLogEntryDecoder returns a new instance of the LogEntryDecoder that
// will decode from a reader.
func NewLogEntryDecoder(r io.Reader) *LogEntryDecoder {
return &LogEntryDecoder{r: r}
}
// Decode reads a log entry from the decoder's reader.
func (dec *LogEntryDecoder) Decode(e *LogEntry) error {
// Read first byte to determine the log entry type.
var b [logEntryHeaderSize]byte
if _, err := io.ReadFull(dec.r, b[:1]); err != nil {
return err
}
e.Type = LogEntryType(b[0])
// If it's a snapshot then return immediately.
if e.Type == logEntrySnapshot {
e.Index = 0
e.Term = 0
e.Data = nil
return nil
}
// If it's not a snapshot then read the full header.
if _, err := io.ReadFull(dec.r, b[1:]); err == io.EOF {
return io.ErrUnexpectedEOF
} else if err != nil {
return err
}
sz := binary.BigEndian.Uint64(b[0:8]) & 0x00FFFFFFFFFFFFFF
e.Index = binary.BigEndian.Uint64(b[8:16])
e.Term = binary.BigEndian.Uint64(b[16:24])
// Read data.
data := make([]byte, sz)
if _, err := io.ReadFull(dec.r, data); err != nil && err != io.EOF {
return err
}
e.Data = data
return nil
}