updates from gary

This commit is contained in:
Ömer Faruk IRMAK 2025-07-28 09:12:55 +03:00
parent 3d40a60beb
commit ff5beb274b
2 changed files with 35 additions and 17 deletions

View file

@ -16,37 +16,55 @@
package common package common
import "fmt"
// Arena is an allocation primitive that allows individual allocations // Arena is an allocation primitive that allows individual allocations
// out of a page of items and bulk de-allocations of last N allocations. // out of a page of items and bulk de-allocations of last N allocations.
// The most common way of using an Arena is to pair it up with a sync.Pool // The most common way of using an Arena is to pair it up with a sync.Pool
// of pages. // of pages.
//
// Notably, arena is not thread safe, please manage the concurrency issues
// by yourselves.
type Arena[T any] struct { type Arena[T any] struct {
used uint32 used uint32
pages [][]T pages [][]T
pageSize uint32
PageSize uint32 newPage func() any
NewPage func() any releasePage func(any)
ReleasePage func(any)
} }
// Alloc returns the next free item on the arena // NewArena constructs the arena for the given type.
// Allocates a new page if needed func NewArena[T any](pageSize uint32, newPage func() any, releasePage func(any)) *Arena[T] {
return &Arena[T]{
pageSize: pageSize,
newPage: newPage,
releasePage: releasePage,
}
}
// Alloc returns the next free item on the arena.
func (a *Arena[T]) Alloc() *T { func (a *Arena[T]) Alloc() *T {
pageIndex := a.used / a.PageSize pageIndex := a.used / a.pageSize
pageOffset := a.used % a.PageSize pageOffset := a.used % a.pageSize
if pageOffset == 0 {
a.pages = append(a.pages, a.NewPage().([]T)) // Allocate additional items if all pre-allocated ones have been exhausted
if pageOffset == 0 && int(pageIndex) == len(a.pages) {
items := a.newPage().([]T)
if len(items) != int(a.pageSize) {
panic(fmt.Errorf("invalid page size, want: %d, got: %d", a.pageSize, len(items)))
}
a.pages = append(a.pages, items)
} }
a.used++ a.used++
return &a.pages[pageIndex][pageOffset] return &a.pages[pageIndex][pageOffset]
} }
// Used returns the number of items that live on this arena // Used returns the number of items that live on this arena.
func (a *Arena[T]) Used() uint32 { func (a *Arena[T]) Used() uint32 {
return a.used return a.used
} }
// Reset rollsback the active set of live elements to the given number // Reset rollbacks the active set of live elements to the given number.
func (a *Arena[T]) Reset(to uint32) { func (a *Arena[T]) Reset(to uint32) {
a.used = to a.used = to
} }
@ -54,7 +72,7 @@ func (a *Arena[T]) Reset(to uint32) {
// Release releases all the pages that the arena currently owns // Release releases all the pages that the arena currently owns
func (a *Arena[T]) Release() { func (a *Arena[T]) Release() {
for _, page := range a.pages { for _, page := range a.pages {
a.ReleasePage(page) a.releasePage(page)
} }
a.pages = nil a.pages = nil
a.used = 0 a.used = 0

View file

@ -90,8 +90,8 @@ func NewStackTrie(onTrieNode OnTrieNode) *StackTrie {
onTrieNode: onTrieNode, onTrieNode: onTrieNode,
kBuf: make([]byte, 64), kBuf: make([]byte, 64),
pBuf: make([]byte, 64), pBuf: make([]byte, 64),
nodeAllocator: common.Arena[stNode]{NewPage: stPagePool.Get, PageSize: uint32(stPageSize), ReleasePage: stPagePool.Put}, nodeAllocator: *common.NewArena[stNode](uint32(stPageSize), stPagePool.Get, stPagePool.Put),
byteAllocator: common.Arena[[32]byte]{NewPage: bytePagePool.Get, PageSize: uint32(stPageSize), ReleasePage: bytePagePool.Put}, byteAllocator: *common.NewArena[[32]byte](uint32(stPageSize), bytePagePool.Get, bytePagePool.Put),
} }
t.root = t.nodeAllocator.Alloc().reset() t.root = t.nodeAllocator.Alloc().reset()
t.tmpNode = t.nodeAllocator.Alloc().reset() t.tmpNode = t.nodeAllocator.Alloc().reset()