From f448639ce4a632980eef6394f75aca12b89b6d1c Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Fri, 13 Jun 2014 07:56:10 -0600 Subject: [PATCH] Check for freelist overflow. --- freelist.go | 19 ++++++++++++++++++- tx.go | 4 +++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/freelist.go b/freelist.go index a236079..407dc79 100644 --- a/freelist.go +++ b/freelist.go @@ -1,11 +1,18 @@ package bolt import ( + "errors" "fmt" "sort" "unsafe" ) +var ( + // ErrFreelistOverflow is returned when the total number of free pages + // exceeds 65,536 and the freelist cannot hold any more. + ErrFreelistOverflow = errors.New("freelist overflow") +) + // freelist represents a list of all pages that are available for allocation. // It also tracks pages that have been freed but are still in use by open transactions. type freelist struct { @@ -134,9 +141,19 @@ func (f *freelist) read(p *page) { // write writes the page ids onto a freelist page. All free and pending ids are // saved to disk since in the event of a program crash, all pending ids will // become free. -func (f *freelist) write(p *page) { +func (f *freelist) write(p *page) error { + // Combine the old free pgids and pgids waiting on an open transaction. ids := f.all() + + // Make sure that the sum of all free pages is less than the max uint16 size. + if len(ids) > (1 << 16) { + return ErrFreelistOverflow + } + + // Update the header and write the ids to the page. p.flags |= freelistPageFlag p.count = uint16(len(ids)) copy(((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[:], ids) + + return nil } diff --git a/tx.go b/tx.go index a9781f2..211085a 100644 --- a/tx.go +++ b/tx.go @@ -173,7 +173,9 @@ func (tx *Tx) Commit() error { tx.close() return err } - tx.db.freelist.write(p) + if err := tx.db.freelist.write(p); err != nil { + return err + } tx.meta.freelist = p.id // Write dirty pages to disk.