aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Johnson <benbjohnson@yahoo.com>2016-03-25 08:58:56 -0600
committerBen Johnson <benbjohnson@yahoo.com>2016-03-25 10:53:30 -0600
commit2b4a0e28943f2dc71b7697cb86764b05e9919637 (patch)
treeda55ceb25e0642f44187e1ce5350054b570431be
parentMerge pull request #542 from boltdb/remove-drone-badge (diff)
downloaddedo-2b4a0e28943f2dc71b7697cb86764b05e9919637.tar.gz
dedo-2b4a0e28943f2dc71b7697cb86764b05e9919637.tar.xz
set slice capacity
This commit sets the capacity on slices returned from `Bucket.Get()` to match the slice length. Previously the capacity would be the size of the mmap max size. This does not cause any backwards compatibility issues, however, it does allow users to `append()` to the returned slice since that will cause Go to realloc a new slice on the heap. Fixes #544
-rw-r--r--bucket_test.go40
-rw-r--r--page.go4
2 files changed, 42 insertions, 2 deletions
diff --git a/bucket_test.go b/bucket_test.go
index a02c367..528fec2 100644
--- a/bucket_test.go
+++ b/bucket_test.go
@@ -80,6 +80,46 @@ func TestBucket_Get_IncompatibleValue(t *testing.T) {
}
}
+// Ensure that a slice returned from a bucket has a capacity equal to its length.
+// This also allows slices to be appended to since it will require a realloc by Go.
+//
+// https://github.com/boltdb/bolt/issues/544
+func TestBucket_Get_Capacity(t *testing.T) {
+ db := MustOpenDB()
+ defer db.MustClose()
+
+ // Write key to a bucket.
+ if err := db.Update(func(tx *bolt.Tx) error {
+ b, err := tx.CreateBucket([]byte("bucket"))
+ if err != nil {
+ return err
+ }
+ return b.Put([]byte("key"), []byte("val"))
+ }); err != nil {
+ t.Fatal(err)
+ }
+
+ // Retrieve value and attempt to append to it.
+ if err := db.Update(func(tx *bolt.Tx) error {
+ k, v := tx.Bucket([]byte("bucket")).Cursor().First()
+
+ // Verify capacity.
+ if len(k) != cap(k) {
+ t.Fatalf("unexpected key slice capacity: %d", cap(k))
+ } else if len(v) != cap(v) {
+ t.Fatalf("unexpected value slice capacity: %d", cap(v))
+ }
+
+ // Ensure slice can be appended to without a segfault.
+ k = append(k, []byte("123")...)
+ v = append(v, []byte("123")...)
+
+ return nil
+ }); err != nil {
+ t.Fatal(err)
+ }
+}
+
// Ensure that a bucket can write a key/value.
func TestBucket_Put(t *testing.T) {
db := MustOpenDB()
diff --git a/page.go b/page.go
index 818aa1b..4a55528 100644
--- a/page.go
+++ b/page.go
@@ -111,13 +111,13 @@ type leafPageElement struct {
// key returns a byte slice of the node key.
func (n *leafPageElement) key() []byte {
buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
- return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos]))[:n.ksize]
+ return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos]))[:n.ksize:n.ksize]
}
// value returns a byte slice of the node value.
func (n *leafPageElement) value() []byte {
buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
- return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos+n.ksize]))[:n.vsize]
+ return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos+n.ksize]))[:n.vsize:n.vsize]
}
// PageInfo represents human readable information about a page.