55 "errors"
66 "fmt"
77
8+ iec "github.com/nspcc-dev/neofs-node/internal/ec"
89 "github.com/nspcc-dev/neofs-node/pkg/network"
910 "github.com/nspcc-dev/neofs-node/pkg/services/object/internal"
1011 "github.com/nspcc-dev/neofs-node/pkg/util"
@@ -106,14 +107,27 @@ func (s *Service) GetRange(ctx context.Context, prm RangePrm) error {
106107 return s .copyLocalECPartRange (prm .objWriter , prm .addr .Container (), prm .addr .Object (), pi , prm .rng .GetOffset (), prm .rng .GetLength ())
107108 }
108109
110+ return s .getRange (ctx , prm , nodeLists , repRules , ecRules , nil )
111+ }
112+
113+ func (s * Service ) getRange (ctx context.Context , prm RangePrm , nodeLists [][]netmap.NodeInfo , repRules []uint , ecRules []iec.Rule ,
114+ hashPrm * RangeHashPrm ) error {
109115 if len (repRules ) > 0 { // REP format does not require encoding
110- err := s .get (ctx , prm .commonPrm , withPreSortedContainerNodes (nodeLists [:len (repRules )], repRules ), withPayloadRange (prm .rng )).err
116+ err := s .get (ctx , prm .commonPrm , withPreSortedContainerNodes (nodeLists [:len (repRules )], repRules ), withPayloadRange (prm .rng ), withHash ( hashPrm ) ).err
111117 if len (ecRules ) == 0 || ! errors .Is (err , apistatus .ErrObjectNotFound ) {
112118 return err
113119 }
114120 }
115121
116122 ecNodeLists := nodeLists [len (repRules ):]
123+ if hashPrm != nil && prm .rangeForwarder != nil && ! localNodeInSets (s .neoFSNet , nodeLists ) {
124+ hashes , err := s .proxyHashRequest (ctx , ecNodeLists , prm .rangeForwarder )
125+ if err == nil {
126+ hashPrm .forwardedRangeHashResponse = hashes
127+ }
128+ return err
129+ }
130+
117131 if prm .forwarder != nil && ! localNodeInSets (s .neoFSNet , ecNodeLists ) {
118132 return s .proxyGetRequest (ctx , ecNodeLists , prm .forwarder , "RANGE" , nil )
119133 }
@@ -123,6 +137,11 @@ func (s *Service) GetRange(ctx context.Context, prm RangePrm) error {
123137}
124138
125139func (s * Service ) GetRangeHash (ctx context.Context , prm RangeHashPrm ) (* RangeHashRes , error ) {
140+ nodeLists , repRules , ecRules , err := s .neoFSNet .GetNodesForObject (prm .addr )
141+ if err != nil {
142+ return nil , fmt .Errorf ("get nodes for object: %w" , err )
143+ }
144+
126145 hashes := make ([][]byte , 0 , len (prm .rngs ))
127146
128147 for _ , rng := range prm .rngs {
@@ -142,7 +161,7 @@ func (s *Service) GetRangeHash(ctx context.Context, prm RangeHashPrm) (*RangeHas
142161 hash : util .NewSaltingWriter (h , prm .salt ),
143162 })
144163
145- if err := s .get (ctx , rngPrm . commonPrm , withHash ( & prm ), withPayloadRange ( rngPrm . rng )). err ; err != nil {
164+ if err := s .getRange (ctx , rngPrm , nodeLists , repRules , ecRules , & prm ); err != nil {
146165 return nil , err
147166 }
148167
@@ -161,6 +180,34 @@ func (s *Service) GetRangeHash(ctx context.Context, prm RangeHashPrm) (*RangeHas
161180 }, nil
162181}
163182
183+ func (s * Service ) proxyHashRequest (ctx context.Context , sortedNodeLists [][]netmap.NodeInfo , proxyFn RangeRequestForwarder ) ([][]byte , error ) {
184+ for i := range sortedNodeLists {
185+ for j := range sortedNodeLists [i ] {
186+ conn , node , err := s .conns .(* clientCacheWrapper )._connect (sortedNodeLists [i ][j ])
187+ if err != nil {
188+ // TODO: implement address list stringer for lazy encoding
189+ s .log .Debug ("get conn to remote node" ,
190+ zap .String ("addresses" , network .StringifyGroup (node .AddressGroup ())), zap .Error (err ))
191+ continue
192+ }
193+
194+ hashes , err := proxyFn (ctx , node , conn )
195+ if err == nil {
196+ return hashes , nil
197+ }
198+
199+ if errors .Is (err , apistatus .ErrObjectAlreadyRemoved ) || errors .Is (err , apistatus .ErrObjectAccessDenied ) ||
200+ errors .Is (err , apistatus .ErrObjectOutOfRange ) || errors .Is (err , ctx .Err ()) {
201+ return nil , err
202+ }
203+
204+ s .log .Info ("request proxy failed" , zap .String ("request" , "HASH" ), zap .Error (err ))
205+ }
206+ }
207+
208+ return nil , apistatus .ErrObjectNotFound
209+ }
210+
164211// Head reads object header from container.
165212//
166213// Returns ErrNotFound if the header was not received for the call.
0 commit comments