package atree import ( "errors" "fmt" "io/fs" "math" "os" bin "gordenko.dev/dima/bin/little" "gordenko.dev/dima/qb" "gordenko.dev/dima/qb/util" ) // fix - додати ID, щоб потім перемістити із тимчасового буфера в pages, або звільнити // type AllocatedPage struct { // PageNo uint32 // Data []byte // IsReused bool // } type readResult struct { Data []byte Err error } // INDEX PAGES func (s *Atree) DeletePages(pageNumbers []uint32) { s.mutex.Lock() for _, pageNo := range pageNumbers { delete(s.pages, pageNo) } s.mutex.Unlock() } func (s *Atree) fetchIndexPage(pageNo uint32) ([]byte, error) { // buf, err := s.fetchPage(pageNo) // if err != nil { // return nil, err // } // if buf[pageTypeIdx] != PageTypeIndex { // return nil, fmt.Errorf("wrong pageType %d instead of %d", buf[pageTypeIdx], PageTypeIndex) // } // return buf, nil return nil, nil } func (s *Atree) fetchDataPage(pageNo uint32) ([]byte, error) { // buf, err := s.fetchPage(pageNo) // if err != nil { // return nil, err // } // if buf[pageTypeIdx] != PageTypeIndex { // return nil, fmt.Errorf("wrong pageType %d instead of %d", buf[pageTypeIdx], PageTypeIndex) // } // return buf, nil return nil, nil } func (s *Atree) fetchPage(pageNo uint32) ([]byte, error) { // s.mutex.Lock() // p, ok := s.pages[pageNo] // if ok { // p.ReferenceCount++ // s.mutex.Unlock() // return p.Buf, nil // } // resultCh := make(chan readResult, 1) // s.pageWaits[pageNo] = append(s.pageWaits[pageNo], resultCh) // if len(s.pageWaits[pageNo]) == 1 { // s.pagesToRead = append(s.pagesToRead, pageNo) // s.mutex.Unlock() // select { // case s.readSignalCh <- struct{}{}: // default: // } // } else { // s.mutex.Unlock() // } // result := <-resultCh // if result.Err == nil { // result.Err = s.verifyCRC(result.Data, PageSize) // } // return result.Data, result.Err return nil, nil } func (s *Atree) releasePage(pageNo uint32) { s.mutex.Lock() defer s.mutex.Unlock() p, ok := s.pages[pageNo] if ok { if p.ReferenceCount > 0 { p.ReferenceCount-- return } else { qb.Abort( qb.ReferenceCountBug, fmt.Errorf("call releasePage on page %d with reference count = %d", pageNo, p.ReferenceCount), ) } } } func (s *Atree) allocPageNumber() (uint32, bool) { // fix return 0, true } // func (s *Atree) allocPage() AllocatedPage { // var ( // allocated = AllocatedPage{ // Data: make([]byte, PageSize), // } // ) // //allocated.PageNo = s.freelist.ReservePage() // s.mutex.Lock() // // if allocated.PageNo > 0 { // // allocated.IsReused = true // // } else { // // if s.allocatedPagesQty == math.MaxUint32 { // // qb.Abort(qb.MaxAtreeSizeExceeded, errors.New("no space in Atree index")) // // } // // s.allocatedPagesQty++ // // allocated.PageNo = s.allocatedPagesQty // // } // // s.pages[allocated.PageNo] = &_page{ // // // fix pageType // // PageNo: allocated.PageNo, // // Buf: allocated.Data, // // ReferenceCount: 1, // // } // s.mutex.Unlock() // return allocated // } // // fix - без freelist // func (s *Atree) allocIndexPage() AllocatedPage { // var ( // allocated = AllocatedPage{ // Data: make([]byte, PageSize), // } // ) // allocated.PageNo = s.freelist.ReservePage() // s.mutex.Lock() // if allocated.PageNo > 0 { // allocated.IsReused = true // } else { // if s.allocatedPagesQty == math.MaxUint32 { // qb.Abort(qb.MaxAtreeSizeExceeded, errors.New("no space in Atree index")) // } // s.allocatedPagesQty++ // allocated.PageNo = s.allocatedPagesQty // } // s.pages[allocated.PageNo] = &_page{ // // fix pageType // PageNo: allocated.PageNo, // Buf: allocated.Data, // ReferenceCount: 1, // } // s.mutex.Unlock() // return allocated // } // func (s *Atree) allocDataPage() AllocatedPage { // var ( // allocated = AllocatedPage{ // Data: make([]byte, PageSize), // } // ) // allocated.PageNo = s.freelist.ReservePage() // s.mutex.Lock() // if allocated.PageNo > 0 { // allocated.IsReused = true // } else { // if s.allocatedPagesQty == math.MaxUint32 { // qb.Abort(qb.MaxAtreeSizeExceeded, errors.New("no space in Atree index")) // } // s.allocatedPagesQty++ // allocated.PageNo = s.allocatedPagesQty // } // s.pages[allocated.PageNo] = &_page{ // // fix pageType // PageNo: allocated.PageNo, // Buf: allocated.Data, // ReferenceCount: 1, // } // s.mutex.Unlock() // return allocated // } // DATA PAGES // READ func (s *Atree) pageReader() { for { select { case <-s.readSignalCh: s.readPages() } } } func (s *Atree) readPages() { // s.mutex.Lock() // if len(s.pagesToRead) == 0 { // s.mutex.Unlock() // return // } // pagesToRead := s.pagesToRead // s.pagesToRead = nil // s.mutex.Unlock() // for _, pageNo := range pagesToRead { // buf := make([]byte, PageSize) // off := (pageNo - 1) * PageSize // n, err := s.file.ReadAt(buf, int64(off)) // if n != PageSize { // err = fmt.Errorf("read %d instead of %d", n, PageSize) // } // s.mutex.Lock() // resultChannels := s.pageWaits[pageNo] // delete(s.pageWaits, pageNo) // if err != nil { // s.mutex.Unlock() // for _, resultCh := range resultChannels { // resultCh <- readResult{ // Err: err, // } // } // } else { // s.pages[pageNo] = &_page{ // // fix - page type // PageNo: pageNo, // Buf: buf, // ReferenceCount: len(resultChannels), // } // s.mutex.Unlock() // for _, resultCh := range resultChannels { // resultCh <- readResult{ // Data: buf, // } // } // } // } } // WRITE // func (s *Atree) pageWriter() { // for { // select { // case <-s.writeSignalCh: // err := s.writeTasks() // if err != nil { // qb.Abort(qb.WriteToAtreeFailed, err) // } // } // } // } // type WriteTask struct { // WaitCh chan struct{} // Pages []PageToWrite // } // func (s *Atree) appendWriteTaskToQueue(task WriteTask) { // s.mutex.Lock() // s.writeTasksQueue = append(s.writeTasksQueue, task) // s.mutex.Unlock() // select { // case s.writeSignalCh <- struct{}{}: // default: // } // } // func (s *Atree) writeTasks() error { // s.mutex.Lock() // tasks := s.writeTasksQueue // s.writeTasksQueue = nil // s.mutex.Unlock() // for _, task := range tasks { // for _, p := range task.Pages { // if len(p.Data) != PageSize { // return fmt.Errorf("wrong page %d size: %d", // p.PageNo, len(p.Data)) // } // bin.PutUint32(p.Data[crc32Idx:], calcChecksum(p.Data[:crc32Idx])) // off := (p.PageNo - 1) * PageSize // n, err := s.file.WriteAt(p.Data, int64(off)) // if err != nil { // return err // } // if n != len(p.Data) { // return fmt.Errorf("write %d instead of %d", n, len(p.Data)) // } // } // close(task.WaitCh) // } // return nil // } // IO func isFileExist(fileName string) (bool, error) { _, err := os.Stat(fileName) if err != nil { if errors.Is(err, fs.ErrNotExist) { return false, nil } else { return false, err } } else { return true, nil } } func openFile(fileName string, pageSize int) (_ *os.File, _ uint32, err error) { file, err := os.OpenFile(fileName, os.O_RDWR, filePerm) if err != nil { return } fi, err := file.Stat() if err != nil { return } fileSize := fi.Size() if (fileSize % int64(pageSize)) > 0 { err = fmt.Errorf("the file size %d is not a multiple of the page size %d", fileSize, pageSize) return } allocatedPagesQty := fileSize / int64(pageSize) if allocatedPagesQty > math.MaxUint32 { err = fmt.Errorf("allocated pages %d is > max pages %d", allocatedPagesQty, math.MaxUint32) return } return file, uint32(allocatedPagesQty), nil } // func (s *Atree) ApplyREDO(task WriteTask) { // s.appendWriteTaskToQueue(task) // } func (s *Atree) verifyCRC(data []byte, pageSize int) error { var ( pos = pageSize - 4 calculatedCRC = util.CalcChecksum(data[:pos]) storedCRC, _ = bin.GetUint32(data[pos:]) ) if calculatedCRC != storedCRC { return fmt.Errorf("calculatedCRC %d not equal storedCRC %d", calculatedCRC, storedCRC) } return nil }