package atree import ( "fmt" bin "gordenko.dev/dima/bin/little" "gordenko.dev/dima/qb" "gordenko.dev/dima/qb/storage" "gordenko.dev/dima/qb/util" ) 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 } return buf, 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, storage.DataPageSize) } return result.Data, result.Err } 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), ) } } } // 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, storage.DataPageSize) off := int(pageNo-1) * storage.DataPageSize n, err := s.file.ReadAt(buf, int64(off)) if n != storage.DataPageSize { err = fmt.Errorf("read %d instead of %d", n, storage.DataPageSize) } 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{ PageNo: pageNo, Buf: buf, ReferenceCount: len(resultChannels), } s.mutex.Unlock() for _, resultCh := range resultChannels { resultCh <- readResult{ Data: buf, } } } } } // WRITE func (s *Atree) verifyCRC(data []byte, pageSize int) error { var ( pos = pageSize - 4 calculatedCRC = util.CalculateCRC32(data[:pos]) storedCRC, _ = bin.GetUint32(data[pos:]) ) if calculatedCRC != storedCRC { return fmt.Errorf("calculatedCRC %d not equal storedCRC %d", calculatedCRC, storedCRC) } return nil }