From bcbdaf11d1eca7f945d1bb9c12870f1bc4c9a01a Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Fri, 30 Jan 2026 16:34:36 +0300 Subject: [PATCH 1/2] engine: don't base58/hash shard IDs 1. base58 adds noticeable performance penalty and allocates. 2. There is no value added by hashing them, they're already random UUIDs. 3. As long as they're different hrw is ok. Signed-off-by: Roman Khimov --- pkg/local_object_storage/engine/shards.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/local_object_storage/engine/shards.go b/pkg/local_object_storage/engine/shards.go index 4cc2a3a374..dfb10ecfa4 100644 --- a/pkg/local_object_storage/engine/shards.go +++ b/pkg/local_object_storage/engine/shards.go @@ -1,6 +1,7 @@ package engine import ( + "encoding/binary" "fmt" "sync/atomic" @@ -256,7 +257,5 @@ func (e *StorageEngine) HandleNewEpoch(epoch uint64) { } func (s shardWrapper) Hash() uint64 { - return hrw.Hash( - []byte(s.Shard.ID().String()), - ) + return binary.BigEndian.Uint64(*s.ID()) } From 7823814bbb89982bd6b02e7f489b1c6342365e66 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Fri, 30 Jan 2026 16:46:02 +0300 Subject: [PATCH 2/2] engine: don't base58/hash addresses for hrw.Sort 1. base58 allocates and spends some CPU cycles for something we don't need. 2. OID is a hash already, unique for each object, hashing it again adds no value. Signed-off-by: Roman Khimov --- CHANGELOG.md | 1 + pkg/local_object_storage/engine/evacuate.go | 2 +- pkg/local_object_storage/engine/shards.go | 8 +++++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf4f2a4e27..a37b690dc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ Changelog for NeoFS Node - Garbage marking scheme in metabase (#3753) - SN sorts shards identically when writing and reading EC parts (#3773) - SN puts EC parts concurrently now (#3777) +- Optimized object-to-shard placement (#3794) ### Removed - Deprecated `fschain_autodeploy`, `without_mainnet`, `governance.disable`, `fee.main_chain` and `contracts` IR config options (#3716) diff --git a/pkg/local_object_storage/engine/evacuate.go b/pkg/local_object_storage/engine/evacuate.go index 5af0cc75e9..491a0ed6ed 100644 --- a/pkg/local_object_storage/engine/evacuate.go +++ b/pkg/local_object_storage/engine/evacuate.go @@ -100,7 +100,7 @@ mainLoop: loop: for i := range lst { addr := lst[i].Address - addrHash := hrw.WrapBytes([]byte(addr.EncodeToString())) + addrHash := hrwOIDWrapper(addr.Object()) obj, err := sh.Get(addr, false) if err != nil { diff --git a/pkg/local_object_storage/engine/shards.go b/pkg/local_object_storage/engine/shards.go index dfb10ecfa4..5687ad588a 100644 --- a/pkg/local_object_storage/engine/shards.go +++ b/pkg/local_object_storage/engine/shards.go @@ -192,7 +192,7 @@ func generateShardID() (*shard.ID, error) { func (e *StorageEngine) sortedShards(objAddr oid.Address) []shardWrapper { shards := e.unsortedShards() - hrw.Sort(shards, hrw.WrapBytes([]byte(objAddr.EncodeToString()))) + hrw.Sort(shards, hrwOIDWrapper(objAddr.Object())) for i := range shards { shards[i].shardIface = shards[i].Shard @@ -259,3 +259,9 @@ func (e *StorageEngine) HandleNewEpoch(epoch uint64) { func (s shardWrapper) Hash() uint64 { return binary.BigEndian.Uint64(*s.ID()) } + +type hrwOIDWrapper oid.ID + +func (o hrwOIDWrapper) Hash() uint64 { + return binary.BigEndian.Uint64(o[:]) +}