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 } } }