mirror of https://github.com/etcd-io/bbolt.git
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.pull/34/head
parent
9ffb29787a
commit
2321036228
|
@ -2,6 +2,7 @@ package bolt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"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.
|
// Ensure that accessing and updating nested buckets is ok across transactions.
|
||||||
func TestBucket_Nested(t *testing.T) {
|
func TestBucket_Nested(t *testing.T) {
|
||||||
withOpenDB(func(db *DB, path string) {
|
withOpenDB(func(db *DB, path string) {
|
||||||
|
|
1
node.go
1
node.go
|
@ -486,7 +486,6 @@ func (n *node) rebalance() {
|
||||||
target.inodes = append(target.inodes, n.inodes...)
|
target.inodes = append(target.inodes, n.inodes...)
|
||||||
n.parent.del(n.key)
|
n.parent.del(n.key)
|
||||||
n.parent.removeChild(n)
|
n.parent.removeChild(n)
|
||||||
n.parent.put(target.key, target.inodes[0].key, nil, target.pgid, 0)
|
|
||||||
delete(n.bucket.nodes, n.pgid)
|
delete(n.bucket.nodes, n.pgid)
|
||||||
n.free()
|
n.free()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue