Files
qb/storage/wal_reader.go

187 lines
3.4 KiB
Go
Raw Normal View History

2026-06-10 06:18:45 +03:00
package storage
2026-02-10 14:02:11 +00:00
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"os"
2026-06-09 08:16:16 +03:00
bin "gordenko.dev/dima/bin/little"
"gordenko.dev/dima/qb/util"
2026-02-10 14:02:11 +00:00
)
2026-06-09 08:16:16 +03:00
const readBufferSize = 8 * 1024 * 1024
2026-06-10 06:18:45 +03:00
type WALReader struct {
2026-06-09 08:16:16 +03:00
file *os.File
reader *bufio.Reader
current []any
next []any
2026-02-10 14:02:11 +00:00
}
2026-06-10 06:18:45 +03:00
type WALReaderOptions struct {
2026-02-10 14:02:11 +00:00
FileName string
BufferSize int
}
2026-06-10 06:18:45 +03:00
func NewWALReader(opt WALReaderOptions) (*WALReader, error) {
2026-02-10 14:02:11 +00:00
if opt.FileName == "" {
return nil, errors.New("FileName option is required")
}
if opt.BufferSize <= 0 {
return nil, errors.New("BufferSize option is required")
}
file, err := os.Open(opt.FileName)
if err != nil {
return nil, err
}
2026-06-10 06:18:45 +03:00
return &WALReader{
2026-02-10 14:02:11 +00:00
file: file,
2026-06-09 08:16:16 +03:00
reader: bufio.NewReaderSize(file, readBufferSize),
2026-02-10 14:02:11 +00:00
}, nil
}
2026-06-10 06:18:45 +03:00
func (s *WALReader) Close() {
2026-02-10 14:02:11 +00:00
s.file.Close()
}
2026-06-10 06:18:45 +03:00
func (s *WALReader) NextPacket() ([]any, bool, error) {
2026-06-09 08:16:16 +03:00
var err error
if s.current == nil {
s.current, err = s.readPacket()
if err != nil {
return nil, false, err
}
if len(s.current) > 0 {
s.next, err = s.readPacket()
if err != nil {
return nil, false, err
}
}
}
current := s.current
done := s.next == nil
s.current = s.next
s.next, err = s.readPacket()
2026-02-10 14:02:11 +00:00
if err != nil {
2026-06-09 08:16:16 +03:00
return nil, false, err
}
return current, done, nil
}
2026-06-10 06:18:45 +03:00
func (s *WALReader) readPacket() (_ []any, err error) {
2026-06-09 08:16:16 +03:00
payloadSize, err := bin.ReadVarSize(s.reader)
if err != nil {
if err == io.EOF {
return nil, nil
2026-02-10 14:02:11 +00:00
} else {
2026-06-09 08:16:16 +03:00
return
2026-02-10 14:02:11 +00:00
}
}
2026-06-09 08:16:16 +03:00
storedCRC, err := bin.ReadUint32(s.reader)
if err != nil {
return
}
2026-02-10 14:02:11 +00:00
2026-06-09 08:16:16 +03:00
body, err := bin.ReadN(s.reader, int(payloadSize))
2026-02-10 14:02:11 +00:00
if err != nil {
2026-06-09 08:16:16 +03:00
return
2026-02-10 14:02:11 +00:00
}
2026-06-09 08:16:16 +03:00
hasher := util.NewHasher()
2026-02-10 14:02:11 +00:00
hasher.Write(body)
calculatedCRC := hasher.Sum32()
2026-06-09 08:16:16 +03:00
if calculatedCRC == storedCRC {
return s.parseRecords(body)
2026-02-10 14:02:11 +00:00
}
2026-06-09 08:16:16 +03:00
//s.logger.Printf("stored CRC %d != calculated CRC %d", storedCRC, calculatedCRC)
return nil, nil
2026-02-10 14:02:11 +00:00
}
2026-06-10 06:18:45 +03:00
func (s *WALReader) parseRecords(body []byte) ([]any, error) {
2026-02-10 14:02:11 +00:00
var (
src = bytes.NewBuffer(body)
records []any
)
for {
recordType, err := src.ReadByte()
if err != nil {
if err == io.EOF {
return records, nil
}
return nil, err
}
switch recordType {
2026-06-10 06:18:45 +03:00
case CodeMetricAdd:
rec := new(MetricAddRecord)
2026-05-10 00:59:47 +00:00
if err = rec.Parse(src); err != nil {
2026-02-10 14:02:11 +00:00
return nil, err
}
records = append(records, rec)
2026-06-10 06:18:45 +03:00
case CodeMetricDelete:
rec := new(MetricDeleteRecord)
2026-05-10 00:59:47 +00:00
if err = rec.Parse(src); err != nil {
2026-02-10 14:02:11 +00:00
return nil, err
}
records = append(records, rec)
2026-05-21 23:38:52 +03:00
// case CodeAppendedMeasure:
// rec := new(AppendedMeasure)
// if err = rec.Parse(src); err != nil {
// return nil, err
// }
// records = append(records, rec)
// case CodeAppendedMeasures:
// rec := new(AppendedMeasures)
// if err = rec.Parse(src); err != nil {
// return nil, err
// }
// records = append(records, rec)
// case CodeAppendedPages:
// rec := new(AppendedPages)
// if err = rec.Parse(src); err != nil {
// return nil, err
// }
// records = append(records, rec)
2026-02-10 14:02:11 +00:00
2026-06-10 06:18:45 +03:00
case CodeMeasuresDelete:
2026-06-13 08:01:42 +03:00
rec := new(MeasuresDeleteRecord)
2026-05-10 00:59:47 +00:00
if err = rec.Parse(src); err != nil {
2026-02-10 14:02:11 +00:00
return nil, err
}
records = append(records, rec)
default:
return nil, fmt.Errorf("unknown record type code: %d", recordType)
}
}
}
// HELPERS
2026-06-14 07:57:01 +03:00
// func (s *WALReader) Seek(offset int64) error {
// ret, err := s.file.Seek(offset, 0)
// if err != nil {
// return err
// }
// if ret != offset {
// return fmt.Errorf("ret %d != offset %d", ret, offset)
// }
// return nil
// }