frostfs-node/pkg/local_object_storage/metabase/cleanup.go
Alex Vanin 41578001e4 [#337] metabase: Keep container size estimation
Storage nodes keep container size estimation so they
can announce this info and hope for some basic income
settlements. This is also useful for monitoring.

Container size does not include non regular or inhumed
object sizes.

Signed-off-by: Alex Vanin <alexey@nspcc.ru>
2021-01-29 11:04:30 +03:00

108 lines
2.1 KiB
Go

package meta
import (
"bytes"
"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) {
switch { // clean well-known global metabase buckets
case bytes.Equal(name, containerVolumeBucketName):
_ = b.ForEach(func(k, v []byte) error {
if parseContainerSize(v) == 0 {
_ = b.Delete(k)
}
return nil
})
default:
// do nothing
}
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)
}