etcd/wal/wal.go

199 lines
3.4 KiB
Go
Raw Normal View History

2014-07-26 01:20:21 +04:00
package wal
import (
"bufio"
2014-07-26 11:10:59 +04:00
"bytes"
2014-07-26 01:20:21 +04:00
"encoding/binary"
"encoding/json"
"fmt"
2014-07-26 11:10:59 +04:00
"io"
2014-07-26 01:20:21 +04:00
"os"
"github.com/coreos/etcd/raft"
)
var (
infoType = int64(1)
entryType = int64(2)
stateType = int64(3)
)
type WAL struct {
2014-07-28 07:28:41 +04:00
f *os.File
bw *bufio.Writer
buf *bytes.Buffer
2014-07-26 01:20:21 +04:00
}
2014-07-28 07:32:23 +04:00
func newWAL(f *os.File) *WAL {
return &WAL{f, bufio.NewWriter(f), new(bytes.Buffer)}
}
2014-07-26 01:20:21 +04:00
func New(path string) (*WAL, error) {
2014-07-26 01:54:08 +04:00
f, err := os.Open(path)
if err == nil {
f.Close()
return nil, os.ErrExist
}
f, err = os.Create(path)
2014-07-26 01:20:21 +04:00
if err != nil {
return nil, err
}
2014-07-28 07:32:23 +04:00
return newWAL(f), nil
2014-07-26 01:20:21 +04:00
}
2014-07-26 11:10:59 +04:00
func Open(path string) (*WAL, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
2014-07-28 07:32:23 +04:00
return newWAL(f), nil
2014-07-26 11:10:59 +04:00
}
2014-07-26 01:54:08 +04:00
func (w *WAL) Close() {
if w.f != nil {
2014-07-28 04:23:04 +04:00
w.Flush()
2014-07-26 01:54:08 +04:00
w.f.Close()
}
}
2014-07-28 04:23:04 +04:00
func (w *WAL) SaveInfo(id int64) error {
2014-07-26 11:10:59 +04:00
if err := w.checkAtHead(); err != nil {
2014-07-26 01:20:21 +04:00
return err
}
2014-07-28 07:28:41 +04:00
w.buf.Reset()
err := binary.Write(w.buf, binary.LittleEndian, id)
2014-07-28 04:23:04 +04:00
if err != nil {
panic(err)
2014-07-26 01:20:21 +04:00
}
2014-07-28 07:28:41 +04:00
return writeBlock(w.bw, infoType, w.buf.Bytes())
2014-07-26 01:20:21 +04:00
}
2014-07-28 04:23:04 +04:00
func (w *WAL) SaveEntry(e *raft.Entry) error {
// protobuf?
2014-07-26 01:20:21 +04:00
b, err := json.Marshal(e)
if err != nil {
2014-07-28 04:23:04 +04:00
panic(err)
2014-07-26 01:20:21 +04:00
}
2014-07-28 04:23:04 +04:00
return writeBlock(w.bw, entryType, b)
2014-07-26 01:20:21 +04:00
}
2014-07-28 04:23:04 +04:00
func (w *WAL) SaveState(s *raft.State) error {
2014-07-28 07:28:41 +04:00
w.buf.Reset()
err := binary.Write(w.buf, binary.LittleEndian, s)
2014-07-28 04:23:04 +04:00
if err != nil {
panic(err)
2014-07-26 01:20:21 +04:00
}
2014-07-28 07:28:41 +04:00
return writeBlock(w.bw, stateType, w.buf.Bytes())
2014-07-26 01:20:21 +04:00
}
2014-07-28 04:23:04 +04:00
func (w *WAL) Flush() error {
2014-07-26 01:20:21 +04:00
return w.bw.Flush()
}
2014-07-26 02:21:04 +04:00
2014-07-26 11:10:59 +04:00
func (w *WAL) checkAtHead() error {
o, err := w.f.Seek(0, os.SEEK_CUR)
if err != nil {
return err
}
if o != 0 || w.bw.Buffered() != 0 {
return fmt.Errorf("cannot write info at %d, expect 0", max(o, int64(w.bw.Buffered())))
}
return nil
}
type Node struct {
Id int64
Ents []raft.Entry
State raft.State
}
2014-07-28 04:23:04 +04:00
func (w *WAL) LoadNode() (*Node, error) {
2014-07-26 11:10:59 +04:00
if err := w.checkAtHead(); err != nil {
return nil, err
}
br := bufio.NewReader(w.f)
2014-07-28 07:28:41 +04:00
b := &block{}
2014-07-26 11:10:59 +04:00
2014-07-28 07:28:41 +04:00
err := readBlock(br, b)
2014-07-26 11:10:59 +04:00
if err != nil {
return nil, err
}
2014-07-28 04:23:04 +04:00
if b.t != infoType {
return nil, fmt.Errorf("the first block of wal is not infoType but %d", b.t)
}
id, err := loadInfo(b.d)
if err != nil {
return nil, err
2014-07-26 11:10:59 +04:00
}
ents := make([]raft.Entry, 0)
var state raft.State
2014-07-28 07:28:41 +04:00
for err = readBlock(br, b); err == nil; err = readBlock(br, b) {
2014-07-26 11:10:59 +04:00
switch b.t {
case entryType:
2014-07-28 04:23:04 +04:00
e, err := loadEntry(b.d)
2014-07-26 11:10:59 +04:00
if err != nil {
return nil, err
}
ents = append(ents, e)
case stateType:
2014-07-28 04:23:04 +04:00
s, err := loadState(b.d)
2014-07-26 11:10:59 +04:00
if err != nil {
return nil, err
}
state = s
default:
2014-07-28 04:23:04 +04:00
return nil, fmt.Errorf("unexpected block type %d", b.t)
2014-07-26 11:10:59 +04:00
}
}
2014-07-28 04:23:04 +04:00
if err != io.EOF {
return nil, err
}
return &Node{id, ents, state}, nil
2014-07-26 11:10:59 +04:00
}
2014-07-28 04:23:04 +04:00
func loadInfo(d []byte) (int64, error) {
2014-07-26 11:10:59 +04:00
if len(d) != 8 {
return 0, fmt.Errorf("len = %d, want 8", len(d))
}
buf := bytes.NewBuffer(d)
return readInt64(buf)
}
2014-07-28 04:23:04 +04:00
func loadEntry(d []byte) (raft.Entry, error) {
2014-07-26 11:10:59 +04:00
var e raft.Entry
err := json.Unmarshal(d, &e)
return e, err
}
2014-07-28 04:23:04 +04:00
func loadState(d []byte) (raft.State, error) {
2014-07-26 11:10:59 +04:00
var s raft.State
buf := bytes.NewBuffer(d)
err := binary.Read(buf, binary.LittleEndian, &s)
return s, err
}
2014-07-28 04:23:04 +04:00
func writeInt64(w io.Writer, n int64) error {
return binary.Write(w, binary.LittleEndian, n)
2014-07-26 11:10:59 +04:00
}
func readInt64(r io.Reader) (int64, error) {
var n int64
err := binary.Read(r, binary.LittleEndian, &n)
return n, err
}
2014-07-28 04:23:04 +04:00
func unexpectedEOF(err error) error {
if err == io.EOF {
return io.ErrUnexpectedEOF
}
return err
}
2014-07-26 02:21:04 +04:00
func max(a, b int64) int64 {
if a > b {
return a
}
return b
}