From af4db8a73ba569a71bcff87b4ce472b436b5fb69 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Tue, 14 Jun 2022 18:53:09 +0300 Subject: [PATCH] [#1516] metabase: Cache address key and do not decode address twice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``` name old time/op new time/op delta ListWithCursor/1_item-8 10.6µs ± 1% 6.4µs ±13% -39.62% (p=0.000 n=7+10) ListWithCursor/10_items-8 75.3µs ± 2% 30.9µs ±21% -58.97% (p=0.000 n=10+10) ListWithCursor/100_items-8 726µs ± 2% 274µs ±27% -62.28% (p=0.000 n=10+10) name old alloc/op new alloc/op delta ListWithCursor/1_item-8 3.19kB ± 0% 2.26kB ± 0% -29.21% (p=0.000 n=10+10) ListWithCursor/10_items-8 20.7kB ± 0% 10.8kB ± 0% -47.68% (p=0.000 n=10+8) ListWithCursor/100_items-8 196kB ± 0% 97kB ± 0% -50.65% (p=0.000 n=7+10) name old allocs/op new allocs/op delta ListWithCursor/1_item-8 55.0 ± 0% 39.0 ± 0% -29.09% (p=0.000 n=10+10) ListWithCursor/10_items-8 346 ± 0% 192 ± 0% -44.51% (p=0.000 n=10+10) ListWithCursor/100_items-8 3.25k ± 0% 1.72k ± 0% -47.13% (p=0.000 n=9+10) ``` Signed-off-by: Evgenii Stratonikov --- pkg/local_object_storage/metabase/exists.go | 9 ++++- pkg/local_object_storage/metabase/list.go | 42 +++++++++++++-------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/pkg/local_object_storage/metabase/exists.go b/pkg/local_object_storage/metabase/exists.go index 4a27d875..5d6b7466 100644 --- a/pkg/local_object_storage/metabase/exists.go +++ b/pkg/local_object_storage/metabase/exists.go @@ -105,6 +105,11 @@ func (db *DB) exists(tx *bbolt.Tx, addr oid.Address) (exists bool, err error) { // * 1 if object with GC mark; // * 2 if object is covered with tombstone. func inGraveyard(tx *bbolt.Tx, addr oid.Address) uint8 { + addrKey := addressKey(addr) + return inGraveyardWithKey(tx, addrKey) +} + +func inGraveyardWithKey(tx *bbolt.Tx, addrKey []byte) uint8 { graveyard := tx.Bucket(graveyardBucketName) if graveyard == nil { // incorrect metabase state, does not make @@ -112,7 +117,7 @@ func inGraveyard(tx *bbolt.Tx, addr oid.Address) uint8 { return 0 } - val := graveyard.Get(addressKey(addr)) + val := graveyard.Get(addrKey) if val == nil { garbageBCK := tx.Bucket(garbageBucketName) if garbageBCK == nil { @@ -120,7 +125,7 @@ func inGraveyard(tx *bbolt.Tx, addr oid.Address) uint8 { return 0 } - val = garbageBCK.Get(addressKey(addr)) + val = garbageBCK.Get(addrKey) if val != nil { // object has been marked with GC return 1 diff --git a/pkg/local_object_storage/metabase/list.go b/pkg/local_object_storage/metabase/list.go index becbaee9..3344f86b 100644 --- a/pkg/local_object_storage/metabase/list.go +++ b/pkg/local_object_storage/metabase/list.go @@ -80,17 +80,18 @@ func ListWithCursor(db *DB, count uint32, cursor *Cursor) ([]oid.Address, *Curso // Returns ErrEndOfListing if there are no more objects to return or count // parameter set to zero. func (db *DB) ListWithCursor(prm ListPrm) (res ListRes, err error) { + result := make([]oid.Address, 0, prm.count) + err = db.boltDB.View(func(tx *bbolt.Tx) error { - res.addrList, res.cursor, err = db.listWithCursor(tx, prm.count, prm.cursor) + res.addrList, res.cursor, err = db.listWithCursor(tx, result, prm.count, prm.cursor) return err }) return res, err } -func (db *DB) listWithCursor(tx *bbolt.Tx, count int, cursor *Cursor) ([]oid.Address, *Cursor, error) { +func (db *DB) listWithCursor(tx *bbolt.Tx, result []oid.Address, count int, cursor *Cursor) ([]oid.Address, *Cursor, error) { threshold := cursor == nil // threshold is a flag to ignore cursor - result := make([]oid.Address, 0, count) var bucketName []byte c := tx.Cursor() @@ -100,10 +101,12 @@ func (db *DB) listWithCursor(tx *bbolt.Tx, count int, cursor *Cursor) ([]oid.Add name, _ = c.Seek(cursor.bucketName) } + var containerID cid.ID + loop: for ; name != nil; name, _ = c.Next() { - containerID, postfix := parseContainerIDWithPostfix(name) - if containerID == nil { + postfix, ok := parseContainerIDWithPostfix(&containerID, name) + if !ok { continue } @@ -118,8 +121,7 @@ loop: } prefix := containerID.EncodeToString() + "/" - - result, cursor = selectNFromBucket(tx, name, prefix, result, count, cursor, threshold) + result, cursor = selectNFromBucket(tx, name, prefix, containerID, result, count, cursor, threshold) bucketName = name if len(result) >= count { break loop @@ -146,7 +148,8 @@ loop: // object to start selecting from. Ignores inhumed objects. func selectNFromBucket(tx *bbolt.Tx, name []byte, // bucket name - prefix string, // string of container ID, optimization + prefix string, // container ID prefix, optimization + cnt cid.ID, // container ID to []oid.Address, // listing result limit int, // stop listing at `limit` items in result cursor *Cursor, // start from cursor object @@ -172,18 +175,28 @@ func selectNFromBucket(tx *bbolt.Tx, k, _ = c.Next() // we are looking for objects _after_ the cursor } + addrRaw := make([]byte, len(prefix)+44) + copy(addrRaw, prefix) + for ; k != nil; k, _ = c.Next() { if count >= limit { break } - var a oid.Address - if err := a.DecodeString(prefix + string(k)); err != nil { + + var obj oid.ID + if err := obj.DecodeString(string(k)); err != nil { break } + offset = k - if inGraveyard(tx, a) > 0 { + addrRaw = append(addrRaw[:len(prefix)], k...) + if inGraveyardWithKey(tx, addrRaw) > 0 { continue } + + var a oid.Address + a.SetContainer(cnt) + a.SetObject(obj) to = append(to, a) count++ } @@ -196,9 +209,8 @@ func selectNFromBucket(tx *bbolt.Tx, return to, cursor } -func parseContainerIDWithPostfix(name []byte) (*cid.ID, string) { +func parseContainerIDWithPostfix(containerID *cid.ID, name []byte) (string, bool) { var ( - containerID cid.ID containerIDStr = string(name) postfix string ) @@ -210,8 +222,8 @@ func parseContainerIDWithPostfix(name []byte) (*cid.ID, string) { } if err := containerID.DecodeString(containerIDStr); err != nil { - return nil, "" + return "", false } - return &containerID, postfix + return postfix, true }