You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
96 lines
2.0 KiB
96 lines
2.0 KiB
package redo
|
|
|
|
import (
|
|
"fmt"
|
|
"hash/crc32"
|
|
"io"
|
|
"os"
|
|
|
|
"gordenko.dev/dima/diploma/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
|
|
}
|
|
}
|
|
}
|
|
|