2020-10-21 09:24:02 +00:00
|
|
|
package policer
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2022-05-30 05:24:45 +00:00
|
|
|
"errors"
|
2020-10-21 09:24:02 +00:00
|
|
|
|
2021-10-16 11:21:03 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine"
|
2020-10-21 09:24:02 +00:00
|
|
|
headsvc "github.com/nspcc-dev/neofs-node/pkg/services/object/head"
|
2020-10-21 11:50:48 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/services/replicator"
|
2022-05-20 11:31:55 +00:00
|
|
|
"github.com/nspcc-dev/neofs-sdk-go/client"
|
2021-11-10 07:08:33 +00:00
|
|
|
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
2022-05-31 17:00:41 +00:00
|
|
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
2020-10-21 09:24:02 +00:00
|
|
|
"go.uber.org/zap"
|
|
|
|
)
|
|
|
|
|
2022-06-09 19:11:35 +00:00
|
|
|
type nodeCache map[uint64]bool
|
|
|
|
|
|
|
|
func (n nodeCache) SubmitSuccessfulReplication(id uint64) {
|
|
|
|
n[id] = true
|
|
|
|
}
|
|
|
|
|
2022-05-31 17:00:41 +00:00
|
|
|
func (p *Policer) processObject(ctx context.Context, addr oid.Address) {
|
|
|
|
idCnr := addr.Container()
|
2022-05-12 16:37:46 +00:00
|
|
|
|
2022-05-31 17:00:41 +00:00
|
|
|
cnr, err := p.cnrSrc.Get(idCnr)
|
2020-10-21 09:24:02 +00:00
|
|
|
if err != nil {
|
|
|
|
p.log.Error("could not get container",
|
2022-05-12 16:37:46 +00:00
|
|
|
zap.Stringer("cid", idCnr),
|
2020-10-21 09:24:02 +00:00
|
|
|
zap.String("error", err.Error()),
|
|
|
|
)
|
2022-03-17 08:17:45 +00:00
|
|
|
if container.IsErrNotFound(err) {
|
2022-05-23 13:12:32 +00:00
|
|
|
var prm engine.InhumePrm
|
2021-10-16 11:21:03 +00:00
|
|
|
prm.MarkAsGarbage(addr)
|
|
|
|
_, err := p.jobQueue.localStorage.Inhume(prm)
|
|
|
|
if err != nil {
|
|
|
|
p.log.Error("could not inhume object with missing container",
|
2022-05-12 16:37:46 +00:00
|
|
|
zap.Stringer("cid", idCnr),
|
2022-05-31 17:00:41 +00:00
|
|
|
zap.Stringer("oid", addr.Object()),
|
2021-10-16 11:21:03 +00:00
|
|
|
zap.String("error", err.Error()))
|
|
|
|
}
|
|
|
|
}
|
2020-10-21 09:24:02 +00:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-11-16 09:43:52 +00:00
|
|
|
policy := cnr.PlacementPolicy()
|
2022-06-08 23:18:26 +00:00
|
|
|
if policy == nil {
|
|
|
|
p.log.Error("missing placement policy in container",
|
|
|
|
zap.Stringer("cid", idCnr),
|
|
|
|
)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-05-31 17:00:41 +00:00
|
|
|
obj := addr.Object()
|
2020-10-21 09:24:02 +00:00
|
|
|
|
2022-06-08 23:18:26 +00:00
|
|
|
nn, err := p.placementBuilder.BuildPlacement(idCnr, &obj, *policy)
|
2020-10-21 09:24:02 +00:00
|
|
|
if err != nil {
|
|
|
|
p.log.Error("could not build placement vector for object",
|
|
|
|
zap.String("error", err.Error()),
|
|
|
|
)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-05-20 11:31:55 +00:00
|
|
|
c := &processPlacementContext{
|
|
|
|
Context: ctx,
|
|
|
|
}
|
2020-10-21 09:24:02 +00:00
|
|
|
|
2022-06-09 19:11:35 +00:00
|
|
|
var numOfContainerNodes int
|
|
|
|
for i := range nn {
|
|
|
|
numOfContainerNodes += len(nn[i])
|
|
|
|
}
|
|
|
|
|
|
|
|
// cached info about already checked nodes
|
|
|
|
var checkedNodes nodeCache = make(map[uint64]bool, numOfContainerNodes)
|
|
|
|
|
2020-10-21 09:24:02 +00:00
|
|
|
for i := range nn {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
|
2022-06-08 23:18:26 +00:00
|
|
|
p.processNodes(c, addr, nn[i], policy.ReplicaNumberByIndex(i), checkedNodes)
|
2022-05-20 11:31:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if !c.needLocalCopy {
|
|
|
|
p.log.Info("redundant local object copy detected",
|
|
|
|
zap.Stringer("object", addr),
|
|
|
|
)
|
|
|
|
|
|
|
|
p.cbRedundantCopy(addr)
|
2020-10-21 09:24:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-20 11:31:55 +00:00
|
|
|
type processPlacementContext struct {
|
|
|
|
context.Context
|
|
|
|
|
|
|
|
needLocalCopy bool
|
|
|
|
}
|
|
|
|
|
2022-06-09 19:11:35 +00:00
|
|
|
func (p *Policer) processNodes(ctx *processPlacementContext, addr oid.Address,
|
2022-06-08 23:18:26 +00:00
|
|
|
nodes []netmap.NodeInfo, shortage uint32, checkedNodes nodeCache) {
|
2020-10-21 09:24:02 +00:00
|
|
|
prm := new(headsvc.RemoteHeadPrm).WithObjectAddress(addr)
|
|
|
|
|
2022-05-20 11:31:55 +00:00
|
|
|
for i := 0; shortage > 0 && i < len(nodes); i++ {
|
2020-10-21 09:24:02 +00:00
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
|
2021-09-06 12:17:14 +00:00
|
|
|
if p.netmapKeys.IsLocalKey(nodes[i].PublicKey()) {
|
2022-05-20 11:31:55 +00:00
|
|
|
ctx.needLocalCopy = true
|
|
|
|
|
|
|
|
shortage--
|
2022-05-30 05:19:59 +00:00
|
|
|
} else {
|
2022-06-08 23:18:26 +00:00
|
|
|
nodeID := nodes[i].Hash()
|
|
|
|
if hasReplica, checked := checkedNodes[nodeID]; checked {
|
2022-06-09 19:11:35 +00:00
|
|
|
if hasReplica {
|
|
|
|
// node already contains replica, no need to replicate
|
|
|
|
nodes = append(nodes[:i], nodes[i+1:]...)
|
|
|
|
i--
|
|
|
|
shortage--
|
|
|
|
}
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2022-05-30 05:19:59 +00:00
|
|
|
callCtx, cancel := context.WithTimeout(ctx, p.headTimeout)
|
2022-05-20 11:31:55 +00:00
|
|
|
|
2022-06-08 23:18:26 +00:00
|
|
|
_, err := p.remoteHeader.Head(callCtx, prm.WithNodeInfo(nodes[i]))
|
2020-10-21 09:24:02 +00:00
|
|
|
|
2022-05-30 05:19:59 +00:00
|
|
|
cancel()
|
2020-10-21 09:24:02 +00:00
|
|
|
|
2022-05-30 05:24:45 +00:00
|
|
|
// client.IsErrObjectNotFound doesn't support wrapped errors, so unwrap it
|
|
|
|
for wErr := errors.Unwrap(err); wErr != nil; wErr = errors.Unwrap(err) {
|
|
|
|
err = wErr
|
|
|
|
}
|
|
|
|
|
2022-05-30 05:19:59 +00:00
|
|
|
if client.IsErrObjectNotFound(err) {
|
2022-06-08 23:18:26 +00:00
|
|
|
checkedNodes[nodeID] = false
|
2022-05-30 05:19:59 +00:00
|
|
|
continue
|
|
|
|
}
|
2022-05-20 11:31:55 +00:00
|
|
|
|
2020-10-21 09:24:02 +00:00
|
|
|
if err != nil {
|
2022-06-02 17:20:27 +00:00
|
|
|
p.log.Error("receive object header to check policy compliance",
|
|
|
|
zap.Stringer("object", addr),
|
2022-05-20 11:31:55 +00:00
|
|
|
zap.String("error", err.Error()),
|
|
|
|
)
|
2020-10-21 09:24:02 +00:00
|
|
|
} else {
|
|
|
|
shortage--
|
2022-06-08 23:18:26 +00:00
|
|
|
checkedNodes[nodeID] = true
|
2020-10-21 09:24:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nodes = append(nodes[:i], nodes[i+1:]...)
|
|
|
|
i--
|
|
|
|
}
|
|
|
|
|
|
|
|
if shortage > 0 {
|
2022-06-02 17:20:27 +00:00
|
|
|
p.log.Debug("shortage of object copies detected",
|
|
|
|
zap.Stringer("object", addr),
|
2020-10-21 09:24:02 +00:00
|
|
|
zap.Uint32("shortage", shortage),
|
|
|
|
)
|
2020-10-21 11:50:48 +00:00
|
|
|
|
2021-11-10 11:47:52 +00:00
|
|
|
p.replicator.HandleTask(ctx, new(replicator.Task).
|
2020-10-21 11:50:48 +00:00
|
|
|
WithObjectAddress(addr).
|
|
|
|
WithNodes(nodes).
|
|
|
|
WithCopiesNumber(shortage),
|
2022-06-09 19:11:35 +00:00
|
|
|
checkedNodes,
|
2020-10-21 11:50:48 +00:00
|
|
|
)
|
2020-10-21 09:24:02 +00:00
|
|
|
}
|
|
|
|
}
|