package txlog import ( "bytes" bin "gordenko.dev/dima/bin/little" ) type CompletedDataPage struct { PageNo uint32 Reused bool PrevPageNo uint32 Checksum uint32 TimestampsOffset int // offset on 1st page Timestamps []byte ValuesOffset int // offset on 1st page Values []byte } type CompletedIndexPage struct { PageNo uint32 Reused bool Checksum uint32 Records []byte // offset не потрібен, оскільки Records додаються в кінець } type ChangedIndexLevel struct { CompletedIndexPage *CompletedIndexPage IndexPages []SealedIndexPage TailRecords []byte // payload only } type WALRecordAppendMeasures struct { MetricID uint32 CompletedDataPage CompletedDataPage DataPages []SealedDataPage ChangedIndexLevels []ChangedIndexLevel TailTimestamps []byte // data level tail TailValues []byte // data level tail } /* Format appended measures: 1b - tx type 4b - metricID 4b - pageNo 1b - reused 4b - prevPageNo 4b - page crc32 Nb - (varsize) timestamps offset Nb - (varsize) timestamps tail size on 1st filled data page Nb - timestamps tail on 1st filled data page Nb - (varsize) values offset Nb - (varsize) values tail size on 1st filled data page Nb - values tail on 1st filled data page Nb - (varsize) filled data pages qty [ 4b - pageNo 1b - reused Nb - (data page size) page content ] Nb - (varsize) timestamps payload size on tail Nb - timestamps payload Nb - (varsize) values payload size on tail Nb - values payload Nb - (varsize) qty of index levels [ // NOTE! // - idx = 0 - zeroLevel // - skipped = maxRecordsOnIndexPage - records count 4b - pageNo of 1st index page 1b - reused 4b - page crc32 Nb - (varsize) records tail count on 1st filled index page Nb - records tail on 1st filled index page Nb - (varsize) qty of level filled pages [ 4b - pageNo 1b - reused Nb - (index page size) page content ] Nb - (varsize) size of records level tail Nb - level tail records ] */ func (s WALRecordAppendMeasures) WriteTo(w *bytes.Buffer) { w.WriteByte(CodeAppendedMeasures) bin.WriteUint32(w, s.MetricID) // completed data page completed := s.CompletedDataPage bin.WriteUint32(w, completed.PageNo) bin.WriteBool(w, completed.Reused) bin.WriteUint32(w, completed.PrevPageNo) bin.WriteUint32(w, completed.Checksum) bin.WriteVarSize(w, completed.TimestampsOffset) bin.WriteVarSize(w, len(completed.Timestamps)) w.Write(completed.Timestamps) bin.WriteVarSize(w, completed.ValuesOffset) bin.WriteVarSize(w, len(completed.Values)) w.Write(completed.Values) // data pages bin.WriteVarSize(w, len(s.DataPages)) for _, p := range s.DataPages { bin.WriteUint32(w, p.PageNo) bin.WriteBool(w, p.Reused) bin.WriteVarSize(w, len(p.Content)) w.Write(p.Content) } // data tail bin.WriteVarSize(w, len(s.TailTimestamps)) w.Write(s.TailTimestamps) bin.WriteVarSize(w, len(s.TailValues)) w.Write(s.TailValues) // changed levels bin.WriteVarSize(w, len(s.ChangedIndexLevels)) for _, level := range s.ChangedIndexLevels { // completed index page completed := level.CompletedIndexPage bin.WriteUint32(w, completed.PageNo) bin.WriteBool(w, completed.Reused) bin.WriteUint32(w, completed.Checksum) bin.WriteVarSize(w, len(completed.Records)/indexRecordSize) w.Write(completed.Records) // full index pages for _, p := range level.IndexPages { bin.WriteUint32(w, p.PageNo) bin.WriteBool(w, p.Reused) bin.WriteVarSize(w, len(p.Content)) w.Write(p.Content) } // level tail bin.WriteVarSize(w, len(level.TailRecords)/indexRecordSize) w.Write(level.TailRecords) } return } func (s *WALRecordAppendMeasures) Parse(r *bytes.Buffer) (err error) { var ( size int recordsCount int ) s.MetricID, err = bin.ReadUint32(r) if err != nil { return } s.CompletedDataPage.PageNo, err = bin.ReadUint32(r) if err != nil { return } s.CompletedDataPage.Reused, err = bin.ReadBool(r) if err != nil { return } s.CompletedDataPage.PrevPageNo, err = bin.ReadUint32(r) if err != nil { return } s.CompletedDataPage.Checksum, err = bin.ReadUint32(r) if err != nil { return } s.CompletedDataPage.TimestampsOffset, err = bin.ReadVarSize(r) if err != nil { return } size, err = bin.ReadVarSize(r) if err != nil { return } s.CompletedDataPage.Timestamps, err = bin.ReadN(r, size) if err != nil { return } size, err = bin.ReadVarSize(r) if err != nil { return } s.CompletedDataPage.Values, err = bin.ReadN(r, size) if err != nil { return } // data pages dataPagesQty, err := bin.ReadVarSize(r) if err != nil { return } for range dataPagesQty { var ( p SealedDataPage ) p.PageNo, err = bin.ReadUint32(r) if err != nil { return } p.Reused, err = bin.ReadBool(r) if err != nil { return } size, err = bin.ReadVarSize(r) if err != nil { return } p.Content, err = bin.ReadN(r, size) if err != nil { return } s.DataPages = append(s.DataPages, p) } // data tail size, err = bin.ReadVarSize(r) if err != nil { return } s.TailTimestamps, err = bin.ReadN(r, size) if err != nil { return } size, err = bin.ReadVarSize(r) if err != nil { return } s.TailValues, err = bin.ReadN(r, size) if err != nil { return } // changed levels changedIndexLevelsCount, err := bin.ReadVarSize(r) if err != nil { return } for range changedIndexLevelsCount { var ( indexPagesCount int level ChangedIndexLevel ) // completed index page level.CompletedIndexPage.PageNo, err = bin.ReadUint32(r) if err != nil { return } level.CompletedIndexPage.Reused, err = bin.ReadBool(r) if err != nil { return } level.CompletedIndexPage.Checksum, err = bin.ReadUint32(r) if err != nil { return } recordsCount, err = bin.ReadVarSize(r) if err != nil { return } level.CompletedIndexPage.Records, err = bin.ReadN(r, recordsCount*indexRecordSize) if err != nil { return } // indexPagesCount, err = bin.ReadVarSize(r) if err != nil { return } for range indexPagesCount { var p SealedIndexPage p.PageNo, err = bin.ReadUint32(r) if err != nil { return } p.Reused, err = bin.ReadBool(r) if err != nil { return } p.Checksum, err = bin.ReadUint32(r) if err != nil { return } size, err = bin.ReadVarSize(r) if err != nil { return } p.Content, err = bin.ReadN(r, size) if err != nil { return } level.IndexPages = append(level.IndexPages, p) } recordsCount, err = bin.ReadVarSize(r) if err != nil { return } level.TailRecords, err = bin.ReadN(r, recordsCount*indexRecordSize) if err != nil { return } s.ChangedIndexLevels = append(s.ChangedIndexLevels, level) } return }