Skip to content

Commit

Permalink
Try to use reflect.SliceHeader correctly this time
Browse files Browse the repository at this point in the history
  • Loading branch information
jrick committed May 21, 2020
1 parent 81f2578 commit 9034717
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 13 deletions.
21 changes: 15 additions & 6 deletions freelist.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,18 +267,23 @@ func (f *freelist) read(p *page) {
}
// If the page.count is at the max uint16 value (64k) then it's considered
// an overflow and the size of the freelist is stored as the first element.
var idx, count uintptr = 0, uintptr(p.count)
var idx, count = 0, int(p.count)
if count == 0xFFFF {
idx = 1
count = uintptr(*(*pgid)(unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))))
c := *(*pgid)(unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)))
count = int(c)
if count < 0 {
panic(fmt.Sprintf("leading element count %d overflows int", c))
}
}

// Copy the list of page ids from the freelist.
if count == 0 {
f.ids = nil
} else {
ids := (*[maxAllocSize]pgid)(unsafeAdd(
unsafe.Pointer(p), unsafe.Sizeof(*p)))[idx : idx+count : idx+count]
var ids []pgid
data := unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p), unsafe.Sizeof(ids[0]), idx)
unsafeSlice(unsafe.Pointer(&ids), data, count)

// copy the ids, so we don't modify on the freelist page directly
idsCopy := make([]pgid, count)
Expand Down Expand Up @@ -316,11 +321,15 @@ func (f *freelist) write(p *page) error {
p.count = uint16(l)
} else if l < 0xFFFF {
p.count = uint16(l)
ids := (*[maxAllocSize]pgid)(unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)))[:l:l]
var ids []pgid
data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
unsafeSlice(unsafe.Pointer(&ids), data, l)
f.copyall(ids)
} else {
p.count = 0xFFFF
ids := (*[maxAllocSize]pgid)(unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)))[: l+1 : l+1]
var ids []pgid
data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
unsafeSlice(unsafe.Pointer(&ids), data, l+1)
ids[0] = pgid(l)
f.copyall(ids[1:])
}
Expand Down
14 changes: 8 additions & 6 deletions page.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ func (p *page) leafPageElements() []leafPageElement {
if p.count == 0 {
return nil
}
const maxArraySize = maxAllocSize / unsafe.Sizeof(leafPageElement{})
return (*[maxArraySize]leafPageElement)(unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p),
unsafe.Sizeof(leafPageElement{}), 0))[:p.count:p.count]
var elems []leafPageElement
data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
unsafeSlice(unsafe.Pointer(&elems), data, int(p.count))
return elems
}

// branchPageElement retrieves the branch node by index
Expand All @@ -80,9 +81,10 @@ func (p *page) branchPageElements() []branchPageElement {
if p.count == 0 {
return nil
}
const maxArraySize = maxAllocSize / unsafe.Sizeof(branchPageElement{})
return (*[maxArraySize]branchPageElement)(unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p),
unsafe.Sizeof(branchPageElement{}), 0))[:p.count:p.count]
var elems []branchPageElement
data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
unsafeSlice(unsafe.Pointer(&elems), data, int(p.count))
return elems
}

// dump writes n bytes of the page to STDERR as hex output.
Expand Down
16 changes: 15 additions & 1 deletion unsafe.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package bbolt

import "unsafe"
import (
"reflect"
"unsafe"
)

func unsafeAdd(base unsafe.Pointer, offset uintptr) unsafe.Pointer {
return unsafe.Pointer(uintptr(base) + offset)
Expand All @@ -23,3 +26,14 @@ func unsafeByteSlice(base unsafe.Pointer, offset uintptr, i, j int) []byte {
// all), so this is believed to be correct.
return (*[maxAllocSize]byte)(unsafeAdd(base, offset))[i:j:j]
}

// unsafeSlice modifies the data, len, and cap of a slice variable pointed to by
// the slice parameter. This helper should be used over other direct
// manipulation of reflect.SliceHeader to prevent misuse, namely, converting
// from reflect.SliceHeader to a Go slice type.
func unsafeSlice(slice, data unsafe.Pointer, len int) {
s := (*reflect.SliceHeader)(slice)
s.Data = uintptr(data)
s.Cap = len
s.Len = len
}

0 comments on commit 9034717

Please sign in to comment.