Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clone key in DeleteBucket and CreateBucketIfNotExists #660

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 19 additions & 17 deletions bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,29 +202,29 @@ func (b *Bucket) CreateBucket(key []byte) (rb *Bucket, err error) {
// Returns an error if the bucket name is blank, or if the bucket name is too long.
// The bucket instance is only valid for the lifetime of the transaction.
func (b *Bucket) CreateBucketIfNotExists(key []byte) (rb *Bucket, err error) {
// Insert into node.
// Tip: Use a new variable `newKey` instead of reusing the existing `key` to prevent
// it from being marked as leaking, and accordingly cannot be allocated on stack.
newKey := cloneBytes(key)

lg := b.tx.db.Logger()
lg.Debugf("Creating bucket if not exist %q", string(key))
lg.Debugf("Creating bucket if not exist %q", string(newKey))
defer func() {
if err != nil {
lg.Errorf("Creating bucket if not exist %q failed: %v", string(key), err)
lg.Errorf("Creating bucket if not exist %q failed: %v", string(newKey), err)
} else {
lg.Debugf("Creating bucket if not exist %q successfully", string(key))
lg.Debugf("Creating bucket if not exist %q successfully", string(newKey))
}
}()

if b.tx.db == nil {
return nil, errors.ErrTxClosed
} else if !b.tx.writable {
return nil, errors.ErrTxNotWritable
} else if len(key) == 0 {
} else if len(newKey) == 0 {
return nil, errors.ErrBucketNameRequired
}

// Insert into node.
// Tip: Use a new variable `newKey` instead of reusing the existing `key` to prevent
// it from being marked as leaking, and accordingly cannot be allocated on stack.
newKey := cloneBytes(key)

if b.buckets != nil {
if child := b.buckets[string(newKey)]; child != nil {
return child, nil
Expand Down Expand Up @@ -269,13 +269,15 @@ func (b *Bucket) CreateBucketIfNotExists(key []byte) (rb *Bucket, err error) {
// DeleteBucket deletes a bucket at the given key.
// Returns an error if the bucket does not exist, or if the key represents a non-bucket value.
func (b *Bucket) DeleteBucket(key []byte) (err error) {
newKey := cloneBytes(key)

lg := b.tx.db.Logger()
lg.Debugf("Deleting bucket %q", string(key))
lg.Debugf("Deleting bucket %q", string(newKey))
defer func() {
if err != nil {
lg.Errorf("Deleting bucket %q failed: %v", string(key), err)
lg.Errorf("Deleting bucket %q failed: %v", string(newKey), err)
} else {
lg.Debugf("Deleting bucket %q successfully", string(key))
lg.Debugf("Deleting bucket %q successfully", string(newKey))
}
}()

Expand All @@ -287,17 +289,17 @@ func (b *Bucket) DeleteBucket(key []byte) (err error) {

// Move cursor to correct position.
c := b.Cursor()
k, _, flags := c.seek(key)
k, _, flags := c.seek(newKey)

// Return an error if bucket doesn't exist or is not a bucket.
if !bytes.Equal(key, k) {
if !bytes.Equal(newKey, k) {
return errors.ErrBucketNotFound
} else if (flags & common.BucketLeafFlag) == 0 {
return errors.ErrIncompatibleValue
}

// Recursively delete all child buckets.
child := b.Bucket(key)
child := b.Bucket(newKey)
err = child.ForEachBucket(func(k []byte) error {
if err := child.DeleteBucket(k); err != nil {
return fmt.Errorf("delete bucket: %s", err)
Expand All @@ -309,15 +311,15 @@ func (b *Bucket) DeleteBucket(key []byte) (err error) {
}

// Remove cached copy.
delete(b.buckets, string(key))
delete(b.buckets, string(newKey))

// Release all bucket pages to freelist.
child.nodes = nil
child.rootNode = nil
child.free()

// Delete the node if we have a matching key.
c.node().del(key)
c.node().del(newKey)

return nil
}
Expand Down
Loading