97 lines
2.0 KiB
Go
97 lines
2.0 KiB
Go
package redo
|
||
|
||
import (
|
||
"fmt"
|
||
"hash/crc32"
|
||
"io"
|
||
"os"
|
||
|
||
"gordenko.dev/dima/qb/bin"
|
||
)
|
||
|
||
type REDOFile struct {
|
||
MetricID uint32
|
||
Timestamp uint32
|
||
Value float64
|
||
IsDataPageReused bool
|
||
DataPage PageToWrite
|
||
IsRootChanged bool
|
||
RootPageNo uint32
|
||
ReusedIndexPages []uint32
|
||
IndexPages []PageToWrite
|
||
}
|
||
|
||
type ReadREDOFileReq struct {
|
||
FileName string
|
||
DataPageSize int
|
||
IndexPageSize int
|
||
}
|
||
|
||
func ReadREDOFile(req ReadREDOFileReq) (*REDOFile, error) {
|
||
buf, err := os.ReadFile(req.FileName)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if len(buf) < 25 {
|
||
return nil, io.EOF
|
||
}
|
||
|
||
var (
|
||
end = len(buf) - 4
|
||
payload = buf[:end]
|
||
checksum = bin.GetUint32(buf[end:])
|
||
calculatedChecksum = crc32.ChecksumIEEE(payload)
|
||
)
|
||
|
||
// Помилка чексуми означає що файл або недописаний, або пошкодженний
|
||
if checksum != calculatedChecksum {
|
||
return nil, fmt.Errorf("written checksum %d not equal calculated checksum %d",
|
||
checksum, calculatedChecksum)
|
||
}
|
||
|
||
var (
|
||
redoLog = REDOFile{
|
||
MetricID: bin.GetUint32(buf[0:]),
|
||
Timestamp: bin.GetUint32(buf[4:]),
|
||
Value: bin.GetFloat64(buf[8:]),
|
||
IsDataPageReused: buf[16] == 1,
|
||
DataPage: PageToWrite{
|
||
PageNo: bin.GetUint32(buf[17:]),
|
||
Data: buf[21 : 21+req.DataPageSize],
|
||
},
|
||
}
|
||
pos = 21 + req.DataPageSize
|
||
)
|
||
|
||
for {
|
||
if pos == len(payload) {
|
||
return &redoLog, nil
|
||
}
|
||
|
||
if pos > len(payload) {
|
||
return nil, io.EOF
|
||
}
|
||
|
||
flags := buf[pos]
|
||
|
||
item := PageToWrite{
|
||
PageNo: bin.GetUint32(buf[pos+1:]),
|
||
}
|
||
pos += 5 // flags + pageNo
|
||
item.Data = buf[pos : pos+req.IndexPageSize]
|
||
pos += req.IndexPageSize
|
||
|
||
redoLog.IndexPages = append(redoLog.IndexPages, item)
|
||
|
||
if (flags & FlagReused) == FlagReused {
|
||
redoLog.ReusedIndexPages = append(redoLog.ReusedIndexPages, item.PageNo)
|
||
}
|
||
|
||
if (flags & FlagNewRoot) == FlagNewRoot {
|
||
redoLog.IsRootChanged = true
|
||
redoLog.RootPageNo = item.PageNo
|
||
}
|
||
}
|
||
}
|