[#778] services/object: Return the composite error of PUT operation

In previous implementation Object service's handler returned const error in
case of failure (full or partial) of PUT operation. This did not even allow
us to roughly guess what the reason is. Not as a complete solution, but to
alleviate some cases where all nodes in a container return the same error,
it is suggested to return the error of the last server that responded.

Return latest server error from placement loop of `iteratePlacement` method
of `distributedTarget` type.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2021-09-09 02:13:55 +03:00 committed by Alex Vanin
parent 5f86d54721
commit 02f2a98bcc

View file

@ -4,6 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"sync" "sync"
"sync/atomic"
"github.com/nspcc-dev/neofs-node/pkg/core/object" "github.com/nspcc-dev/neofs-node/pkg/core/object"
svcutil "github.com/nspcc-dev/neofs-node/pkg/services/object/util" svcutil "github.com/nspcc-dev/neofs-node/pkg/services/object/util"
@ -93,6 +94,8 @@ func (t *distributedTarget) iteratePlacement(f func(placement.Node) error) (*tra
return nil, fmt.Errorf("(%T) could not create object placement traverser: %w", t, err) return nil, fmt.Errorf("(%T) could not create object placement traverser: %w", t, err)
} }
var resErr atomic.Value
loop: loop:
for { for {
addrs := traverser.Next() addrs := traverser.Next()
@ -110,6 +113,7 @@ loop:
defer wg.Done() defer wg.Done()
if err := f(addr); err != nil { if err := f(addr); err != nil {
resErr.Store(err)
svcutil.LogServiceError(t.log, "PUT", addr.Addresses(), err) svcutil.LogServiceError(t.log, "PUT", addr.Addresses(), err)
return return
} }
@ -128,6 +132,10 @@ loop:
} }
if !traverser.Success() { if !traverser.Success() {
if err, ok := resErr.Load().(error); ok {
return nil, err
}
return nil, errIncompletePut return nil, errIncompletePut
} }