package atree import ( "errors" "hash" "hash/crc32" ) type Writer struct { metricID uint32 timestamp uint32 value float64 tmp []byte hasher hash.Hash32 isDataPageReused bool dataPageNo uint32 isRootChanged bool newRootPageNo uint32 indexPages []uint32 reusedIndexPages []uint32 indexPagesToWrite []PageToWrite } type WriterOptions struct { MetricID uint32 Value float64 Timestamp uint32 IsDataPageReused bool DataPageNo uint32 Page []byte } // dataPage можно записати 1 раз. Щоб не заплутувати інтерфейс - передаю data сторінку // через Options. Index сторінок може бути від 1 до N, тому виділяю окремий метод func NewWriter(opt WriterOptions) (*Writer, error) { if opt.MetricID == 0 { return nil, errors.New("MetricID option is required") } if opt.DataPageNo == 0 { return nil, errors.New("DataPageNo option is required") } // if len(opt.Page) != octopus.DataPageSize { // return nil, fmt.Errorf("bug: wrong data page size %d", len(opt.Page)) // } s := &Writer{ metricID: opt.MetricID, timestamp: opt.Timestamp, value: opt.Value, tmp: make([]byte, 21), isDataPageReused: opt.IsDataPageReused, dataPageNo: opt.DataPageNo, hasher: crc32.NewIEEE(), } // var err error // err = s.init(opt.Page) // if err != nil { // return nil, err // } return s, nil } /* Формат: 4b metricID 8b value 4b timestamp 1b flags (reused) 4b dataPageNo 8KB dataPage */ // func (s *Writer) init(dataPage []byte) error { // bin.PutUint32(s.tmp[0:], s.metricID) // bin.PutUint32(s.tmp[4:], s.timestamp) // bin.PutFloat64(s.tmp[8:], s.value) // if s.isDataPageReused { // s.tmp[16] = 1 // } // bin.PutUint32(s.tmp[17:], s.dataPageNo) // _, err := s.file.Write(s.tmp) // if err != nil { // return err // } // _, err = s.file.Write(dataPage) // if err != nil { // return err // } // s.hasher.Write(s.tmp) // s.hasher.Write(dataPage) // return nil // } /* Формат 1b index page flags 4b indexPageNo Nb indexPage */ // func (s *Writer) AppendIndexPage(indexPageNo uint32, indexPage []byte, flags byte) error { // s.tmp[0] = flags // bin.PutUint32(s.tmp[1:], indexPageNo) // // _, err := s.file.Write(s.tmp[:5]) // // if err != nil { // // return err // // } // // _, err = s.file.Write(indexPage) // // if err != nil { // // return err // // } // s.hasher.Write(s.tmp[:5]) // s.hasher.Write(indexPage) // s.indexPages = append(s.indexPages, indexPageNo) // if (flags & FlagReused) == FlagReused { // s.reusedIndexPages = append(s.reusedIndexPages, indexPageNo) // } // if (flags & FlagNewRoot) == FlagNewRoot { // s.newRootPageNo = indexPageNo // s.isRootChanged = true // } // s.indexPagesToWrite = append(s.indexPagesToWrite, // PageToWrite{ // PageNo: indexPageNo, // Data: indexPage, // }) // return nil // } // func (s *Writer) IndexPagesToWrite() []PageToWrite { // return s.indexPagesToWrite // } // func (s *Writer) Close() (err error) { // // финализирую запись // bin.PutUint32(s.tmp, s.hasher.Sum32()) // _, err = s.file.Write(s.tmp[:4]) // if err != nil { // return err // } // err = s.file.Sync() // if err != nil { // return // } // return s.file.Close() // } // func (s *Writer) GetReport() Report { // return Report{ // IsDataPageReused: s.isDataPageReused, // DataPageNo: s.dataPageNo, // //IndexPages: s.indexPages, // IsRootChanged: s.isRootChanged, // NewRootPageNo: s.newRootPageNo, // ReusedIndexPages: s.reusedIndexPages, // } // }