92 lines
2.0 KiB
Go
92 lines
2.0 KiB
Go
package wal
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"hash/crc32"
|
|
"io"
|
|
|
|
"git.crumpington.com/public/jldb/lib/errs"
|
|
)
|
|
|
|
const recordHeaderSize = 28
|
|
|
|
type Record struct {
|
|
SeqNum int64
|
|
TimestampMS int64
|
|
DataSize int64
|
|
Reader io.Reader
|
|
}
|
|
|
|
func (rec Record) writeHeaderTo(w io.Writer) (int, error) {
|
|
buf := make([]byte, recordHeaderSize)
|
|
binary.LittleEndian.PutUint64(buf[0:], uint64(rec.SeqNum))
|
|
binary.LittleEndian.PutUint64(buf[8:], uint64(rec.TimestampMS))
|
|
binary.LittleEndian.PutUint64(buf[16:], uint64(rec.DataSize))
|
|
crc := crc32.ChecksumIEEE(buf[:recordHeaderSize-4])
|
|
binary.LittleEndian.PutUint32(buf[24:], crc)
|
|
|
|
n, err := w.Write(buf)
|
|
if err != nil {
|
|
err = errs.IO.WithErr(err)
|
|
}
|
|
return n, err
|
|
}
|
|
|
|
func (rec *Record) readHeaderFrom(r io.Reader) error {
|
|
buf := make([]byte, recordHeaderSize)
|
|
if _, err := io.ReadFull(r, buf); err != nil {
|
|
return errs.IO.WithErr(err)
|
|
}
|
|
|
|
crc := crc32.ChecksumIEEE(buf[:recordHeaderSize-4])
|
|
stored := binary.LittleEndian.Uint32(buf[recordHeaderSize-4:])
|
|
if crc != stored {
|
|
return errs.Corrupt.WithMsg("checksum mismatch")
|
|
}
|
|
|
|
rec.SeqNum = int64(binary.LittleEndian.Uint64(buf[0:]))
|
|
rec.TimestampMS = int64(binary.LittleEndian.Uint64(buf[8:]))
|
|
rec.DataSize = int64(binary.LittleEndian.Uint64(buf[16:]))
|
|
|
|
return nil
|
|
}
|
|
|
|
func (rec Record) serializedSize() int64 {
|
|
return recordHeaderSize + rec.DataSize + 4 // 4 for data CRC32.
|
|
}
|
|
|
|
func (rec Record) writeTo(w io.Writer) (int64, error) {
|
|
nn, err := rec.writeHeaderTo(w)
|
|
if err != nil {
|
|
return int64(nn), err
|
|
}
|
|
|
|
n := int64(nn)
|
|
|
|
// Write the data.
|
|
crcW := newCRCWriter(w)
|
|
n2, err := io.CopyN(crcW, rec.Reader, rec.DataSize)
|
|
n += n2
|
|
if err != nil {
|
|
return n, errs.IO.WithErr(err)
|
|
}
|
|
|
|
// Write the data crc value.
|
|
err = binary.Write(w, binary.LittleEndian, crcW.CRC())
|
|
if err != nil {
|
|
return n, errs.IO.WithErr(err)
|
|
}
|
|
n += 4
|
|
|
|
return n, nil
|
|
}
|
|
|
|
func (rec *Record) readFrom(r io.Reader) error {
|
|
if err := rec.readHeaderFrom(r); err != nil {
|
|
return err
|
|
}
|
|
|
|
rec.Reader = newDataReader(r, rec.DataSize)
|
|
return nil
|
|
}
|