@@ -5,8 +5,11 @@ import (
55 "errors"
66 "fmt"
77
8+ iec "github.com/nspcc-dev/neofs-node/internal/ec"
9+ "github.com/nspcc-dev/neofs-node/pkg/network"
810 "github.com/nspcc-dev/neofs-node/pkg/util"
911 apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
12+ netmapsdk "github.com/nspcc-dev/neofs-sdk-go/netmap"
1013 "github.com/nspcc-dev/neofs-sdk-go/object"
1114 "go.uber.org/zap"
1215)
@@ -66,6 +69,10 @@ func (s *Service) GetRange(ctx context.Context, prm RangePrm) error {
6669 return s .copyLocalECPartRange (prm .objWriter , prm .addr .Container (), prm .addr .Object (), pi , prm .rng .GetOffset (), prm .rng .GetLength ())
6770 }
6871
72+ return s .getRange (ctx , prm , nodeLists , repRules , ecRules )
73+ }
74+
75+ func (s * Service ) getRange (ctx context.Context , prm RangePrm , nodeLists [][]netmapsdk.NodeInfo , repRules []uint , ecRules []iec.Rule ) error {
6976 if len (repRules ) > 0 { // REP format does not require encoding
7077 err := s .get (ctx , prm .commonPrm , withPreSortedContainerNodes (nodeLists [:len (repRules )], repRules ), withPayloadRange (prm .rng )).err
7178 if len (ecRules ) == 0 || ! errors .Is (err , apistatus .ErrObjectNotFound ) {
@@ -78,6 +85,15 @@ func (s *Service) GetRange(ctx context.Context, prm RangePrm) error {
7885}
7986
8087func (s * Service ) GetRangeHash (ctx context.Context , prm RangeHashPrm ) (* RangeHashRes , error ) {
88+ nodeLists , repRules , ecRules , err := s .neoFSNet .GetNodesForObject (prm .addr )
89+ if err != nil {
90+ return nil , fmt .Errorf ("get nodes for object: %w" , err )
91+ }
92+
93+ if prm .common .SessionToken () == nil && prm .rangeForwarder != nil && ! localNodeInSets (s .neoFSNet , nodeLists ) {
94+ return s .proxyHashRequest (ctx , nodeLists , prm .rangeForwarder )
95+ }
96+
8197 hashes := make ([][]byte , 0 , len (prm .rngs ))
8298
8399 for _ , rng := range prm .rngs {
@@ -97,17 +113,10 @@ func (s *Service) GetRangeHash(ctx context.Context, prm RangeHashPrm) (*RangeHas
97113 hash : util .NewSaltingWriter (h , prm .salt ),
98114 })
99115
100- if err := s .get (ctx , rngPrm . commonPrm , withHash ( & prm ), withPayloadRange ( rngPrm . rng )). err ; err != nil {
116+ if err := s .getRange (ctx , rngPrm , nodeLists , repRules , ecRules ) ; err != nil {
101117 return nil , err
102118 }
103119
104- if prm .forwardedRangeHashResponse != nil {
105- // forwarder request case; no need to collect the other
106- // parts, the whole response has already been received
107- hashes = prm .forwardedRangeHashResponse
108- break
109- }
110-
111120 hashes = append (hashes , h .Sum (nil ))
112121 }
113122
@@ -116,6 +125,34 @@ func (s *Service) GetRangeHash(ctx context.Context, prm RangeHashPrm) (*RangeHas
116125 }, nil
117126}
118127
128+ func (s * Service ) proxyHashRequest (ctx context.Context , sortedNodeLists [][]netmapsdk.NodeInfo , proxyFn RangeRequestForwarder ) (* RangeHashRes , error ) {
129+ for i := range sortedNodeLists {
130+ for j := range sortedNodeLists [i ] {
131+ conn , node , err := s .conns .(* clientCacheWrapper )._connect (sortedNodeLists [i ][j ])
132+ if err != nil {
133+ // TODO: implement address list stringer for lazy encoding
134+ s .log .Debug ("get conn to remote node" ,
135+ zap .String ("addresses" , network .StringifyGroup (node .AddressGroup ())), zap .Error (err ))
136+ continue
137+ }
138+
139+ hashes , err := proxyFn (ctx , node , conn )
140+ if err == nil {
141+ return & RangeHashRes {hashes : hashes }, nil
142+ }
143+
144+ if errors .Is (err , apistatus .ErrObjectAlreadyRemoved ) || errors .Is (err , apistatus .ErrObjectAccessDenied ) ||
145+ errors .Is (err , apistatus .ErrObjectOutOfRange ) || errors .Is (err , ctx .Err ()) {
146+ return nil , err
147+ }
148+
149+ s .log .Debug ("HASH proxy failed" , zap .Error (err ))
150+ }
151+ }
152+
153+ return nil , apistatus .ErrObjectNotFound
154+ }
155+
119156// Head reads object header from container.
120157//
121158// Returns ErrNotFound if the header was not received for the call.
0 commit comments