Fix double free in merge-left rebalance.

This commit fixes a bug where deletions that caused merge-left rebalances were updating
the parent node which caused a node to "reappear" even after it had been deleted. This was
fixed in merge-right rebalances a while ago but merge-left is less frequent so it was
missed until now.

Many thanks to Jordan Sherer (@jsherer) for finding and reporting the bug.
master
Ben Johnson 2014-06-06 17:14:17 -06:00
parent 9ffb29787a
commit 2321036228
2 changed files with 45 additions and 1 deletions

View File

@ -2,6 +2,7 @@ package bolt
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"math/rand"
@ -189,6 +190,50 @@ func TestBucket_Delete_Large(t *testing.T) {
})
}
// Ensure that deleting a large set of keys will work correctly.
// Reported by Jordan Sherer: https://github.com/boltdb/bolt/issues/184
func TestBucket_Delete_Large2(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}
withOpenDB(func(db *DB, path string) {
k := make([]byte, 16)
for i := uint64(0); i < 10000; i++ {
err := db.Update(func(tx *Tx) error {
b, err := tx.CreateBucketIfNotExists([]byte("0"))
if err != nil {
t.Fatalf("bucket error: %s", err)
}
for j := uint64(0); j < 1000; j++ {
binary.BigEndian.PutUint64(k[:8], i)
binary.BigEndian.PutUint64(k[8:], j)
if err := b.Put(k, nil); err != nil {
t.Fatalf("put error: %s", err)
}
}
return nil
})
if err != nil {
t.Fatalf("update error: %s", err)
}
}
// Delete all of them in one large transaction
db.Update(func(tx *Tx) error {
b := tx.Bucket([]byte("0"))
c := b.Cursor()
for k, _ := c.First(); k != nil; k, _ = c.Next() {
b.Delete(k)
}
return nil
})
})
}
// Ensure that accessing and updating nested buckets is ok across transactions.
func TestBucket_Nested(t *testing.T) {
withOpenDB(func(db *DB, path string) {

View File

@ -486,7 +486,6 @@ func (n *node) rebalance() {
target.inodes = append(target.inodes, n.inodes...)
n.parent.del(n.key)
n.parent.removeChild(n)
n.parent.put(target.key, target.inodes[0].key, nil, target.pgid, 0)
delete(n.bucket.nodes, n.pgid)
n.free()
}