From adf7ebab5b295070adb3c866058c218f53d07d42 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Fri, 16 Feb 2024 22:49:53 +0300 Subject: [PATCH] [#996] metabase: Speed up bucket creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most of the time it exits, e.g. when it is per-container and use on each object PUT. Bbolt implementation first tries to create bucket and then returns it if it exists. Create operation uses cursor and thus is not very lightweight, we can avoid it. ``` goos: linux goarch: amd64 pkg: git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase cpu: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz │ old │ new │ │ sec/op │ sec/op vs base │ Put/parallel-8 174.4µ ± 3% 163.3µ ± 3% -6.39% (p=0.000 n=10) Put/sequential-8 263.3µ ± 2% 259.0µ ± 1% -1.64% (p=0.000 n=10) geomean 214.3µ 205.6µ -4.05% │ old │ new │ │ B/op │ B/op vs base │ Put/parallel-8 275.3Ki ± 3% 281.1Ki ± 4% ~ (p=0.063 n=10) Put/sequential-8 413.0Ki ± 2% 426.6Ki ± 2% +3.29% (p=0.003 n=10) geomean 337.2Ki 346.3Ki +2.70% │ old │ new │ │ allocs/op │ allocs/op vs base │ Put/parallel-8 678.0 ± 1% 524.5 ± 2% -22.64% (p=0.000 n=10) Put/sequential-8 1.329k ± 0% 1.183k ± 0% -10.91% (p=0.000 n=10) geomean 949.1 787.9 -16.98% ``` Signed-off-by: Evgenii Stratonikov --- pkg/local_object_storage/metabase/counter.go | 4 ++-- pkg/local_object_storage/metabase/put.go | 23 +++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/pkg/local_object_storage/metabase/counter.go b/pkg/local_object_storage/metabase/counter.go index 915fbd95..ee1ab41d 100644 --- a/pkg/local_object_storage/metabase/counter.go +++ b/pkg/local_object_storage/metabase/counter.go @@ -346,7 +346,7 @@ func (db *DB) incContainerObjectCounter(tx *bbolt.Tx, cnrID cid.ID, isUserObject // Does nothing if counters are not empty and force is false. If force is // true, updates the counters anyway. func syncCounter(tx *bbolt.Tx, force bool) error { - shardInfoB, err := tx.CreateBucketIfNotExists(shardInfoBucket) + shardInfoB, err := createBucketLikelyExists(tx, shardInfoBucket) if err != nil { return fmt.Errorf("could not get shard info bucket: %w", err) } @@ -359,7 +359,7 @@ func syncCounter(tx *bbolt.Tx, force bool) error { return nil } - containerCounterB, err := tx.CreateBucketIfNotExists(containerCounterBucketName) + containerCounterB, err := createBucketLikelyExists(tx, containerCounterBucketName) if err != nil { return fmt.Errorf("could not get container counter bucket: %w", err) } diff --git a/pkg/local_object_storage/metabase/put.go b/pkg/local_object_storage/metabase/put.go index 1f002238..5d8e4d26 100644 --- a/pkg/local_object_storage/metabase/put.go +++ b/pkg/local_object_storage/metabase/put.go @@ -356,8 +356,21 @@ func updateFKBTIndexes(tx *bbolt.Tx, obj *objectSDK.Object, f updateIndexItemFun return nil } +type bucketContainer interface { + Bucket([]byte) *bbolt.Bucket + CreateBucket([]byte) (*bbolt.Bucket, error) + CreateBucketIfNotExists([]byte) (*bbolt.Bucket, error) +} + +func createBucketLikelyExists[T bucketContainer](tx T, name []byte) (*bbolt.Bucket, error) { + if bkt := tx.Bucket(name); bkt != nil { + return bkt, nil + } + return tx.CreateBucket(name) +} + func putUniqueIndexItem(tx *bbolt.Tx, item namedBucketItem) error { - bkt, err := tx.CreateBucketIfNotExists(item.name) + bkt, err := createBucketLikelyExists(tx, item.name) if err != nil { return fmt.Errorf("can't create index %v: %w", item.name, err) } @@ -366,12 +379,12 @@ func putUniqueIndexItem(tx *bbolt.Tx, item namedBucketItem) error { } func putFKBTIndexItem(tx *bbolt.Tx, item namedBucketItem) error { - bkt, err := tx.CreateBucketIfNotExists(item.name) + bkt, err := createBucketLikelyExists(tx, item.name) if err != nil { return fmt.Errorf("can't create index %v: %w", item.name, err) } - fkbtRoot, err := bkt.CreateBucketIfNotExists(item.key) + fkbtRoot, err := createBucketLikelyExists(bkt, item.key) if err != nil { return fmt.Errorf("can't create fake bucket tree index %v: %w", item.key, err) } @@ -380,7 +393,7 @@ func putFKBTIndexItem(tx *bbolt.Tx, item namedBucketItem) error { } func putListIndexItem(tx *bbolt.Tx, item namedBucketItem) error { - bkt, err := tx.CreateBucketIfNotExists(item.name) + bkt, err := createBucketLikelyExists(tx, item.name) if err != nil { return fmt.Errorf("can't create index %v: %w", item.name, err) } @@ -474,7 +487,7 @@ func getVarUint(data []byte) (uint64, int, error) { // storage location to another. func updateStorageID(tx *bbolt.Tx, addr oid.Address, id []byte) error { key := make([]byte, bucketKeySize) - bkt, err := tx.CreateBucketIfNotExists(smallBucketName(addr.Container(), key)) + bkt, err := createBucketLikelyExists(tx, smallBucketName(addr.Container(), key)) if err != nil { return err }