diff options
author | Ben Johnson <benbjohnson@yahoo.com> | 2014-06-13 16:02:47 -0600 |
---|---|---|
committer | Ben Johnson <benbjohnson@yahoo.com> | 2014-06-13 16:02:47 -0600 |
commit | 0329b03f58799ab8e51e7567f836c80c24258a16 (patch) | |
tree | fda84a12d1bca54725f40eb901a0b914a126f159 /freelist.go | |
parent | Merge pull request #194 from benbjohnson/fix-deadlock (diff) | |
parent | Fix freelist rollback. (diff) | |
download | dedo-0329b03f58799ab8e51e7567f836c80c24258a16.tar.gz dedo-0329b03f58799ab8e51e7567f836c80c24258a16.tar.xz |
Merge pull request #193 from benbjohnson/check-freelist-overflow
Check for freelist overflow
Diffstat (limited to 'freelist.go')
-rw-r--r-- | freelist.go | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/freelist.go b/freelist.go index a236079..e27f80a 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 { @@ -106,6 +113,11 @@ func (f *freelist) release(txid txid) { sort.Sort(pgids(f.ids)) } +// rollback removes the pages from a given pending tx. +func (f *freelist) rollback(txid txid) { + delete(f.pending, txid) +} + // isFree returns whether a given page is in the free list. func (f *freelist) isFree(pgid pgid) bool { for _, id := range f.ids { @@ -134,9 +146,36 @@ 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) >= 65565 { + 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 +} + +// reload reads the freelist from a page and filters out pending items. +func (f *freelist) reload(p *page) { + f.read(p) + + // Filter out pending free pages. + ids := f.ids + f.ids = nil + + var a []pgid + for _, id := range ids { + if !f.isFree(id) { + a = append(a, id) + } + } + f.ids = a } |