diff --git a/rbf/cursor.go b/rbf/cursor.go index 2419bc5f8..22d4427e6 100644 --- a/rbf/cursor.go +++ b/rbf/cursor.go @@ -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) diff --git a/rbf/db.go b/rbf/db.go index 97de950e6..1d693fac6 100644 --- a/rbf/db.go +++ b/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) } diff --git a/rbf/tx.go b/rbf/tx.go index aef2b395c..b2a1a5185 100644 --- a/rbf/tx.go +++ b/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 {