Skip to content

fstree: serve HEAD from the storage#3383

Merged
roman-khimov merged 2 commits intomasterfrom
2085-serve-head-from-storage
Jun 26, 2025
Merged

fstree: serve HEAD from the storage#3383
roman-khimov merged 2 commits intomasterfrom
2085-serve-head-from-storage

Conversation

@End-rey
Copy link
Contributor

@End-rey End-rey commented Jun 6, 2025

Closes #2085.

goos: linux
goarch: amd64
pkg: github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree
cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
BenchmarkFSTree_HeadVsGet
BenchmarkFSTree_HeadVsGet/Empty
BenchmarkFSTree_HeadVsGet/Empty/Head
BenchmarkFSTree_HeadVsGet/Empty/Head-16    	   51844	     28350 ns/op	    2288 B/op	      33 allocs/op
BenchmarkFSTree_HeadVsGet/Empty/Get
BenchmarkFSTree_HeadVsGet/Empty/Get-16     	   39008	     29472 ns/op	    2240 B/op	      32 allocs/op
BenchmarkFSTree_HeadVsGet/100B
BenchmarkFSTree_HeadVsGet/100B/Head
BenchmarkFSTree_HeadVsGet/100B/Head-16     	   48838	     29173 ns/op	    2736 B/op	      39 allocs/op
BenchmarkFSTree_HeadVsGet/100B/Get
BenchmarkFSTree_HeadVsGet/100B/Get-16      	   39392	     35613 ns/op	    2896 B/op	      39 allocs/op
BenchmarkFSTree_HeadVsGet/10KB
BenchmarkFSTree_HeadVsGet/10KB/Head
BenchmarkFSTree_HeadVsGet/10KB/Head-16     	   32133	     31803 ns/op	    2736 B/op	      39 allocs/op
BenchmarkFSTree_HeadVsGet/10KB/Get
BenchmarkFSTree_HeadVsGet/10KB/Get-16      	   23450	     47310 ns/op	   23520 B/op	      39 allocs/op
BenchmarkFSTree_HeadVsGet/100KB
BenchmarkFSTree_HeadVsGet/100KB/Head
BenchmarkFSTree_HeadVsGet/100KB/Head-16    	   48626	     30835 ns/op	    2736 B/op	      39 allocs/op
BenchmarkFSTree_HeadVsGet/100KB/Get
BenchmarkFSTree_HeadVsGet/100KB/Get-16     	    8876	    133707 ns/op	  215393 B/op	      39 allocs/op
BenchmarkFSTree_HeadVsGet/1MB
BenchmarkFSTree_HeadVsGet/1MB/Head
BenchmarkFSTree_HeadVsGet/1MB/Head-16      	   41428	     31624 ns/op	    2736 B/op	      39 allocs/op
BenchmarkFSTree_HeadVsGet/1MB/Get
BenchmarkFSTree_HeadVsGet/1MB/Get-16       	    1042	   1105492 ns/op	 2107974 B/op	      40 allocs/op

@codecov
Copy link

codecov bot commented Jun 6, 2025

Codecov Report

Attention: Patch coverage is 55.29412% with 76 lines in your changes missing coverage. Please review.

Project coverage is 21.04%. Comparing base (d651e2d) to head (e1cfe2a).
Report is 37 commits behind head on master.

Files with missing lines Patch % Lines
pkg/local_object_storage/blobstor/fstree/head.go 54.74% 45 Missing and 17 partials ⚠️
pkg/local_object_storage/blobstor/fstree/fstree.go 72.72% 5 Missing and 1 partial ⚠️
pkg/local_object_storage/shard/head.go 37.50% 4 Missing and 1 partial ⚠️
pkg/local_object_storage/writecache/get.go 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3383      +/-   ##
==========================================
- Coverage   21.16%   21.04%   -0.13%     
==========================================
  Files         708      707       -1     
  Lines       53045    52939     -106     
==========================================
- Hits        11229    11141      -88     
+ Misses      41015    40980      -35     
- Partials      801      818      +17     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@End-rey End-rey force-pushed the 2085-serve-head-from-storage branch from bccb054 to c551e92 Compare June 16, 2025 08:07
)

for {
n, err := io.ReadFull(f, comBuf[:])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading 16K of data is not much different from reading several bytes of data, you can leverage this to avoid some seeks (like when the file is not using combined format).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think reading 16K in the first chunk is good.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it was a combined object and it wasn't the first one, then it would be necessary to search for it, so for this I found only a way through io.MultiReader(buf, f), and then do not Seek, but io.CopyN(io.Discard...), which is in theory much worse.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depends on the size. The next OID can be in the same 16K, it's pretty easy to check, then if it's not there you're seeking for real.

if fieldEnd > len(data) {
return nil, fmt.Errorf("field exceeds data boundary")
}
out = append(out, data[offset-tagLen-lenLen:fieldEnd]...)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can reuse data, or just have a single slices.Copy() after you have found where the header ends.

@End-rey End-rey force-pushed the 2085-serve-head-from-storage branch from c551e92 to b525589 Compare June 18, 2025 11:41
@End-rey
Copy link
Contributor Author

End-rey commented Jun 18, 2025

goos: linux
goarch: amd64
pkg: github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree
cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
BenchmarkFSTree_HeadVsGet
BenchmarkFSTree_HeadVsGet/Empty
BenchmarkFSTree_HeadVsGet/Empty/Head
BenchmarkFSTree_HeadVsGet/Empty/Head-16    	   25698	     47241 ns/op	   18368 B/op	      31 allocs/op
BenchmarkFSTree_HeadVsGet/Empty/Get
BenchmarkFSTree_HeadVsGet/Empty/Get-16     	   42552	     31136 ns/op	    2240 B/op	      32 allocs/op
BenchmarkFSTree_HeadVsGet/100B
BenchmarkFSTree_HeadVsGet/100B/Head
BenchmarkFSTree_HeadVsGet/100B/Head-16     	   24008	     50258 ns/op	   18688 B/op	      37 allocs/op
BenchmarkFSTree_HeadVsGet/100B/Get
BenchmarkFSTree_HeadVsGet/100B/Get-16      	   31474	     36056 ns/op	    2896 B/op	      39 allocs/op
BenchmarkFSTree_HeadVsGet/10KB
BenchmarkFSTree_HeadVsGet/10KB/Head
BenchmarkFSTree_HeadVsGet/10KB/Head-16     	   23216	     50045 ns/op	   18688 B/op	      37 allocs/op
BenchmarkFSTree_HeadVsGet/10KB/Get
BenchmarkFSTree_HeadVsGet/10KB/Get-16      	   25491	     50612 ns/op	   23520 B/op	      39 allocs/op
BenchmarkFSTree_HeadVsGet/100KB
BenchmarkFSTree_HeadVsGet/100KB/Head
BenchmarkFSTree_HeadVsGet/100KB/Head-16    	   24316	     49310 ns/op	   18688 B/op	      37 allocs/op
BenchmarkFSTree_HeadVsGet/100KB/Get
BenchmarkFSTree_HeadVsGet/100KB/Get-16     	    7108	    143598 ns/op	  215394 B/op	      39 allocs/op
BenchmarkFSTree_HeadVsGet/1MB
BenchmarkFSTree_HeadVsGet/1MB/Head
BenchmarkFSTree_HeadVsGet/1MB/Head-16      	   24378	     47563 ns/op	   18688 B/op	      37 allocs/op
BenchmarkFSTree_HeadVsGet/1MB/Get
BenchmarkFSTree_HeadVsGet/1MB/Get-16       	    1030	   1214829 ns/op	 2107971 B/op	      40 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/100B
BenchmarkFSTree_HeadVsGet_Compressed/100B/Head_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/100B/Head_Compressed-16         	   12673	     93972 ns/op	   43447 B/op	      73 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/100B/Get_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/100B/Get_Compressed-16          	   58302	     17357 ns/op	    3312 B/op	      40 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/10KB
BenchmarkFSTree_HeadVsGet_Compressed/10KB/Head_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/10KB/Head_Compressed-16         	   11109	    108974 ns/op	   73652 B/op	      73 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/10KB/Get_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/10KB/Get_Compressed-16          	   27180	     46195 ns/op	   34432 B/op	      40 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/100KB
BenchmarkFSTree_HeadVsGet_Compressed/100KB/Head_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/100KB/Head_Compressed-16        	    5901	    199074 ns/op	  360508 B/op	      73 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/100KB/Get_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/100KB/Get_Compressed-16         	    8000	    148029 ns/op	  321920 B/op	      40 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/1MB
BenchmarkFSTree_HeadVsGet_Compressed/1MB/Head_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/1MB/Head_Compressed-16          	    1611	    747157 ns/op	 2703418 B/op	      76 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/1MB/Get_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/1MB/Get_Compressed-16           	    1306	    909101 ns/op	 3164752 B/op	      41 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/10MB
BenchmarkFSTree_HeadVsGet_Compressed/10MB/Head_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/10MB/Head_Compressed-16         	     577	   2043909 ns/op	10035257 B/op	      76 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/10MB/Get_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/10MB/Get_Compressed-16          	     135	   8580717 ns/op	31476305 B/op	      41 allocs/op

Since it works worse on small sizes, mb I can do the usual Read and Unmarshal with CutPayload for such?

if err != nil {
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
if !isCombined {
return comBuf[:n], nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this even be a valid header?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

func extractCombinedObject(id oid.ID, f *os.File) ([]byte, error) {
var (
comBuf [combinedDataOff]byte
data []byte
isCombined bool
)
for {
n, err := io.ReadFull(f, comBuf[:])
if err != nil {
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
if !isCombined {
return comBuf[:n], nil
}
return nil, fs.ErrNotExist

I took it from here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Big objects don't use combined format.

@roman-khimov
Copy link
Member

small sizes

We always know the size (either from the file size or from the combined header), so we can (and should, if there is a performance difference) adjust the logic wrt it.

@End-rey End-rey force-pushed the 2085-serve-head-from-storage branch from b525589 to fd09d6d Compare June 18, 2025 12:54
@End-rey
Copy link
Contributor Author

End-rey commented Jun 18, 2025

goos: linux
goarch: amd64
pkg: github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree
cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
BenchmarkFSTree_HeadVsGet
BenchmarkFSTree_HeadVsGet/Empty
BenchmarkFSTree_HeadVsGet/Empty/Head
BenchmarkFSTree_HeadVsGet/Empty/Head-16    	   25634	     66777 ns/op	    9632 B/op	     135 allocs/op
BenchmarkFSTree_HeadVsGet/Empty/Get
BenchmarkFSTree_HeadVsGet/Empty/Get-16     	   18246	     64145 ns/op	    9248 B/op	     134 allocs/op
BenchmarkFSTree_HeadVsGet/100B
BenchmarkFSTree_HeadVsGet/100B/Head
BenchmarkFSTree_HeadVsGet/100B/Head-16     	   18121	     70177 ns/op	   10392 B/op	     146 allocs/op
BenchmarkFSTree_HeadVsGet/100B/Get
BenchmarkFSTree_HeadVsGet/100B/Get-16      	   17790	     67663 ns/op	   10008 B/op	     145 allocs/op
BenchmarkFSTree_HeadVsGet/10KB
BenchmarkFSTree_HeadVsGet/10KB/Head
BenchmarkFSTree_HeadVsGet/10KB/Head-16     	   15078	     77482 ns/op	   30336 B/op	     127 allocs/op
BenchmarkFSTree_HeadVsGet/10KB/Get
BenchmarkFSTree_HeadVsGet/10KB/Get-16      	   15609	     77399 ns/op	   29952 B/op	     126 allocs/op
BenchmarkFSTree_HeadVsGet/100KB
BenchmarkFSTree_HeadVsGet/100KB/Head
BenchmarkFSTree_HeadVsGet/100KB/Head-16    	   15103	     78250 ns/op	   24424 B/op	     143 allocs/op
BenchmarkFSTree_HeadVsGet/100KB/Get
BenchmarkFSTree_HeadVsGet/100KB/Get-16     	    6230	    184139 ns/op	  221130 B/op	     145 allocs/op
BenchmarkFSTree_HeadVsGet/1MB
BenchmarkFSTree_HeadVsGet/1MB/Head
BenchmarkFSTree_HeadVsGet/1MB/Head-16      	   15006	     83145 ns/op	   23920 B/op	     125 allocs/op
BenchmarkFSTree_HeadVsGet/1MB/Get
BenchmarkFSTree_HeadVsGet/1MB/Get-16       	     966	   1274660 ns/op	 2113010 B/op	     127 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/100B
BenchmarkFSTree_HeadVsGet_Compressed/100B/Head_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/100B/Head_Compressed-16         	   28869	     39087 ns/op	   11576 B/op	     136 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/100B/Get_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/100B/Get_Compressed-16          	   31962	     37131 ns/op	   11192 B/op	     135 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/10KB
BenchmarkFSTree_HeadVsGet_Compressed/10KB/Head_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/10KB/Head_Compressed-16         	   14811	     73411 ns/op	   43336 B/op	     147 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/10KB/Get_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/10KB/Get_Compressed-16          	   15410	     73273 ns/op	   42952 B/op	     146 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/100KB
BenchmarkFSTree_HeadVsGet_Compressed/100KB/Head_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/100KB/Head_Compressed-16        	    5196	    227659 ns/op	  349506 B/op	     168 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/100KB/Get_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/100KB/Get_Compressed-16         	    6386	    176203 ns/op	  327256 B/op	     135 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/1MB
BenchmarkFSTree_HeadVsGet_Compressed/1MB/Head_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/1MB/Head_Compressed-16          	    1496	    792203 ns/op	 2692983 B/op	     183 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/1MB/Get_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/1MB/Get_Compressed-16           	    1290	    932975 ns/op	 3170456 B/op	     147 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/10MB
BenchmarkFSTree_HeadVsGet_Compressed/10MB/Head_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/10MB/Head_Compressed-16         	     592	   2005437 ns/op	10024413 B/op	     172 allocs/op
BenchmarkFSTree_HeadVsGet_Compressed/10MB/Get_Compressed
BenchmarkFSTree_HeadVsGet_Compressed/10MB/Get_Compressed-16          	     132	   8309719 ns/op	31481593 B/op	     136 allocs/op

The values are lower than before because I used https://pkg.go.dev/github.com/nspcc-dev/neofs-sdk-go/object/test#Object

)

for {
n, err := io.ReadFull(f, comBuf[:])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think reading 16K in the first chunk is good.

@End-rey End-rey force-pushed the 2085-serve-head-from-storage branch from fd09d6d to 638c2e9 Compare June 19, 2025 18:27
@End-rey End-rey force-pushed the 2085-serve-head-from-storage branch from 638c2e9 to c8d0121 Compare June 20, 2025 13:52
@cthulhu-rider
Copy link
Contributor

@End-rey i see ur trying to pool buffers which is generally reasonable, but for the future lets make such improvements into changes separate from the functional part (even separate issues/PRs). Amending them complicates the review

@End-rey End-rey force-pushed the 2085-serve-head-from-storage branch from c8d0121 to 2bdf007 Compare June 20, 2025 14:48
@End-rey
Copy link
Contributor Author

End-rey commented Jun 24, 2025

goos: linux
goarch: amd64
pkg: github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree
cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
BenchmarkFSTree_HeadVsHead2/Empty/WithHeader/NewStruct_Head-16                             17799             71600 ns/op            9544 B/op        132 allocs/op
BenchmarkFSTree_HeadVsHead2/Empty/WithHeader/Storage_Head-16                               15642             76309 ns/op           26440 B/op        132 allocs/op
BenchmarkFSTree_HeadVsHead2/Empty/WithoutHeader/NewStruct_Head-16                          16225             72772 ns/op            9960 B/op        144 allocs/op
BenchmarkFSTree_HeadVsHead2/Empty/WithoutHeader/Storage_Head-16                            15097             79197 ns/op           26856 B/op        144 allocs/op
BenchmarkFSTree_HeadVsHead2/Empty/WithHeader_Compressed/NewStruct_Head-16                  28329             42984 ns/op           11592 B/op        145 allocs/op
BenchmarkFSTree_HeadVsHead2/Empty/WithHeader_Compressed/Storage_Head-16                    21354             63590 ns/op           28488 B/op        145 allocs/op
BenchmarkFSTree_HeadVsHead2/Empty/WithoutHeader_Compressed/NewStruct_Head-16               16915             70447 ns/op            9432 B/op        128 allocs/op
BenchmarkFSTree_HeadVsHead2/Empty/WithoutHeader_Compressed/Storage_Head-16                 15867             75412 ns/op           26328 B/op        128 allocs/op

BenchmarkFSTree_HeadVsHead2/100B/WithHeader/NewStruct_Head-16                              16556             69927 ns/op            9928 B/op        132 allocs/op
BenchmarkFSTree_HeadVsHead2/100B/WithHeader/Storage_Head-16                                15696             76432 ns/op           26568 B/op        132 allocs/op
BenchmarkFSTree_HeadVsHead2/100B/WithoutHeader/NewStruct_Head-16                           16454             73023 ns/op            9880 B/op        139 allocs/op
BenchmarkFSTree_HeadVsHead2/100B/WithoutHeader/Storage_Head-16                             15331             78875 ns/op           26776 B/op        139 allocs/op
BenchmarkFSTree_HeadVsHead2/100B/WithHeader_Compressed/NewStruct_Head-16                   28323             42287 ns/op           11752 B/op        141 allocs/op
BenchmarkFSTree_HeadVsHead2/100B/WithHeader_Compressed/Storage_Head-16                     20347             60362 ns/op           28648 B/op        141 allocs/op
BenchmarkFSTree_HeadVsHead2/100B/WithoutHeader_Compressed/NewStruct_Head-16                16209             71165 ns/op           10376 B/op        143 allocs/op
BenchmarkFSTree_HeadVsHead2/100B/WithoutHeader_Compressed/Storage_Head-16                  15086             79251 ns/op           27016 B/op        143 allocs/op

BenchmarkFSTree_HeadVsHead2/10KB/WithHeader/NewStruct_Head-16                              13856             86454 ns/op           30808 B/op        140 allocs/op
BenchmarkFSTree_HeadVsHead2/10KB/WithHeader/Storage_Head-16                                13914             85882 ns/op           36952 B/op        140 allocs/op
BenchmarkFSTree_HeadVsHead2/10KB/WithoutHeader/NewStruct_Head-16                           14044             84699 ns/op           30648 B/op        136 allocs/op
BenchmarkFSTree_HeadVsHead2/10KB/WithoutHeader/Storage_Head-16                             14001             85406 ns/op           36792 B/op        136 allocs/op
BenchmarkFSTree_HeadVsHead2/10KB/WithHeader_Compressed/NewStruct_Head-16                   14620             78818 ns/op           43416 B/op        148 allocs/op
BenchmarkFSTree_HeadVsHead2/10KB/WithHeader_Compressed/Storage_Head-16                     15364             83019 ns/op           49560 B/op        148 allocs/op
BenchmarkFSTree_HeadVsHead2/10KB/WithoutHeader_Compressed/NewStruct_Head-16                14569             83984 ns/op           30376 B/op        128 allocs/op
BenchmarkFSTree_HeadVsHead2/10KB/WithoutHeader_Compressed/Storage_Head-16                  14312             83759 ns/op           36520 B/op        128 allocs/op

BenchmarkFSTree_HeadVsHead2/100KB/WithHeader/NewStruct_Head-16                             17217             70027 ns/op            9984 B/op        144 allocs/op
BenchmarkFSTree_HeadVsHead2/100KB/WithHeader/Storage_Head-16                               15168             77343 ns/op           26840 B/op        142 allocs/op
BenchmarkFSTree_HeadVsHead2/100KB/WithoutHeader/NewStruct_Head-16                           5559            193208 ns/op          221529 B/op        147 allocs/op
BenchmarkFSTree_HeadVsHead2/100KB/WithoutHeader/Storage_Head-16                            14971             80337 ns/op           26488 B/op        144 allocs/op
BenchmarkFSTree_HeadVsHead2/100KB/WithHeader_Compressed/NewStruct_Head-16                  28316             35900 ns/op            9904 B/op        140 allocs/op
BenchmarkFSTree_HeadVsHead2/100KB/WithHeader_Compressed/Storage_Head-16                    18867             55324 ns/op           26760 B/op        138 allocs/op
BenchmarkFSTree_HeadVsHead2/100KB/WithoutHeader_Compressed/NewStruct_Head-16                5860            193233 ns/op          221369 B/op        143 allocs/op
BenchmarkFSTree_HeadVsHead2/100KB/WithoutHeader_Compressed/Storage_Head-16                 15336             79660 ns/op           26328 B/op        140 allocs/op

BenchmarkFSTree_HeadVsHead2/1MB/WithHeader/NewStruct_Head-16                               15350             76556 ns/op            9936 B/op        138 allocs/op
BenchmarkFSTree_HeadVsHead2/1MB/WithHeader/Storage_Head-16                                 13207             90339 ns/op           26744 B/op        136 allocs/op
BenchmarkFSTree_HeadVsHead2/1MB/WithoutHeader/NewStruct_Head-16                              872           1414288 ns/op         2114180 B/op        148 allocs/op
BenchmarkFSTree_HeadVsHead2/1MB/WithoutHeader/Storage_Head-16                              12928             93106 ns/op           26712 B/op        145 allocs/op
BenchmarkFSTree_HeadVsHead2/1MB/WithHeader_Compressed/NewStruct_Head-16                    37783             29837 ns/op            9808 B/op        134 allocs/op
BenchmarkFSTree_HeadVsHead2/1MB/WithHeader_Compressed/Storage_Head-16                      25893             47574 ns/op           26632 B/op        132 allocs/op
BenchmarkFSTree_HeadVsHead2/1MB/WithoutHeader_Compressed/NewStruct_Head-16                   830           1283129 ns/op         2113809 B/op        137 allocs/op
BenchmarkFSTree_HeadVsHead2/1MB/WithoutHeader_Compressed/Storage_Head-16                   13240             89855 ns/op           26376 B/op        134 allocs/op

The new structure of the objects gives an increase in speed, but on small objects almost everything is the same. There is a large increase mainly on compressed objects due to the use of fast DecodeAll, instead of sequential reading.
WithHeader is the case when a new data structure is used. WithoutHeaders is an old data storage format.

if offset < len(buf) {
n = copy(comBuf[:], buf[offset:])
}
_, err := io.ReadFull(f, comBuf[n:])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to be suboptimal for combined files with small objects, but it's correct anyway.

@End-rey End-rey force-pushed the 2085-serve-head-from-storage branch from 2bdf007 to efe51b1 Compare June 25, 2025 18:36
@End-rey End-rey requested a review from roman-khimov June 25, 2025 19:03
}

offset += int(l)
if n-offset < objectSDK.MaxHeaderLen {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather check that buffer has at least combinedDataOff bytes from offset. If it is --- check the next OID and act accordingly. It's quite likely the next OID is not going to be the one we need and we do not want to read more in this case. Read the next four pages only if offset points to something out of the buffer scope.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we check this way, there may be a situation where the data will not be enough for the header, but the ID has been found. Will I have to read it again then? Or should I leave it like it is now?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll read it in header getter, pass whatever you have there, if it's not sufficient it'll read a bit more. It'd be more efficient for 1-4K objects, you can have like 10 of them in the first 16K and if you quickly jump through them --- good for you. Maybe the one we need is in this 16K, maybe not, doesn't matter, the less reads/seeks we do the better. And in case of 32K objects nothing really changes, seek/read, OK, no way around it.

@End-rey End-rey force-pushed the 2085-serve-head-from-storage branch from efe51b1 to 7c69c80 Compare June 26, 2025 10:29
@End-rey End-rey requested a review from roman-khimov June 26, 2025 10:29
@End-rey End-rey force-pushed the 2085-serve-head-from-storage branch from 7c69c80 to 5d1b7cd Compare June 26, 2025 11:39
Copy link
Member

@roman-khimov roman-khimov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some reads can still be optimized, but OK for now.

@End-rey End-rey force-pushed the 2085-serve-head-from-storage branch from 5d1b7cd to e1cfe2a Compare June 26, 2025 11:56
End-rey added 2 commits June 26, 2025 14:57
Now the `HEAD` operation can be performed directly in the storage, where the
object is retrieved from the file without payload. Add tests and bench to see
the difference between `Head` and `Get`. Use the new `Head` function in the
write cache and in the shard.

Closes #2085.

Signed-off-by: Andrey Butusov <andrey@nspcc.io>
Signed-off-by: Andrey Butusov <andrey@nspcc.io>
@roman-khimov roman-khimov merged commit c745de8 into master Jun 26, 2025
21 of 22 checks passed
@roman-khimov roman-khimov deleted the 2085-serve-head-from-storage branch June 26, 2025 12:26
End-rey added a commit that referenced this pull request Jul 1, 2025
Since #3383 and #3431, it is now not necessary to unmarshal the object to get
its payload, and we can read the payload from reader to find the data.

Closes #1724.

Signed-off-by: Andrey Butusov <andrey@nspcc.io>
End-rey added a commit that referenced this pull request Jul 3, 2025
Since #3383 and #3431, it is now not necessary to unmarshal the object to get
its payload, and we can read the payload from reader to find the data.

```
goos: linux
goarch: amd64
pkg: github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree
cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
                                                            │   old.txt    │               new.txt                │
                                                            │    sec/op    │    sec/op     vs base                │
FSTree_GetRange/size=10MB,off=1MB,len=4KB/regular-16          7457.9µ ± 8%   262.2µ ±  8%  -96.48% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/compressed-16       7440.2µ ± 5%   261.5µ ± 10%  -96.49% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/combined-16         9840.3µ ± 6%   355.8µ ±  4%  -96.38% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/regular-16        8.242m ± 8%   3.977m ±  1%  -51.75% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/compressed-16     7.814m ± 4%   3.979m ±  2%  -49.07% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/combined-16       9.821m ± 4%   3.765m ±  3%  -61.67% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/regular-16      10.432m ± 6%   3.987m ±  2%  -61.78% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/compressed-16   10.721m ± 9%   3.982m ±  2%  -62.85% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/combined-16      9.766m ± 5%   3.680m ±  6%  -62.32% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/regular-16          77.48µ ± 2%   90.66µ ±  2%  +17.00% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/compressed-16       77.42µ ± 5%   91.58µ ±  3%  +18.29% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/combined-16         79.90µ ± 3%   90.45µ ±  1%  +13.21% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/regular-16        80.28µ ± 2%   89.15µ ±  2%  +11.05% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/compressed-16     79.36µ ± 3%   89.60µ ±  3%  +12.91% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/combined-16       77.83µ ± 6%   91.00µ ±  1%  +16.93% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/regular-16            79.47µ ± 2%   86.42µ ±  2%   +8.75% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/compressed-16         79.30µ ± 4%   88.33µ ±  2%  +11.40% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/combined-16           79.86µ ± 2%   90.45µ ±  1%  +13.27% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/regular-16          10.294m ± 6%   1.856m ±  3%  -81.97% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/compressed-16       10.059m ± 6%   1.848m ±  4%  -81.63% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/combined-16          9.650m ± 6%   1.723m ±  6%  -82.15% (p=0.000 n=10)
geomean                                                        1.199m        478.5µ        -60.09%

                                                            │     old.txt     │                new.txt                │
                                                            │      B/op       │     B/op      vs base                 │
FSTree_GetRange/size=10MB,off=1MB,len=4KB/regular-16          20495.52Ki ± 0%   43.91Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/compressed-16       20495.52Ki ± 0%   43.90Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/combined-16         20495.96Ki ± 0%   43.81Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/regular-16          20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/compressed-16       20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/combined-16         20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/regular-16         20.02Mi ± 0%   10.04Mi ± 0%   -49.85% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/compressed-16      20.02Mi ± 0%   10.04Mi ± 0%   -49.85% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/combined-16        20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/regular-16            17.62Ki ± 0%   48.31Ki ± 0%  +174.24% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/compressed-16         17.62Ki ± 0%   48.31Ki ± 0%  +174.24% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/combined-16           17.90Ki ± 0%   48.08Ki ± 0%  +168.60% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/regular-16          17.77Ki ± 0%   47.95Ki ± 0%  +169.80% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/compressed-16       17.77Ki ± 0%   47.95Ki ± 0%  +169.80% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/combined-16         17.91Ki ± 0%   48.13Ki ± 0%  +168.81% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/regular-16              17.92Ki ± 0%   44.77Ki ± 0%  +149.83% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/compressed-16           17.92Ki ± 0%   44.77Ki ± 0%  +149.83% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/combined-16             17.95Ki ± 1%   45.13Ki ± 0%  +151.45% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/regular-16          20495.92Ki ± 0%   43.66Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/compressed-16       20495.92Ki ± 0%   43.66Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/combined-16         20495.94Ki ± 0%   43.75Ki ± 0%   -99.79% (p=0.000 n=10)
geomean                                                          999.8Ki        214.7Ki        -78.52%

                                                            │  old.txt   │              new.txt               │
                                                            │ allocs/op  │ allocs/op   vs base                │
FSTree_GetRange/size=10MB,off=1MB,len=4KB/regular-16          127.0 ± 0%   145.0 ± 0%  +14.17% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/compressed-16       127.0 ± 0%   145.0 ± 0%  +14.17% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/combined-16         139.0 ± 2%   141.0 ± 1%   +1.44% (p=0.010 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/regular-16       149.0 ± 0%   148.0 ± 0%   -0.67% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/compressed-16    149.0 ± 0%   148.0 ± 0%   -0.67% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/combined-16      138.5 ± 3%   140.0 ± 2%   +1.08% (p=0.027 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/regular-16      135.0 ± 0%   137.0 ± 0%   +1.48% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/compressed-16   135.0 ± 0%   137.0 ± 0%   +1.48% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/combined-16     137.0 ± 2%   141.0 ± 1%   +2.92% (p=0.001 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/regular-16         131.0 ± 0%   145.0 ± 0%  +10.69% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/compressed-16      131.0 ± 0%   145.0 ± 0%  +10.69% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/combined-16        137.0 ± 1%   139.0 ± 1%   +1.46% (p=0.007 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/regular-16       135.0 ± 0%   137.0 ± 0%   +1.48% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/compressed-16    135.0 ± 0%   137.0 ± 0%   +1.48% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/combined-16      137.5 ± 0%   140.5 ± 1%   +2.18% (p=0.001 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/regular-16           139.0 ± 0%   129.0 ± 0%   -7.19% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/compressed-16        139.0 ± 0%   129.0 ± 0%   -7.19% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/combined-16          139.0 ± 2%   140.5 ± 2%        ~ (p=0.058 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/regular-16          139.0 ± 0%   138.0 ± 0%   -0.72% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/compressed-16       139.0 ± 0%   138.0 ± 0%   -0.72% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/combined-16         138.0 ± 2%   140.5 ± 2%   +1.81% (p=0.002 n=10)
geomean                                                       136.8        139.9        +2.26%
```

Closes #1724.

Signed-off-by: Andrey Butusov <andrey@nspcc.io>
End-rey added a commit that referenced this pull request Jul 3, 2025
Since #3383 and #3431, it is now not necessary to unmarshal the object to get
its payload, and we can read the payload from reader to find the data.

```
goos: linux
goarch: amd64
pkg: github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree
cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
                                                            │   old.txt    │               new.txt                │
                                                            │    sec/op    │    sec/op     vs base                │
FSTree_GetRange/size=10MB,off=1MB,len=4KB/regular-16          7457.9µ ± 8%   262.2µ ±  8%  -96.48% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/compressed-16       7440.2µ ± 5%   261.5µ ± 10%  -96.49% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/combined-16         9840.3µ ± 6%   355.8µ ±  4%  -96.38% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/regular-16        8.242m ± 8%   3.977m ±  1%  -51.75% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/compressed-16     7.814m ± 4%   3.979m ±  2%  -49.07% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/combined-16       9.821m ± 4%   3.765m ±  3%  -61.67% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/regular-16      10.432m ± 6%   3.987m ±  2%  -61.78% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/compressed-16   10.721m ± 9%   3.982m ±  2%  -62.85% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/combined-16      9.766m ± 5%   3.680m ±  6%  -62.32% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/regular-16          77.48µ ± 2%   90.66µ ±  2%  +17.00% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/compressed-16       77.42µ ± 5%   91.58µ ±  3%  +18.29% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/combined-16         79.90µ ± 3%   90.45µ ±  1%  +13.21% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/regular-16        80.28µ ± 2%   89.15µ ±  2%  +11.05% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/compressed-16     79.36µ ± 3%   89.60µ ±  3%  +12.91% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/combined-16       77.83µ ± 6%   91.00µ ±  1%  +16.93% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/regular-16            79.47µ ± 2%   86.42µ ±  2%   +8.75% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/compressed-16         79.30µ ± 4%   88.33µ ±  2%  +11.40% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/combined-16           79.86µ ± 2%   90.45µ ±  1%  +13.27% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/regular-16          10.294m ± 6%   1.856m ±  3%  -81.97% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/compressed-16       10.059m ± 6%   1.848m ±  4%  -81.63% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/combined-16          9.650m ± 6%   1.723m ±  6%  -82.15% (p=0.000 n=10)
geomean                                                        1.199m        478.5µ        -60.09%

                                                            │     old.txt     │                new.txt                │
                                                            │      B/op       │     B/op      vs base                 │
FSTree_GetRange/size=10MB,off=1MB,len=4KB/regular-16          20495.52Ki ± 0%   43.91Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/compressed-16       20495.52Ki ± 0%   43.90Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/combined-16         20495.96Ki ± 0%   43.81Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/regular-16          20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/compressed-16       20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/combined-16         20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/regular-16         20.02Mi ± 0%   10.04Mi ± 0%   -49.85% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/compressed-16      20.02Mi ± 0%   10.04Mi ± 0%   -49.85% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/combined-16        20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/regular-16            17.62Ki ± 0%   48.31Ki ± 0%  +174.24% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/compressed-16         17.62Ki ± 0%   48.31Ki ± 0%  +174.24% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/combined-16           17.90Ki ± 0%   48.08Ki ± 0%  +168.60% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/regular-16          17.77Ki ± 0%   47.95Ki ± 0%  +169.80% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/compressed-16       17.77Ki ± 0%   47.95Ki ± 0%  +169.80% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/combined-16         17.91Ki ± 0%   48.13Ki ± 0%  +168.81% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/regular-16              17.92Ki ± 0%   44.77Ki ± 0%  +149.83% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/compressed-16           17.92Ki ± 0%   44.77Ki ± 0%  +149.83% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/combined-16             17.95Ki ± 1%   45.13Ki ± 0%  +151.45% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/regular-16          20495.92Ki ± 0%   43.66Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/compressed-16       20495.92Ki ± 0%   43.66Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/combined-16         20495.94Ki ± 0%   43.75Ki ± 0%   -99.79% (p=0.000 n=10)
geomean                                                          999.8Ki        214.7Ki        -78.52%

                                                            │  old.txt   │              new.txt               │
                                                            │ allocs/op  │ allocs/op   vs base                │
FSTree_GetRange/size=10MB,off=1MB,len=4KB/regular-16          127.0 ± 0%   145.0 ± 0%  +14.17% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/compressed-16       127.0 ± 0%   145.0 ± 0%  +14.17% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/combined-16         139.0 ± 2%   141.0 ± 1%   +1.44% (p=0.010 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/regular-16       149.0 ± 0%   148.0 ± 0%   -0.67% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/compressed-16    149.0 ± 0%   148.0 ± 0%   -0.67% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/combined-16      138.5 ± 3%   140.0 ± 2%   +1.08% (p=0.027 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/regular-16      135.0 ± 0%   137.0 ± 0%   +1.48% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/compressed-16   135.0 ± 0%   137.0 ± 0%   +1.48% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/combined-16     137.0 ± 2%   141.0 ± 1%   +2.92% (p=0.001 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/regular-16         131.0 ± 0%   145.0 ± 0%  +10.69% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/compressed-16      131.0 ± 0%   145.0 ± 0%  +10.69% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/combined-16        137.0 ± 1%   139.0 ± 1%   +1.46% (p=0.007 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/regular-16       135.0 ± 0%   137.0 ± 0%   +1.48% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/compressed-16    135.0 ± 0%   137.0 ± 0%   +1.48% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/combined-16      137.5 ± 0%   140.5 ± 1%   +2.18% (p=0.001 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/regular-16           139.0 ± 0%   129.0 ± 0%   -7.19% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/compressed-16        139.0 ± 0%   129.0 ± 0%   -7.19% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/combined-16          139.0 ± 2%   140.5 ± 2%        ~ (p=0.058 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/regular-16          139.0 ± 0%   138.0 ± 0%   -0.72% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/compressed-16       139.0 ± 0%   138.0 ± 0%   -0.72% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/combined-16         138.0 ± 2%   140.5 ± 2%   +1.81% (p=0.002 n=10)
geomean                                                       136.8        139.9        +2.26%
```

Closes #1724.

Signed-off-by: Andrey Butusov <andrey@nspcc.io>
End-rey added a commit that referenced this pull request Jul 3, 2025
Since #3383 and #3431, it is now not necessary to unmarshal the object to get
its payload, and we can read the payload from reader to find the data.

```
goos: linux
goarch: amd64
pkg: github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree
cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
                                                            │   old.txt    │               new.txt                │
                                                            │    sec/op    │    sec/op     vs base                │
FSTree_GetRange/size=10MB,off=1MB,len=4KB/regular-16          7457.9µ ± 8%   262.2µ ±  8%  -96.48% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/compressed-16       7440.2µ ± 5%   261.5µ ± 10%  -96.49% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/combined-16         9840.3µ ± 6%   355.8µ ±  4%  -96.38% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/regular-16        8.242m ± 8%   3.977m ±  1%  -51.75% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/compressed-16     7.814m ± 4%   3.979m ±  2%  -49.07% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/combined-16       9.821m ± 4%   3.765m ±  3%  -61.67% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/regular-16      10.432m ± 6%   3.987m ±  2%  -61.78% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/compressed-16   10.721m ± 9%   3.982m ±  2%  -62.85% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/combined-16      9.766m ± 5%   3.680m ±  6%  -62.32% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/regular-16          77.48µ ± 2%   90.66µ ±  2%  +17.00% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/compressed-16       77.42µ ± 5%   91.58µ ±  3%  +18.29% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/combined-16         79.90µ ± 3%   90.45µ ±  1%  +13.21% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/regular-16        80.28µ ± 2%   89.15µ ±  2%  +11.05% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/compressed-16     79.36µ ± 3%   89.60µ ±  3%  +12.91% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/combined-16       77.83µ ± 6%   91.00µ ±  1%  +16.93% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/regular-16            79.47µ ± 2%   86.42µ ±  2%   +8.75% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/compressed-16         79.30µ ± 4%   88.33µ ±  2%  +11.40% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/combined-16           79.86µ ± 2%   90.45µ ±  1%  +13.27% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/regular-16          10.294m ± 6%   1.856m ±  3%  -81.97% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/compressed-16       10.059m ± 6%   1.848m ±  4%  -81.63% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/combined-16          9.650m ± 6%   1.723m ±  6%  -82.15% (p=0.000 n=10)
geomean                                                        1.199m        478.5µ        -60.09%

                                                            │     old.txt     │                new.txt                │
                                                            │      B/op       │     B/op      vs base                 │
FSTree_GetRange/size=10MB,off=1MB,len=4KB/regular-16          20495.52Ki ± 0%   43.91Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/compressed-16       20495.52Ki ± 0%   43.90Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/combined-16         20495.96Ki ± 0%   43.81Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/regular-16          20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/compressed-16       20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/combined-16         20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/regular-16         20.02Mi ± 0%   10.04Mi ± 0%   -49.85% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/compressed-16      20.02Mi ± 0%   10.04Mi ± 0%   -49.85% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/combined-16        20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/regular-16            17.62Ki ± 0%   48.31Ki ± 0%  +174.24% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/compressed-16         17.62Ki ± 0%   48.31Ki ± 0%  +174.24% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/combined-16           17.90Ki ± 0%   48.08Ki ± 0%  +168.60% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/regular-16          17.77Ki ± 0%   47.95Ki ± 0%  +169.80% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/compressed-16       17.77Ki ± 0%   47.95Ki ± 0%  +169.80% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/combined-16         17.91Ki ± 0%   48.13Ki ± 0%  +168.81% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/regular-16              17.92Ki ± 0%   44.77Ki ± 0%  +149.83% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/compressed-16           17.92Ki ± 0%   44.77Ki ± 0%  +149.83% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/combined-16             17.95Ki ± 1%   45.13Ki ± 0%  +151.45% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/regular-16          20495.92Ki ± 0%   43.66Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/compressed-16       20495.92Ki ± 0%   43.66Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/combined-16         20495.94Ki ± 0%   43.75Ki ± 0%   -99.79% (p=0.000 n=10)
geomean                                                          999.8Ki        214.7Ki        -78.52%

                                                            │  old.txt   │              new.txt               │
                                                            │ allocs/op  │ allocs/op   vs base                │
FSTree_GetRange/size=10MB,off=1MB,len=4KB/regular-16          127.0 ± 0%   145.0 ± 0%  +14.17% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/compressed-16       127.0 ± 0%   145.0 ± 0%  +14.17% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/combined-16         139.0 ± 2%   141.0 ± 1%   +1.44% (p=0.010 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/regular-16       149.0 ± 0%   148.0 ± 0%   -0.67% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/compressed-16    149.0 ± 0%   148.0 ± 0%   -0.67% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/combined-16      138.5 ± 3%   140.0 ± 2%   +1.08% (p=0.027 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/regular-16      135.0 ± 0%   137.0 ± 0%   +1.48% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/compressed-16   135.0 ± 0%   137.0 ± 0%   +1.48% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/combined-16     137.0 ± 2%   141.0 ± 1%   +2.92% (p=0.001 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/regular-16         131.0 ± 0%   145.0 ± 0%  +10.69% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/compressed-16      131.0 ± 0%   145.0 ± 0%  +10.69% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/combined-16        137.0 ± 1%   139.0 ± 1%   +1.46% (p=0.007 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/regular-16       135.0 ± 0%   137.0 ± 0%   +1.48% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/compressed-16    135.0 ± 0%   137.0 ± 0%   +1.48% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/combined-16      137.5 ± 0%   140.5 ± 1%   +2.18% (p=0.001 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/regular-16           139.0 ± 0%   129.0 ± 0%   -7.19% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/compressed-16        139.0 ± 0%   129.0 ± 0%   -7.19% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/combined-16          139.0 ± 2%   140.5 ± 2%        ~ (p=0.058 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/regular-16          139.0 ± 0%   138.0 ± 0%   -0.72% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/compressed-16       139.0 ± 0%   138.0 ± 0%   -0.72% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=9MB,len=4KB/combined-16         138.0 ± 2%   140.5 ± 2%   +1.81% (p=0.002 n=10)
geomean                                                       136.8        139.9        +2.26%
```

Closes #1724.

Signed-off-by: Andrey Butusov <andrey@nspcc.io>
End-rey added a commit that referenced this pull request Jul 4, 2025
Since #3383 and #3431, it is now not necessary to unmarshal the object to get
its payload, and we can read the payload from reader to find the data.

```
goos: linux
goarch: amd64
pkg: github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree
cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
                                                            │    old.txt     │               new.txt                │
                                                            │     sec/op     │    sec/op     vs base                │
FSTree_GetRange/size=10MB,off=1MB,len=4KB/regular-16           8027.9µ ±  9%   264.8µ ±  5%  -96.70% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/compressed-16        7608.3µ ±  5%   270.5µ ±  6%  -96.45% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/combined-16          7391.8µ ±  6%   360.6µ ±  8%  -95.12% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/regular-16         7.876m ±  4%   4.134m ±  3%  -47.52% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/compressed-16      7.989m ±  6%   4.170m ±  3%  -47.80% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/combined-16        7.530m ±  2%   4.038m ±  8%  -46.37% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/regular-16        8.220m ±  6%   4.164m ±  4%  -49.35% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/compressed-16     8.183m ±  6%   4.703m ±  6%  -42.53% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/combined-16       7.508m ±  5%   4.325m ±  5%  -42.40% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/regular-16            822.54µ ±  6%   83.04µ ±  4%  -89.90% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/compressed-16         884.94µ ±  7%   92.61µ ±  5%  -89.53% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/combined-16          1346.99µ ± 11%   84.62µ ± 10%  -93.72% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/regular-16           908.2µ ± 15%   817.8µ ±  9%        ~ (p=0.165 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/compressed-16        946.3µ ±  3%   806.2µ ±  4%  -14.80% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/combined-16         1290.4µ ±  9%   914.6µ ± 11%  -29.12% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/regular-16         955.0µ ±  3%   863.4µ ±  4%   -9.60% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/compressed-16      948.7µ ±  4%   869.5µ ±  5%   -8.35% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/combined-16       1318.8µ ± 13%   955.9µ ±  7%  -27.52% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/regular-16           79.55µ ±  5%   89.11µ ±  2%  +12.01% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/compressed-16        78.48µ ±  5%   87.90µ ±  2%  +12.01% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/combined-16          79.15µ ±  4%   92.59µ ±  3%  +16.98% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/regular-16         81.78µ ±  4%   92.22µ ±  4%  +12.77% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/compressed-16      79.80µ ± 11%   90.99µ ±  3%  +14.02% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/combined-16        92.39µ ±  9%   92.73µ ±  2%        ~ (p=0.280 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/regular-16             92.11µ ±  1%   89.30µ ±  2%   -3.06% (p=0.002 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/compressed-16          80.11µ ± 17%   91.34µ ±  2%        ~ (p=0.105 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/combined-16            79.40µ ±  5%   90.61µ ±  4%  +14.12% (p=0.000 n=10)
geomean                                                         871.6µ         399.9µ        -54.12%

                                                            │     old.txt     │                new.txt                │
                                                            │      B/op       │     B/op      vs base                 │
FSTree_GetRange/size=10MB,off=1MB,len=4KB/regular-16          20495.77Ki ± 0%   43.65Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/compressed-16       20495.77Ki ± 0%   43.65Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/combined-16         20496.00Ki ± 0%   43.81Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/regular-16          20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/compressed-16       20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/combined-16         20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/regular-16         20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/compressed-16      20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/combined-16        20.02Mi ± 0%   10.04Mi ± 0%   -49.85% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/regular-16            2063.83Ki ± 0%   43.65Ki ± 0%   -97.89% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/compressed-16         2063.83Ki ± 0%   43.65Ki ± 0%   -97.88% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/combined-16           2063.98Ki ± 0%   43.89Ki ± 0%   -97.87% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/regular-16            2.015Mi ± 0%   1.039Mi ± 0%   -48.45% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/compressed-16         2.015Mi ± 0%   1.039Mi ± 0%   -48.45% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/combined-16           2.016Mi ± 0%   1.039Mi ± 0%   -48.46% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/regular-16          2.015Mi ± 0%   1.039Mi ± 0%   -48.44% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/compressed-16       2.015Mi ± 0%   1.039Mi ± 0%   -48.44% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/combined-16         2.016Mi ± 0%   1.039Mi ± 0%   -48.46% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/regular-16            17.97Ki ± 0%   47.68Ki ± 0%  +165.35% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/compressed-16         17.97Ki ± 0%   47.68Ki ± 0%  +165.35% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/combined-16           17.91Ki ± 0%   48.13Ki ± 0%  +168.71% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/regular-16          18.12Ki ± 0%   48.09Ki ± 0%  +165.42% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/compressed-16       18.12Ki ± 0%   48.09Ki ± 0%  +165.42% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/combined-16         17.90Ki ± 1%   48.12Ki ± 0%  +168.78% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/regular-16              18.15Ki ± 0%   45.07Ki ± 0%  +148.34% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/compressed-16           18.15Ki ± 0%   45.07Ki ± 0%  +148.34% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/combined-16             17.92Ki ± 1%   45.11Ki ± 0%  +151.67% (p=0.000 n=10)
geomean                                                          913.5Ki        306.3Ki        -66.47%

                                                            │  old.txt   │              new.txt               │
                                                            │ allocs/op  │ allocs/op   vs base                │
FSTree_GetRange/size=10MB,off=1MB,len=4KB/regular-16          135.0 ± 0%   138.0 ± 0%   +2.22% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/compressed-16       135.0 ± 0%   138.0 ± 0%   +2.22% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/combined-16         140.0 ± 1%   140.5 ± 1%   +0.36% (p=0.038 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/regular-16       142.0 ± 0%   145.0 ± 0%   +2.11% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/compressed-16    142.0 ± 0%   145.0 ± 0%   +2.11% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/combined-16      138.0 ± 1%   140.5 ± 2%        ~ (p=0.063 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/regular-16      139.0 ± 0%   148.0 ± 0%   +6.47% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/compressed-16   139.0 ± 0%   148.0 ± 0%   +6.47% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/combined-16     139.0 ± 2%   139.0 ± 1%        ~ (p=0.773 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/regular-16           135.0 ± 0%   134.0 ± 0%   -0.74% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/compressed-16        135.0 ± 0%   134.0 ± 0%   -0.74% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/combined-16          139.5 ± 2%   140.5 ± 2%   +0.72% (p=0.030 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/regular-16         127.0 ± 0%   141.0 ± 0%  +11.02% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/compressed-16      127.0 ± 0%   141.0 ± 0%  +11.02% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/combined-16        138.0 ± 2%   139.5 ± 1%        ~ (p=0.195 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/regular-16       127.0 ± 0%   144.0 ± 0%  +13.39% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/compressed-16    127.0 ± 0%   144.0 ± 0%  +13.39% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/combined-16      139.0 ± 1%   140.0 ± 2%        ~ (p=0.146 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/regular-16         139.0 ± 0%   129.0 ± 0%   -7.19% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/compressed-16      139.0 ± 0%   129.0 ± 0%   -7.19% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/combined-16        138.0 ± 1%   140.5 ± 1%   +1.81% (p=0.001 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/regular-16       142.0 ± 0%   140.0 ± 0%   -1.41% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/compressed-16    142.0 ± 0%   140.0 ± 0%   -1.41% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/combined-16      137.5 ± 3%   140.0 ± 2%        ~ (p=0.091 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/regular-16           143.0 ± 0%   140.0 ± 0%   -2.10% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/compressed-16        143.0 ± 0%   140.0 ± 0%   -2.10% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/combined-16          138.0 ± 1%   140.5 ± 2%   +1.81% (p=0.030 n=10)
geomean                                                       137.1        139.9        +2.01%
```

Closes #1724.

Signed-off-by: Andrey Butusov <andrey@nspcc.io>
End-rey added a commit that referenced this pull request Jul 7, 2025
Since #3383 and #3431, it is now not necessary to unmarshal the object to get
its payload, and we can read the payload from reader to find the data.

```
goos: linux
goarch: amd64
pkg: github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree
cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
                                                            │    old.txt     │               new.txt                │
                                                            │     sec/op     │    sec/op     vs base                │
FSTree_GetRange/size=10MB,off=1MB,len=4KB/regular-16           8027.9µ ±  9%   264.8µ ±  5%  -96.70% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/compressed-16        7608.3µ ±  5%   270.5µ ±  6%  -96.45% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/combined-16          7391.8µ ±  6%   360.6µ ±  8%  -95.12% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/regular-16         7.876m ±  4%   4.134m ±  3%  -47.52% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/compressed-16      7.989m ±  6%   4.170m ±  3%  -47.80% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/combined-16        7.530m ±  2%   4.038m ±  8%  -46.37% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/regular-16        8.220m ±  6%   4.164m ±  4%  -49.35% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/compressed-16     8.183m ±  6%   4.703m ±  6%  -42.53% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/combined-16       7.508m ±  5%   4.325m ±  5%  -42.40% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/regular-16            822.54µ ±  6%   83.04µ ±  4%  -89.90% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/compressed-16         884.94µ ±  7%   92.61µ ±  5%  -89.53% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/combined-16          1346.99µ ± 11%   84.62µ ± 10%  -93.72% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/regular-16           908.2µ ± 15%   817.8µ ±  9%        ~ (p=0.165 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/compressed-16        946.3µ ±  3%   806.2µ ±  4%  -14.80% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/combined-16         1290.4µ ±  9%   914.6µ ± 11%  -29.12% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/regular-16         955.0µ ±  3%   863.4µ ±  4%   -9.60% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/compressed-16      948.7µ ±  4%   869.5µ ±  5%   -8.35% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/combined-16       1318.8µ ± 13%   955.9µ ±  7%  -27.52% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/regular-16           79.55µ ±  5%   89.11µ ±  2%  +12.01% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/compressed-16        78.48µ ±  5%   87.90µ ±  2%  +12.01% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/combined-16          79.15µ ±  4%   92.59µ ±  3%  +16.98% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/regular-16         81.78µ ±  4%   92.22µ ±  4%  +12.77% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/compressed-16      79.80µ ± 11%   90.99µ ±  3%  +14.02% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/combined-16        92.39µ ±  9%   92.73µ ±  2%        ~ (p=0.280 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/regular-16             92.11µ ±  1%   89.30µ ±  2%   -3.06% (p=0.002 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/compressed-16          80.11µ ± 17%   91.34µ ±  2%        ~ (p=0.105 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/combined-16            79.40µ ±  5%   90.61µ ±  4%  +14.12% (p=0.000 n=10)
geomean                                                         871.6µ         399.9µ        -54.12%

                                                            │     old.txt     │                new.txt                │
                                                            │      B/op       │     B/op      vs base                 │
FSTree_GetRange/size=10MB,off=1MB,len=4KB/regular-16          20495.77Ki ± 0%   43.65Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/compressed-16       20495.77Ki ± 0%   43.65Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/combined-16         20496.00Ki ± 0%   43.81Ki ± 0%   -99.79% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/regular-16          20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/compressed-16       20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/combined-16         20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/regular-16         20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/compressed-16      20.02Mi ± 0%   10.04Mi ± 0%   -49.84% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/combined-16        20.02Mi ± 0%   10.04Mi ± 0%   -49.85% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/regular-16            2063.83Ki ± 0%   43.65Ki ± 0%   -97.89% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/compressed-16         2063.83Ki ± 0%   43.65Ki ± 0%   -97.88% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/combined-16           2063.98Ki ± 0%   43.89Ki ± 0%   -97.87% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/regular-16            2.015Mi ± 0%   1.039Mi ± 0%   -48.45% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/compressed-16         2.015Mi ± 0%   1.039Mi ± 0%   -48.45% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/combined-16           2.016Mi ± 0%   1.039Mi ± 0%   -48.46% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/regular-16          2.015Mi ± 0%   1.039Mi ± 0%   -48.44% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/compressed-16       2.015Mi ± 0%   1.039Mi ± 0%   -48.44% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/combined-16         2.016Mi ± 0%   1.039Mi ± 0%   -48.46% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/regular-16            17.97Ki ± 0%   47.68Ki ± 0%  +165.35% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/compressed-16         17.97Ki ± 0%   47.68Ki ± 0%  +165.35% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/combined-16           17.91Ki ± 0%   48.13Ki ± 0%  +168.71% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/regular-16          18.12Ki ± 0%   48.09Ki ± 0%  +165.42% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/compressed-16       18.12Ki ± 0%   48.09Ki ± 0%  +165.42% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/combined-16         17.90Ki ± 1%   48.12Ki ± 0%  +168.78% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/regular-16              18.15Ki ± 0%   45.07Ki ± 0%  +148.34% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/compressed-16           18.15Ki ± 0%   45.07Ki ± 0%  +148.34% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/combined-16             17.92Ki ± 1%   45.11Ki ± 0%  +151.67% (p=0.000 n=10)
geomean                                                          913.5Ki        306.3Ki        -66.47%

                                                            │  old.txt   │              new.txt               │
                                                            │ allocs/op  │ allocs/op   vs base                │
FSTree_GetRange/size=10MB,off=1MB,len=4KB/regular-16          135.0 ± 0%   138.0 ± 0%   +2.22% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/compressed-16       135.0 ± 0%   138.0 ± 0%   +2.22% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=1MB,len=4KB/combined-16         140.0 ± 1%   140.5 ± 1%   +0.36% (p=0.038 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/regular-16       142.0 ± 0%   145.0 ± 0%   +2.11% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/compressed-16    142.0 ± 0%   145.0 ± 0%   +2.11% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=10MB/combined-16      138.0 ± 1%   140.5 ± 2%        ~ (p=0.063 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/regular-16      139.0 ± 0%   148.0 ± 0%   +6.47% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/compressed-16   139.0 ± 0%   148.0 ± 0%   +6.47% (p=0.000 n=10)
FSTree_GetRange/size=10MB,off=Empty,len=Empty/combined-16     139.0 ± 2%   139.0 ± 1%        ~ (p=0.773 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/regular-16           135.0 ± 0%   134.0 ± 0%   -0.74% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/compressed-16        135.0 ± 0%   134.0 ± 0%   -0.74% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=1KB,len=4KB/combined-16          139.5 ± 2%   140.5 ± 2%   +0.72% (p=0.030 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/regular-16         127.0 ± 0%   141.0 ± 0%  +11.02% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/compressed-16      127.0 ± 0%   141.0 ± 0%  +11.02% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=1MB/combined-16        138.0 ± 2%   139.5 ± 1%        ~ (p=0.195 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/regular-16       127.0 ± 0%   144.0 ± 0%  +13.39% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/compressed-16    127.0 ± 0%   144.0 ± 0%  +13.39% (p=0.000 n=10)
FSTree_GetRange/size=1MB,off=Empty,len=Empty/combined-16      139.0 ± 1%   140.0 ± 2%        ~ (p=0.146 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/regular-16         139.0 ± 0%   129.0 ± 0%   -7.19% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/compressed-16      139.0 ± 0%   129.0 ± 0%   -7.19% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=4KB/combined-16        138.0 ± 1%   140.5 ± 1%   +1.81% (p=0.001 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/regular-16       142.0 ± 0%   140.0 ± 0%   -1.41% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/compressed-16    142.0 ± 0%   140.0 ± 0%   -1.41% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=Empty,len=Empty/combined-16      137.5 ± 3%   140.0 ± 2%        ~ (p=0.091 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/regular-16           143.0 ± 0%   140.0 ± 0%   -2.10% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/compressed-16        143.0 ± 0%   140.0 ± 0%   -2.10% (p=0.000 n=10)
FSTree_GetRange/size=4KB,off=1KB,len=1KB/combined-16          138.0 ± 1%   140.5 ± 2%   +1.81% (p=0.030 n=10)
geomean                                                       137.1        139.9        +2.01%
```

Closes #1724.

Signed-off-by: Andrey Butusov <andrey@nspcc.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replication does not occur when the disk fails without load, since there is object's information in the meta

4 participants