forked from TrueCloudLab/frostfs-node
[#2047] node: Do not send chunk twice on request forwarding
That could happen if a node forwards request to a node that closed the connection during the original object stream. Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
parent
bd25db5d4a
commit
d54022eacc
2 changed files with 50 additions and 5 deletions
|
@ -48,6 +48,7 @@ Changelog for NeoFS Node
|
||||||
- Making notary deposits with a zero GAS balance (#2080)
|
- Making notary deposits with a zero GAS balance (#2080)
|
||||||
- Notary requests on shutdown (#2075)
|
- Notary requests on shutdown (#2075)
|
||||||
- `neofs-cli container create ` check the sufficiency of the number of nodes in the selector for replicas (#2038)
|
- `neofs-cli container create ` check the sufficiency of the number of nodes in the selector for replicas (#2038)
|
||||||
|
- Data duplication during request forwarding (#2047)
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- `-g` option from `neofs-cli control ...` and `neofs-cli container create` commands (#2089)
|
- `-g` option from `neofs-cli control ...` and `neofs-cli container create` commands (#2089)
|
||||||
|
|
|
@ -66,6 +66,9 @@ func (s *Service) toPrm(req *objectV2.GetRequest, stream objectSvc.GetObjectStre
|
||||||
if !commonPrm.LocalOnly() {
|
if !commonPrm.LocalOnly() {
|
||||||
var onceResign sync.Once
|
var onceResign sync.Once
|
||||||
|
|
||||||
|
var onceHeaderSending sync.Once
|
||||||
|
var globalProgress int
|
||||||
|
|
||||||
p.SetRequestForwarder(groupAddressRequestForwarder(func(addr network.Address, c client.MultiAddressClient, pubkey []byte) (*object.Object, error) {
|
p.SetRequestForwarder(groupAddressRequestForwarder(func(addr network.Address, c client.MultiAddressClient, pubkey []byte) (*object.Object, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -108,6 +111,7 @@ func (s *Service) toPrm(req *objectV2.GetRequest, stream objectSvc.GetObjectStre
|
||||||
var (
|
var (
|
||||||
headWas bool
|
headWas bool
|
||||||
resp = new(objectV2.GetResponse)
|
resp = new(objectV2.GetResponse)
|
||||||
|
localProgress int
|
||||||
)
|
)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
@ -155,7 +159,10 @@ func (s *Service) toPrm(req *objectV2.GetRequest, stream objectSvc.GetObjectStre
|
||||||
obj.SetSignature(v.GetSignature())
|
obj.SetSignature(v.GetSignature())
|
||||||
obj.SetHeader(v.GetHeader())
|
obj.SetHeader(v.GetHeader())
|
||||||
|
|
||||||
if err = streamWrapper.WriteHeader(object.NewFromV2(obj)); err != nil {
|
onceHeaderSending.Do(func() {
|
||||||
|
err = streamWrapper.WriteHeader(object.NewFromV2(obj))
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not write object header in Get forwarder: %w", err)
|
return nil, fmt.Errorf("could not write object header in Get forwarder: %w", err)
|
||||||
}
|
}
|
||||||
case *objectV2.GetObjectPartChunk:
|
case *objectV2.GetObjectPartChunk:
|
||||||
|
@ -163,9 +170,20 @@ func (s *Service) toPrm(req *objectV2.GetRequest, stream objectSvc.GetObjectStre
|
||||||
return nil, errWrongMessageSeq
|
return nil, errWrongMessageSeq
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = streamWrapper.WriteChunk(v.GetChunk()); err != nil {
|
origChunk := v.GetChunk()
|
||||||
|
|
||||||
|
chunk := chunkToSend(globalProgress, localProgress, origChunk)
|
||||||
|
if len(chunk) == 0 {
|
||||||
|
localProgress += len(origChunk)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = streamWrapper.WriteChunk(chunk); err != nil {
|
||||||
return nil, fmt.Errorf("could not write object chunk in Get forwarder: %w", err)
|
return nil, fmt.Errorf("could not write object chunk in Get forwarder: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
localProgress += len(origChunk)
|
||||||
|
globalProgress += len(chunk)
|
||||||
case *objectV2.SplitInfo:
|
case *objectV2.SplitInfo:
|
||||||
si := object.NewSplitInfoFromV2(v)
|
si := object.NewSplitInfoFromV2(v)
|
||||||
return nil, object.NewSplitInfoError(si)
|
return nil, object.NewSplitInfoError(si)
|
||||||
|
@ -213,6 +231,7 @@ func (s *Service) toRangePrm(req *objectV2.GetRangeRequest, stream objectSvc.Get
|
||||||
|
|
||||||
if !commonPrm.LocalOnly() {
|
if !commonPrm.LocalOnly() {
|
||||||
var onceResign sync.Once
|
var onceResign sync.Once
|
||||||
|
var globalProgress int
|
||||||
|
|
||||||
key, err := s.keyStorage.GetKey(nil)
|
key, err := s.keyStorage.GetKey(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -254,6 +273,7 @@ func (s *Service) toRangePrm(req *objectV2.GetRangeRequest, stream objectSvc.Get
|
||||||
}
|
}
|
||||||
|
|
||||||
resp := new(objectV2.GetRangeResponse)
|
resp := new(objectV2.GetRangeResponse)
|
||||||
|
var localProgress int
|
||||||
|
|
||||||
for {
|
for {
|
||||||
// receive message from server stream
|
// receive message from server stream
|
||||||
|
@ -284,9 +304,20 @@ func (s *Service) toRangePrm(req *objectV2.GetRangeRequest, stream objectSvc.Get
|
||||||
case nil:
|
case nil:
|
||||||
return nil, fmt.Errorf("unexpected range type %T", v)
|
return nil, fmt.Errorf("unexpected range type %T", v)
|
||||||
case *objectV2.GetRangePartChunk:
|
case *objectV2.GetRangePartChunk:
|
||||||
if err = streamWrapper.WriteChunk(v.GetChunk()); err != nil {
|
origChunk := v.GetChunk()
|
||||||
|
|
||||||
|
chunk := chunkToSend(globalProgress, localProgress, origChunk)
|
||||||
|
if len(chunk) == 0 {
|
||||||
|
localProgress += len(origChunk)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = streamWrapper.WriteChunk(chunk); err != nil {
|
||||||
return nil, fmt.Errorf("could not write object chunk in GetRange forwarder: %w", err)
|
return nil, fmt.Errorf("could not write object chunk in GetRange forwarder: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
localProgress += len(origChunk)
|
||||||
|
globalProgress += len(chunk)
|
||||||
case *objectV2.SplitInfo:
|
case *objectV2.SplitInfo:
|
||||||
si := object.NewSplitInfoFromV2(v)
|
si := object.NewSplitInfoFromV2(v)
|
||||||
|
|
||||||
|
@ -646,3 +677,16 @@ func checkStatus(stV2 *status.Status) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func chunkToSend(global, local int, chunk []byte) []byte {
|
||||||
|
if global == local {
|
||||||
|
return chunk
|
||||||
|
}
|
||||||
|
|
||||||
|
if local+len(chunk) <= global {
|
||||||
|
// chunk has already been sent
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunk[global-local:]
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue