[#1680] replicator: Consider `NODE_UNDER_MAINTENANCE` as OK

Node response with `NODE_UNDER_MAINTENANCE` status signals that the node
was switched to maintenance mode. There is a delay between the actual
switch and the reflection in the network map of up to one epoch. To
speed up the reaction to the maintenance, it is required to recognize
such node responses in the Policer.

Make `Policer.processNodes` to exclude elements with shortage decreasing
on `NODE_UNDER_MAINTENANCE` status response.

Signed-off-by: Leonard Lyubich <ctulhurider@gmail.com>
support/v0.34
Leonard Lyubich 2022-10-10 17:53:26 +04:00 committed by fyrchik
parent e99e25b52f
commit 050ad2762c
1 changed files with 30 additions and 1 deletions

View File

@ -3,12 +3,14 @@ package policer
import (
"context"
"encoding/hex"
"errors"
"github.com/nspcc-dev/neofs-node/pkg/core/container"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine"
headsvc "github.com/nspcc-dev/neofs-node/pkg/services/object/head"
"github.com/nspcc-dev/neofs-node/pkg/services/replicator"
"github.com/nspcc-dev/neofs-sdk-go/client"
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"go.uber.org/zap"
@ -191,7 +193,9 @@ func (p *Policer) processNodes(ctx *processPlacementContext, addr oid.Address,
continue
}
if err != nil {
if isClientErrMaintenance(err) {
handleMaintenance(nodes[i])
} else if err != nil {
p.log.Error("receive object header to check policy compliance",
zap.Stringer("object", addr),
zap.String("error", err.Error()),
@ -220,3 +224,28 @@ func (p *Policer) processNodes(ctx *processPlacementContext, addr oid.Address,
p.replicator.HandleTask(ctx, task, checkedNodes)
}
}
// isClientErrMaintenance checks if err corresponds to NeoFS status return
// which tells that node is currently under maintenance. Supports wrapped
// errors.
//
// Similar to client.IsErr___ errors, consider replacing to NeoFS SDK.
func isClientErrMaintenance(err error) bool {
switch unwrapErr(err).(type) {
default:
return false
case
apistatus.NodeUnderMaintenance,
*apistatus.NodeUnderMaintenance:
return true
}
}
// unwrapErr unwraps error using errors.Unwrap.
func unwrapErr(err error) error {
for e := errors.Unwrap(err); e != nil; e = errors.Unwrap(err) {
err = e
}
return err
}