168 lines
3.2 KiB
Go
168 lines
3.2 KiB
Go
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
|
|
}
|