mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-07 17:15:56 +00:00
improve the sync.Pool used for pages, avoid excess page allocations for WAL
Several changes. One is, we don't provide a `New` for pagePool, which allows allocPage to check whether a page was returned, and thus, zero pages which were found in the pool, or make new pages, but never zero pages it just created with make. We then also make many more things which were making pages use the pool. Reuse the same page allocation for multiple header pages dumped into the WAL; the bitmap header pages aren't stashed in our page map, they're only written to the disk, so we don't need to make a new page each time, we can just make one new page for the whole batch. Internally in the pool, we pool pointers to [PageSize]byte, rather than slices. sync.Pool needs pointer-like things. To store a pointer to a slice, you have to heap-allocate the slice, also. So, instead of heap-allocating copies of these slices, we just use pointers to the raw data.
This commit is contained in:
parent
49972939ec
commit
adcd5adb02
3 changed files with 30 additions and 18 deletions
|
|
@ -526,7 +526,7 @@ func (c *Cursor) putLeafCellFast(in leafCell, isInsert bool) (err error) {
|
|||
}
|
||||
|
||||
// Write page header.
|
||||
dst := allocPage() // make([]byte, PageSize)
|
||||
dst := allocPage()
|
||||
writePageNo(dst, readPageNo(src))
|
||||
writeFlags(dst, PageTypeLeaf)
|
||||
writeCellN(dst, dstCellN)
|
||||
|
|
@ -616,7 +616,7 @@ func (c *Cursor) deleteLeafCell(key uint64) (err error) {
|
|||
cells = cells[:len(cells)-1]
|
||||
|
||||
// Write cells to page.
|
||||
buf := make([]byte, PageSize)
|
||||
buf := allocPage()
|
||||
writePageNo(buf[:], elem.pgno)
|
||||
writeFlags(buf[:], PageTypeLeaf)
|
||||
writeCellN(buf[:], len(cells))
|
||||
|
|
@ -800,7 +800,7 @@ func (c *Cursor) deleteBranchCell(stackIndex int, key uint64) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
buf := make([]byte, PageSize)
|
||||
buf := allocPage()
|
||||
copy(buf, target)
|
||||
writePageNo(buf[:], elem.pgno)
|
||||
|
||||
|
|
|
|||
29
rbf/db.go
29
rbf/db.go
|
|
@ -11,6 +11,7 @@ import (
|
|||
"sort"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/benbjohnson/immutable"
|
||||
"github.com/molecula/featurebase/v2/logger"
|
||||
|
|
@ -560,7 +561,7 @@ func (db *DB) init() error {
|
|||
// initMetaPage initializes the meta page.
|
||||
func (db *DB) initMetaPage() error {
|
||||
|
||||
page := make([]byte, PageSize)
|
||||
page := allocPage()
|
||||
writeMetaMagic(page)
|
||||
writeMetaPageN(page, 3)
|
||||
writeMetaRootRecordPageNo(page, 1)
|
||||
|
|
@ -572,7 +573,7 @@ func (db *DB) initMetaPage() error {
|
|||
// initRootRecordPage initializes the initial root record page.
|
||||
func (db *DB) initRootRecordPage() error {
|
||||
|
||||
page := make([]byte, PageSize)
|
||||
page := allocPage()
|
||||
writePageNo(page, 1)
|
||||
writeFlags(page, PageTypeRootRecord)
|
||||
_, err := db.file.WriteAt(page, 1*PageSize)
|
||||
|
|
@ -582,7 +583,7 @@ func (db *DB) initRootRecordPage() error {
|
|||
// initFreelistPage initializes the initial freelist btree page.
|
||||
func (db *DB) initFreelistPage() error {
|
||||
|
||||
page := make([]byte, PageSize)
|
||||
page := allocPage()
|
||||
writePageNo(page, 2)
|
||||
writeFlags(page, PageTypeLeaf)
|
||||
_, err := db.file.WriteAt(page, 2*PageSize)
|
||||
|
|
@ -829,18 +830,22 @@ type DebugInfo struct {
|
|||
|
||||
// Shared pool for in-memory database pages.
|
||||
// These are used before being flushed to disk.
|
||||
var pagePool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
page := make([]byte, PageSize)
|
||||
return &page
|
||||
},
|
||||
}
|
||||
var pagePool = &sync.Pool{}
|
||||
|
||||
func allocPage() []byte {
|
||||
page := pagePool.Get().(*[]byte)
|
||||
return *page
|
||||
existing := pagePool.Get()
|
||||
if existing == nil {
|
||||
return make([]byte, PageSize)
|
||||
}
|
||||
// zero the existing page before returning it
|
||||
page := existing.(*[PageSize]byte)[:]
|
||||
for i := range page {
|
||||
page[i] = 0
|
||||
}
|
||||
return page
|
||||
}
|
||||
|
||||
func freePage(page []byte) {
|
||||
pagePool.Put(&page)
|
||||
data := (*[PageSize]byte)(unsafe.Pointer(&page[0]))
|
||||
pagePool.Put(data)
|
||||
}
|
||||
|
|
|
|||
13
rbf/tx.go
13
rbf/tx.go
|
|
@ -236,7 +236,7 @@ func (tx *Tx) createBitmap(name string) error {
|
|||
}
|
||||
|
||||
// Write root page.
|
||||
page := make([]byte, PageSize)
|
||||
page := allocPage()
|
||||
writePageNo(page, pgno)
|
||||
writeFlags(page, PageTypeLeaf)
|
||||
writeCellN(page, 0)
|
||||
|
|
@ -449,7 +449,7 @@ func (tx *Tx) writeRootRecordPages(records *immutable.SortedMap) (err error) {
|
|||
// Write new root record pages.
|
||||
for itr := records.Iterator(); !itr.Done(); {
|
||||
// Initialize page & write as many records as will fit.
|
||||
page := make([]byte, PageSize)
|
||||
page := allocPage()
|
||||
writePageNo(page, pgno)
|
||||
writeFlags(page, PageTypeRootRecord)
|
||||
|
||||
|
|
@ -1800,9 +1800,16 @@ func (tx *Tx) flush() error {
|
|||
}
|
||||
|
||||
// Write bitmap headers & pages to WAL.
|
||||
//
|
||||
// We need to write a bitmap header before each such page. We only allocate
|
||||
// one header, and we reuse it, because each write is flushing it out to
|
||||
// disk, and it doesn't get stored in-memory.
|
||||
var hdr []byte
|
||||
if len(tx.dirtyBitmapPages) > 0 {
|
||||
hdr = allocPage()
|
||||
}
|
||||
for _, pgno := range dirtyPageMapKeys(tx.dirtyBitmapPages) {
|
||||
// Write header page.
|
||||
hdr := make([]byte, PageSize)
|
||||
writePageNo(hdr[:], pgno)
|
||||
writeFlags(hdr[:], PageTypeBitmapHeader)
|
||||
if _, err := tx.writeToWAL(w, hdr); err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue