diff --git a/lnode.go b/lnode.go index f7b1c81..f84a412 100644 --- a/lnode.go +++ b/lnode.go @@ -16,10 +16,12 @@ type lnode struct { // key returns a byte slice of the node key. func (n *lnode) key() []byte { - return (*[MaxKeySize]byte)(unsafe.Pointer(&n))[n.pos : n.pos+n.ksize] + buf := (*[maxAllocSize]byte)(unsafe.Pointer(n)) + return buf[n.pos:n.pos+n.ksize] } // value returns a byte slice of the node value. func (n *lnode) value() []byte { - return (*[MaxKeySize]byte)(unsafe.Pointer(&n))[n.pos+n.ksize : n.pos+n.ksize+n.vsize] + buf := (*[maxAllocSize]byte)(unsafe.Pointer(n)) + return buf[n.pos+n.ksize:n.pos+n.ksize+n.vsize] } diff --git a/page.go b/page.go index 09d4062..dbfff64 100644 --- a/page.go +++ b/page.go @@ -6,7 +6,7 @@ import ( const pageHeaderSize = int(unsafe.Offsetof(((*page)(nil)).ptr)) -const maxPageAllocSize = 0xFFFFFFF +const maxAllocSize = 0xFFFFFFF const minKeysPerPage = 2 const maxNodesPerPage = 65535 diff --git a/tpage.go b/tpage.go index c4dc83f..3701789 100644 --- a/tpage.go +++ b/tpage.go @@ -33,10 +33,11 @@ func (p *tpage) put(key []byte, value []byte) { // read initializes the node data from an on-disk page. func (p *tpage) read(page *page) { - p.nodes = make(tnodes, page.count) + ncount := int(page.count) + p.nodes = make(tnodes, ncount) lnodes := (*[maxNodesPerPage]lnode)(unsafe.Pointer(&page.ptr)) - for i := 0; i < int(page.count); i++ { - lnode := lnodes[i] + for i := 0; i < ncount; i++ { + lnode := &lnodes[i] n := &p.nodes[i] n.key = lnode.key() n.value = lnode.value() @@ -64,7 +65,7 @@ func (p *tpage) write(pageSize int, allocate allocator) ([]*page, error) { // Loop over each node and write it to the page. lnodes := (*[maxNodesPerPage]lnode)(unsafe.Pointer(&page.ptr)) - b := (*[maxPageAllocSize]byte)(unsafe.Pointer(&page.ptr))[lnodeSize*len(nodes):] + b := (*[maxAllocSize]byte)(unsafe.Pointer(&page.ptr))[lnodeSize*len(nodes):] for index, node := range nodes { // Write node. lnode := &lnodes[index] diff --git a/tpage_test.go b/tpage_test.go index d14ebdb..5ca6d63 100644 --- a/tpage_test.go +++ b/tpage_test.go @@ -2,6 +2,7 @@ package bolt import ( "testing" + "unsafe" "github.com/stretchr/testify/assert" ) @@ -21,7 +22,31 @@ func TestTpagePut(t *testing.T) { // Ensure that a temporary page can deserialize from a page. func TestTpageRead(t *testing.T) { - t.Skip("pending") + // Create a page. + var buf [4096]byte + page := (*page)(unsafe.Pointer(&buf[0])) + page.count = 2 + + // Insert 2 leaf nodes at the beginning. sizeof(lnode) == 16 + nodes := (*[3]lnode)(unsafe.Pointer(&page.ptr)) + nodes[0] = lnode{flags: 0, pos: 32, ksize: 3, vsize: 4} // pos = sizeof(lnode) * 2 + nodes[1] = lnode{flags: 0, pos: 23, ksize: 10, vsize: 3} // pos = sizeof(lnode) + 3 + 4 + + // Write data for the nodes at the end. + data := (*[4096]byte)(unsafe.Pointer(&nodes[2])) + copy(data[:], []byte("barfooz")) + copy(data[7:], []byte("helloworldbye")) + + // Deserialize page into a temporary page. + p := &tpage{} + p.read(page) + + // Check that there are two nodes with correct data. + assert.Equal(t, len(p.nodes), 2) + assert.Equal(t, p.nodes[0].key, []byte("bar")) + assert.Equal(t, p.nodes[0].value, []byte("fooz")) + assert.Equal(t, p.nodes[1].key, []byte("helloworld")) + assert.Equal(t, p.nodes[1].value, []byte("bye")) } // Ensure that a temporary page can serialize itself.