Files
qb/atree/io.go

378 lines
8.1 KiB
Go
Raw Normal View History

2026-02-10 14:02:11 +00:00
package atree
import (
"errors"
"fmt"
"io/fs"
"math"
"os"
2026-06-10 06:18:45 +03:00
bin "gordenko.dev/dima/bin/little"
2026-02-23 11:02:29 +00:00
"gordenko.dev/dima/qb"
2026-05-21 23:38:52 +03:00
"gordenko.dev/dima/qb/util"
2026-02-10 14:02:11 +00:00
)
2026-02-23 19:37:05 +00:00
// fix - додати ID, щоб потім перемістити із тимчасового буфера в pages, або звільнити
2026-05-31 20:01:28 +00:00
// type AllocatedPage struct {
// PageNo uint32
// Data []byte
// IsReused bool
// }
2026-02-10 14:02:11 +00:00
type readResult struct {
Data []byte
Err error
}
// INDEX PAGES
2026-02-23 19:37:05 +00:00
func (s *Atree) DeletePages(pageNumbers []uint32) {
2026-02-10 14:02:11 +00:00
s.mutex.Lock()
for _, pageNo := range pageNumbers {
2026-02-23 19:37:05 +00:00
delete(s.pages, pageNo)
2026-02-10 14:02:11 +00:00
}
s.mutex.Unlock()
}
func (s *Atree) fetchIndexPage(pageNo uint32) ([]byte, error) {
2026-06-10 06:18:45 +03:00
// 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
2026-02-23 19:37:05 +00:00
}
func (s *Atree) fetchDataPage(pageNo uint32) ([]byte, error) {
2026-06-10 06:18:45 +03:00
// 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
2026-02-23 19:37:05 +00:00
}
2026-05-10 00:59:47 +00:00
func (s *Atree) fetchPage(pageNo uint32) ([]byte, error) {
2026-06-10 06:18:45 +03:00
// 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
2026-02-10 14:02:11 +00:00
}
2026-02-23 19:37:05 +00:00
func (s *Atree) releasePage(pageNo uint32) {
2026-02-10 14:02:11 +00:00
s.mutex.Lock()
defer s.mutex.Unlock()
2026-02-23 19:37:05 +00:00
p, ok := s.pages[pageNo]
2026-02-10 14:02:11 +00:00
if ok {
if p.ReferenceCount > 0 {
p.ReferenceCount--
return
} else {
2026-02-23 11:02:29 +00:00
qb.Abort(
qb.ReferenceCountBug,
2026-02-23 19:37:05 +00:00
fmt.Errorf("call releasePage on page %d with reference count = %d",
2026-02-10 14:02:11 +00:00
pageNo, p.ReferenceCount),
)
}
}
}
2026-05-10 00:59:47 +00:00
func (s *Atree) allocPageNumber() (uint32, bool) {
// fix
return 0, true
}
2026-05-31 20:01:28 +00:00
// 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
// }
2026-02-10 14:02:11 +00:00
2026-02-23 19:37:05 +00:00
// // 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
// }
2026-02-10 14:02:11 +00:00
2026-02-23 19:37:05 +00:00
// DATA PAGES
2026-02-10 14:02:11 +00:00
// READ
func (s *Atree) pageReader() {
for {
select {
case <-s.readSignalCh:
s.readPages()
}
}
}
func (s *Atree) readPages() {
2026-06-10 06:18:45 +03:00
// 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,
// }
// }
// }
// }
2026-02-10 14:02:11 +00:00
}
// WRITE
2026-05-10 00:59:47 +00:00
// func (s *Atree) pageWriter() {
// for {
// select {
// case <-s.writeSignalCh:
// err := s.writeTasks()
// if err != nil {
// qb.Abort(qb.WriteToAtreeFailed, err)
// }
// }
// }
// }
2026-02-10 14:02:11 +00:00
2026-05-10 00:59:47 +00:00
// type WriteTask struct {
// WaitCh chan struct{}
// Pages []PageToWrite
// }
2026-02-10 14:02:11 +00:00
2026-05-10 00:59:47 +00:00
// func (s *Atree) appendWriteTaskToQueue(task WriteTask) {
// s.mutex.Lock()
// s.writeTasksQueue = append(s.writeTasksQueue, task)
// s.mutex.Unlock()
2026-02-10 14:02:11 +00:00
2026-05-10 00:59:47 +00:00
// select {
// case s.writeSignalCh <- struct{}{}:
// default:
// }
// }
2026-02-10 14:02:11 +00:00
2026-05-10 00:59:47 +00:00
// func (s *Atree) writeTasks() error {
// s.mutex.Lock()
// tasks := s.writeTasksQueue
// s.writeTasksQueue = nil
// s.mutex.Unlock()
2026-02-10 14:02:11 +00:00
2026-05-10 00:59:47 +00:00
// 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
// }
2026-02-10 14:02:11 +00:00
// 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
}
2026-05-10 00:59:47 +00:00
// func (s *Atree) ApplyREDO(task WriteTask) {
// s.appendWriteTaskToQueue(task)
// }
2026-02-10 14:02:11 +00:00
func (s *Atree) verifyCRC(data []byte, pageSize int) error {
var (
pos = pageSize - 4
2026-05-21 23:38:52 +03:00
calculatedCRC = util.CalcChecksum(data[:pos])
2026-06-10 06:18:45 +03:00
storedCRC, _ = bin.GetUint32(data[pos:])
2026-02-10 14:02:11 +00:00
)
if calculatedCRC != storedCRC {
return fmt.Errorf("calculatedCRC %d not equal storedCRC %d",
calculatedCRC, storedCRC)
}
return nil
}