mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-12 04:41:22 +00:00
msgLogFP -> write ahead log
This commit is contained in:
113
consensus/wal.go
Normal file
113
consensus/wal.go
Normal file
@ -0,0 +1,113 @@
|
||||
package consensus
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
. "github.com/tendermint/go-common"
|
||||
"github.com/tendermint/go-wire"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
//--------------------------------------------------------
|
||||
// types and functions for savings consensus messages
|
||||
|
||||
type ConsensusLogMessage struct {
|
||||
Time time.Time `json:"time"`
|
||||
Msg ConsensusLogMessageInterface `json:"msg"`
|
||||
}
|
||||
|
||||
type ConsensusLogMessageInterface interface{}
|
||||
|
||||
var _ = wire.RegisterInterface(
|
||||
struct{ ConsensusLogMessageInterface }{},
|
||||
wire.ConcreteType{&types.EventDataRoundState{}, 0x01},
|
||||
wire.ConcreteType{msgInfo{}, 0x02},
|
||||
wire.ConcreteType{timeoutInfo{}, 0x03},
|
||||
)
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Simple write-ahead logger
|
||||
|
||||
// Write ahead logger writes msgs to disk before they are processed.
|
||||
// Can be used for crash-recovery and deterministic replay
|
||||
type WAL struct {
|
||||
fp *os.File
|
||||
exists bool // if the file already existed (restarted process)
|
||||
}
|
||||
|
||||
func NewWAL(file string) (*WAL, error) {
|
||||
var walExists bool
|
||||
if _, err := os.Stat(file); err == nil {
|
||||
walExists = true
|
||||
}
|
||||
fp, err := os.OpenFile(file, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &WAL{
|
||||
fp: fp,
|
||||
exists: walExists,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// called in newStep and for each pass in receiveRoutine
|
||||
func (wal *WAL) Save(msg ConsensusLogMessageInterface) {
|
||||
if wal != nil {
|
||||
var n int
|
||||
var err error
|
||||
wire.WriteJSON(ConsensusLogMessage{time.Now(), msg}, wal.fp, &n, &err)
|
||||
wire.WriteTo([]byte("\n"), wal.fp, &n, &err) // one message per line
|
||||
if err != nil {
|
||||
PanicQ(Fmt("Error writing msg to consensus wal. Error: %v \n\nMessage: %v", err, msg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Must not be called concurrently.
|
||||
func (wal *WAL) Close() {
|
||||
if wal != nil {
|
||||
wal.fp.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (wal *WAL) SeekFromEnd(found func([]byte) bool) (nLines int, err error) {
|
||||
var current int64
|
||||
// start at the end
|
||||
current, err = wal.fp.Seek(0, 2)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// backup until we find the the right line
|
||||
for {
|
||||
current -= 1
|
||||
if current < 0 {
|
||||
return
|
||||
}
|
||||
// backup one and read a new byte
|
||||
if _, err = wal.fp.Seek(current, 0); err != nil {
|
||||
return
|
||||
}
|
||||
b := make([]byte, 1)
|
||||
if _, err = wal.fp.Read(b); err != nil {
|
||||
return
|
||||
}
|
||||
if b[0] == '\n' || len(b) == 0 {
|
||||
// read a full line
|
||||
reader := bufio.NewReader(wal.fp)
|
||||
lineBytes, _ := reader.ReadBytes('\n')
|
||||
if len(lineBytes) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
nLines += 1
|
||||
if found(lineBytes) {
|
||||
wal.fp.Seek(0, 1) // (?)
|
||||
wal.fp.Seek(current, 0)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user