frostfs-node/pkg/local_object_storage/metabase/cleanup.go

95 lines
1.8 KiB
Go
Raw Normal View History

package meta
import (
"strings"
"go.etcd.io/bbolt"
)
// CleanUpPrm groups the parameters of CleanUp operation.
type CleanUpPrm struct{}
// CleanUpRes groups resulting values of CleanUp operation.
type CleanUpRes struct{}
// CleanUp removes empty buckets from metabase.
func (db *DB) CleanUp(prm *CleanUpPrm) (res *CleanUpRes, err error) {
err = db.boltDB.Update(func(tx *bbolt.Tx) error {
return tx.ForEach(func(name []byte, b *bbolt.Bucket) error {
switch {
case isFKBTBucket(name):
cleanUpFKBT(tx, name, b)
case isListBucket(name):
cleanUpListBucket(tx, name, b)
default:
cleanUpUniqueBucket(tx, name, b)
}
return nil
})
})
return
}
func isFKBTBucket(name []byte) bool {
bucketName := string(name)
switch {
case
strings.Contains(bucketName, userAttributePostfix),
strings.Contains(bucketName, ownerPostfix):
return true
default:
return false
}
}
func isListBucket(name []byte) bool {
bucketName := string(name)
switch {
case
strings.Contains(bucketName, payloadHashPostfix),
strings.Contains(bucketName, parentPostfix):
return true
default:
return false
}
}
func cleanUpUniqueBucket(tx *bbolt.Tx, name []byte, b *bbolt.Bucket) {
if b.Stats().KeyN == 0 {
_ = tx.DeleteBucket(name) // ignore error, best effort there
}
}
func cleanUpFKBT(tx *bbolt.Tx, name []byte, b *bbolt.Bucket) {
removedBuckets := 0
remainingBuckets := b.Stats().BucketN - 1
_ = b.ForEach(func(k, _ []byte) error {
fkbtRoot := b.Bucket(k)
if fkbtRoot == nil {
return nil
}
if fkbtRoot.Stats().KeyN == 0 {
err := b.DeleteBucket(k)
if err == nil {
removedBuckets++
}
}
return nil
})
if remainingBuckets == removedBuckets {
_ = tx.DeleteBucket(name) // ignore error, best effort there
}
}
func cleanUpListBucket(tx *bbolt.Tx, name []byte, b *bbolt.Bucket) {
cleanUpUniqueBucket(tx, name, b)
}