package atree import ( "errors" "fmt" "gordenko.dev/dima/qb" ) type BackwardCursor struct { metricType qb.MetricType fracDigits byte atree *Atree pageNo uint32 pageData []byte timestampDecompressor qb.TimestampDecompressor valueDecompressor qb.ValueDecompressor } type BackwardCursorOptions struct { MetricType qb.MetricType FracDigits byte PageNo uint32 PageData []byte Atree *Atree } func NewBackwardCursor(opt BackwardCursorOptions) (*BackwardCursor, error) { switch opt.MetricType { case qb.Instant, qb.Cumulative: // ok default: return nil, fmt.Errorf("MetricType option has wrong value: %d", opt.MetricType) } if opt.FracDigits > qb.MaxFracDigits { return nil, errors.New("FracDigits option is required") } if opt.Atree == nil { return nil, errors.New("Atree option is required") } if opt.PageNo == 0 { return nil, errors.New("PageNo option is required") } if len(opt.PageData) == 0 { return nil, errors.New("PageData option is required") } s := &BackwardCursor{ metricType: opt.MetricType, fracDigits: opt.FracDigits, atree: opt.Atree, pageNo: opt.PageNo, pageData: opt.PageData, } err := s.makeDecompressors() if err != nil { return nil, err } return s, nil } // timestamp, value, done, error func (s *BackwardCursor) Prev() (uint32, float64, bool, error) { var ( timestamp uint32 value float64 //done bool //err error ) // timestamp, done = s.timestampDecompressor.NextValue() // if !done { // value, done = s.valueDecompressor.NextValue() // if done { // return 0, 0, false, // fmt.Errorf("corrupted data page %d: has timestamp, no value", // s.pageNo) // } // return timestamp, value, false, nil // } // prevPageNo, _ := bin.GetUint32(s.pageData[prevPageIdx:]) // if prevPageNo == 0 { // return 0, 0, true, nil // } // s.atree.releasePage(s.pageNo) // s.pageNo = prevPageNo // s.pageData, err = s.atree.fetchDataPage(s.pageNo) // if err != nil { // return 0, 0, false, fmt.Errorf("atree.fetchDataPage(%d): %s", s.pageNo, err) // } // err = s.makeDecompressors() // if err != nil { // return 0, 0, false, err // } // timestamp, done = s.timestampDecompressor.NextValue() // if done { // return 0, 0, false, // fmt.Errorf("corrupted data page %d: no timestamps", // s.pageNo) // } // value, done = s.valueDecompressor.NextValue() // if done { // return 0, 0, false, // fmt.Errorf("corrupted data page %d: no values", // s.pageNo) // } return timestamp, value, false, nil } func (s *BackwardCursor) Close() { s.atree.releasePage(s.pageNo) } // HELPER func (s *BackwardCursor) makeDecompressors() error { // timestampsSize, _ := bin.GetUint16(s.pageData[timestampsSizeIdx:]) // valuesSize, _ := bin.GetUint16(s.pageData[valuesSizeIdx:]) // payloadSize := timestampsSize + valuesSize // if payloadSize > dataFooterIdx { // return fmt.Errorf("corrupted data page %d: timestamps + values size %d gt payload size", // s.pageNo, payloadSize) // } // s.timestampDecompressor = enc.NewTimeDeltaDecompressor( // s.pageData[:timestampsSize], // ) // vbuf := s.pageData[timestampsSize : timestampsSize+valuesSize] // switch s.metricType { // case qb.Instant: // s.valueDecompressor = enc.NewInstantDeltaDecompressor( // vbuf, s.fracDigits) // case qb.Cumulative: // s.valueDecompressor = enc.NewCumulativeDeltaDecompressor( // vbuf, s.fracDigits) // default: // return fmt.Errorf("bug: wrong metricType %d", s.metricType) // } return nil } func makeDecompressors(pageData []byte, metricType qb.MetricType, fracDigits byte) ( qb.TimestampDecompressor, qb.ValueDecompressor, error, ) { // timestampsSize, _ := bin.GetUint16(pageData[timestampsSizeIdx:]) // valuesSize, _ := bin.GetUint16(pageData[valuesSizeIdx:]) // payloadSize := timestampsSize + valuesSize // if payloadSize > dataFooterIdx { // return nil, nil, fmt.Errorf("corrupted: timestamps + values size %d > payload size", // payloadSize) // } // timestampDecompressor := enc.NewTimeDeltaDecompressor( // pageData[:timestampsSize], // ) // vbuf := pageData[timestampsSize : timestampsSize+valuesSize] // var valueDecompressor qb.ValueDecompressor // switch metricType { // case qb.Instant: // valueDecompressor = enc.NewInstantDeltaDecompressor( // vbuf, fracDigits) // case qb.Cumulative: // valueDecompressor = enc.NewCumulativeDeltaDecompressor( // vbuf, fracDigits) // default: // return nil, nil, fmt.Errorf("bug: wrong metricType %d", metricType) // } //return timestampDecompressor, valueDecompressor, nil return nil, nil, nil }