41578001e4
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>
108 lines
2.1 KiB
Go
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)
|
|
}
|