From 0b1902460db40a50e7851b534b94bd5bff868dea Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Fri, 10 Feb 2023 07:59:15 +0300 Subject: [PATCH 1/3] [#31] fstree: Speedup string-to-address conversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``` name old time/op new time/op delta _addressFromString-8 1.25µs ±30% 1.02µs ± 6% -18.49% (p=0.000 n=9+9) name old alloc/op new alloc/op delta _addressFromString-8 352B ± 0% 256B ± 0% -27.27% (p=0.000 n=9+10) name old allocs/op new allocs/op delta _addressFromString-8 6.00 ± 0% 4.00 ± 0% -33.33% (p=0.000 n=10+10) ``` Also, assure compiler that `s` doesn't escape: Before this commit: ``` ./fstree.go:74:24: leaking param: s ./fstree.go:90:6: moved to heap: addr ``` After this commit: ``` ./fstree.go:74:24: s does not escape ``` Signed-off-by: Evgenii Stratonikov --- .../blobstor/fstree/fstree.go | 24 +++++++++---------- .../blobstor/fstree/fstree_test.go | 16 ++++++++++++- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/pkg/local_object_storage/blobstor/fstree/fstree.go b/pkg/local_object_storage/blobstor/fstree/fstree.go index 5d7094d44..d129bf98a 100644 --- a/pkg/local_object_storage/blobstor/fstree/fstree.go +++ b/pkg/local_object_storage/blobstor/fstree/fstree.go @@ -71,27 +71,27 @@ func stringifyAddress(addr oid.Address) string { return addr.Object().EncodeToString() + "." + addr.Container().EncodeToString() } -func addressFromString(s string) (*oid.Address, error) { - ss := strings.SplitN(s, ".", 2) - if len(ss) != 2 { - return nil, errors.New("invalid address") +func addressFromString(s string) (oid.Address, error) { + i := strings.IndexByte(s, '.') + if i == -1 { + return oid.Address{}, errors.New("invalid address") } var obj oid.ID - if err := obj.DecodeString(ss[0]); err != nil { - return nil, err + if err := obj.DecodeString(s[:i]); err != nil { + return oid.Address{}, err } var cnr cid.ID - if err := cnr.DecodeString(ss[1]); err != nil { - return nil, err + if err := cnr.DecodeString(s[i+1:]); err != nil { + return oid.Address{}, err } var addr oid.Address addr.SetObject(obj) addr.SetContainer(cnr) - return &addr, nil + return addr, nil } // Iterate iterates over all stored objects. @@ -135,7 +135,7 @@ func (t *FSTree) iterate(depth uint64, curPath []string, prm common.IteratePrm) } if prm.LazyHandler != nil { - err = prm.LazyHandler(*addr, func() ([]byte, error) { + err = prm.LazyHandler(addr, func() ([]byte, error) { return os.ReadFile(filepath.Join(curPath...)) }) } else { @@ -147,7 +147,7 @@ func (t *FSTree) iterate(depth uint64, curPath []string, prm common.IteratePrm) if err != nil { if prm.IgnoreErrors { if prm.ErrorHandler != nil { - return prm.ErrorHandler(*addr, err) + return prm.ErrorHandler(addr, err) } continue } @@ -155,7 +155,7 @@ func (t *FSTree) iterate(depth uint64, curPath []string, prm common.IteratePrm) } err = prm.Handler(common.IterationElement{ - Address: *addr, + Address: addr, ObjectData: data, StorageID: []byte{}, }) diff --git a/pkg/local_object_storage/blobstor/fstree/fstree_test.go b/pkg/local_object_storage/blobstor/fstree/fstree_test.go index 4bfcc0a95..97fd6032a 100644 --- a/pkg/local_object_storage/blobstor/fstree/fstree_test.go +++ b/pkg/local_object_storage/blobstor/fstree/fstree_test.go @@ -12,5 +12,19 @@ func TestAddressToString(t *testing.T) { s := stringifyAddress(addr) actual, err := addressFromString(s) require.NoError(t, err) - require.Equal(t, addr, *actual) + require.Equal(t, addr, actual) +} + +func Benchmark_addressFromString(b *testing.B) { + addr := oidtest.Address() + s := stringifyAddress(addr) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := addressFromString(s) + if err != nil { + b.Fatalf("benchmark error: %v", err) + } + } } -- 2.47.2 From b958aa8631424c3a62b2b44954634e0df6bc4add Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Wed, 25 Jan 2023 16:53:10 +0300 Subject: [PATCH 2/3] [#31] fstree: Do not check for a file existence twice Signed-off-by: Evgenii Stratonikov --- .../blobstor/fstree/fstree.go | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/pkg/local_object_storage/blobstor/fstree/fstree.go b/pkg/local_object_storage/blobstor/fstree/fstree.go index d129bf98a..14d1db341 100644 --- a/pkg/local_object_storage/blobstor/fstree/fstree.go +++ b/pkg/local_object_storage/blobstor/fstree/fstree.go @@ -191,15 +191,9 @@ func (t *FSTree) Delete(prm common.DeletePrm) (common.DeleteRes, error) { return common.DeleteRes{}, common.ErrReadOnly } - p, err := t.getPath(prm.Address) - if err != nil { - if os.IsNotExist(err) { - err = logicerr.Wrap(apistatus.ObjectNotFound{}) - } - return common.DeleteRes{}, err - } + p := t.treePath(prm.Address) - err = os.Remove(p) + err := os.Remove(p) if err != nil && os.IsNotExist(err) { err = logicerr.Wrap(apistatus.ObjectNotFound{}) } @@ -209,7 +203,9 @@ func (t *FSTree) Delete(prm common.DeletePrm) (common.DeleteRes, error) { // Exists returns the path to the file with object contents if it exists in the storage // and an error otherwise. func (t *FSTree) Exists(prm common.ExistsPrm) (common.ExistsRes, error) { - _, err := t.getPath(prm.Address) + p := t.treePath(prm.Address) + + _, err := os.Stat(p) found := err == nil if os.IsNotExist(err) { err = nil @@ -217,13 +213,6 @@ func (t *FSTree) Exists(prm common.ExistsPrm) (common.ExistsRes, error) { return common.ExistsRes{Exists: found}, err } -func (t *FSTree) getPath(addr oid.Address) (string, error) { - p := t.treePath(addr) - - _, err := os.Stat(p) - return p, err -} - // Put puts an object in the storage. func (t *FSTree) Put(prm common.PutPrm) (common.PutRes, error) { if t.readOnly { -- 2.47.2 From b23da3678671794e91e79a2ec77848bce3b878e6 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Wed, 25 Jan 2023 17:05:06 +0300 Subject: [PATCH 3/3] [#31] fstree: Optimize `treePath` Signed-off-by: Evgenii Stratonikov --- pkg/local_object_storage/blobstor/fstree/fstree.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pkg/local_object_storage/blobstor/fstree/fstree.go b/pkg/local_object_storage/blobstor/fstree/fstree.go index 14d1db341..7dd8ca3da 100644 --- a/pkg/local_object_storage/blobstor/fstree/fstree.go +++ b/pkg/local_object_storage/blobstor/fstree/fstree.go @@ -172,17 +172,19 @@ func (t *FSTree) iterate(depth uint64, curPath []string, prm common.IteratePrm) func (t *FSTree) treePath(addr oid.Address) string { sAddr := stringifyAddress(addr) - dirs := make([]string, 0, t.Depth+1+1) // 1 for root, 1 for file - dirs = append(dirs, t.RootPath) + var sb strings.Builder + sb.Grow(len(t.RootPath) + len(sAddr) + int(t.Depth) + 1) + sb.WriteString(t.RootPath) for i := 0; uint64(i) < t.Depth; i++ { - dirs = append(dirs, sAddr[:t.DirNameLen]) + sb.WriteRune(filepath.Separator) + sb.WriteString(sAddr[:t.DirNameLen]) sAddr = sAddr[t.DirNameLen:] } - dirs = append(dirs, sAddr) - - return filepath.Join(dirs...) + sb.WriteRune(filepath.Separator) + sb.WriteString(sAddr) + return sb.String() } // Delete removes the object with the specified address from the storage. -- 2.47.2