2020-11-27 17:49:24 +00:00
|
|
|
package meta
|
|
|
|
|
|
|
|
import (
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"go.etcd.io/bbolt"
|
|
|
|
)
|
|
|
|
|
2020-12-08 09:56:14 +00:00
|
|
|
// 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 {
|
2020-11-27 17:49:24 +00:00
|
|
|
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
|
|
|
|
})
|
|
|
|
})
|
2020-12-08 09:56:14 +00:00
|
|
|
|
|
|
|
return
|
2020-11-27 17:49:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|