73 lines
1.6 KiB
Go
73 lines
1.6 KiB
Go
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()
|
||
}
|