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) +}