package freelist import ( "fmt" "sync" "github.com/RoaringBitmap/roaring/v2" ) type FreeList struct { mutex sync.Mutex free *roaring.Bitmap reserved *roaring.Bitmap } func New() *FreeList { return &FreeList{ free: roaring.New(), reserved: roaring.New(), } } func (s *FreeList) Restore(serialized []byte) error { err := s.free.UnmarshalBinary(serialized) if err != nil { return fmt.Errorf("UnmarshalBinary: %s", err) } return nil } func (s *FreeList) AddPages(pageNumbers []uint32) { if len(pageNumbers) == 0 { return } s.mutex.Lock() s.free.AddMany(pageNumbers) s.mutex.Unlock() } // ReserveDataPage - аллокатор резервирует страницу, но не удаляет до визова // DeleteFromFree, ибо транзакция может не завершится, а между віделением страници // и падением транзакции - будет создан init файл. func (s *FreeList) ReservePage() (pageNo uint32) { s.mutex.Lock() defer s.mutex.Unlock() if s.free.IsEmpty() { return } pageNo = s.free.Minimum() s.free.Remove(pageNo) s.reserved.Add(pageNo) return } // Удаляет ранее зарезервированные страницы func (s *FreeList) DeletePages(pageNumbers []uint32) { s.mutex.Lock() for _, pageNo := range pageNumbers { s.reserved.Remove(pageNo) s.free.Remove(pageNo) // прокрута TransactionLog } s.mutex.Unlock() } func (s *FreeList) Serialize() ([]byte, error) { s.mutex.Lock() defer s.mutex.Unlock() tmp := roaring.Or(s.free, s.reserved) tmp.RunOptimize() return tmp.ToBytes() }