From 74d44beb9980377c8a4cc5a0bfdb5b053de7251e Mon Sep 17 00:00:00 2001 From: Alex Vanin Date: Fri, 27 Nov 2020 20:49:24 +0300 Subject: [PATCH] [#199] Add CleanUp method to remove empty buckets from metabase Signed-off-by: Alex Vanin --- .../metabase/v2/cleanup.go | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 pkg/local_object_storage/metabase/v2/cleanup.go diff --git a/pkg/local_object_storage/metabase/v2/cleanup.go b/pkg/local_object_storage/metabase/v2/cleanup.go new file mode 100644 index 000000000..9272e90ad --- /dev/null +++ b/pkg/local_object_storage/metabase/v2/cleanup.go @@ -0,0 +1,85 @@ +package meta + +import ( + "strings" + + "go.etcd.io/bbolt" +) + +func (db *DB) CleanUp() error { + return 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 + }) + }) +} + +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) +}