2020-07-24 13:54:03 +00:00
|
|
|
package placement
|
2020-07-10 14:17:51 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
|
|
|
"github.com/multiformats/go-multiaddr"
|
|
|
|
"github.com/nspcc-dev/neofs-api-go/container"
|
|
|
|
"github.com/nspcc-dev/neofs-api-go/object"
|
|
|
|
"github.com/nspcc-dev/neofs-api-go/refs"
|
2020-07-24 13:54:03 +00:00
|
|
|
netmapcore "github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
|
|
|
"github.com/nspcc-dev/netmap"
|
2020-07-10 14:17:51 +00:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
"google.golang.org/grpc/status"
|
|
|
|
)
|
|
|
|
|
|
|
|
/*
|
|
|
|
File source code includes implementations of placement-related solutions.
|
|
|
|
Highly specialized interfaces give the opportunity to hide placement implementation in a black box for the reasons:
|
|
|
|
* placement is implementation-tied entity working with graphs, filters, etc.;
|
|
|
|
* NeoFS components are mostly needed in a small part of the solutions provided by placement;
|
|
|
|
* direct dependency from placement avoidance helps other components do not touch crucial changes in placement.
|
|
|
|
*/
|
|
|
|
|
|
|
|
type (
|
|
|
|
// CID is a type alias of
|
|
|
|
// CID from refs package of neofs-api-go.
|
|
|
|
CID = refs.CID
|
|
|
|
|
|
|
|
// SGID is a type alias of
|
|
|
|
// SGID from refs package of neofs-api-go.
|
|
|
|
SGID = refs.SGID
|
|
|
|
|
|
|
|
// ObjectID is a type alias of
|
|
|
|
// ObjectID from refs package of neofs-api-go.
|
|
|
|
ObjectID = refs.ObjectID
|
|
|
|
|
|
|
|
// Object is a type alias of
|
|
|
|
// Object from object package of neofs-api-go.
|
|
|
|
Object = object.Object
|
|
|
|
|
|
|
|
// Address is a type alias of
|
|
|
|
// Address from refs package of neofs-api-go.
|
|
|
|
Address = refs.Address
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
PlacementWrapper struct {
|
|
|
|
pl Component
|
2020-07-10 14:17:51 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
var errEmptyPlacement = errors.New("could not create storage lister: empty placement component")
|
2020-07-10 14:17:51 +00:00
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
// NewObjectPlacer wraps Component and returns ObjectPlacer interface.
|
|
|
|
func NewObjectPlacer(pl Component) (*PlacementWrapper, error) {
|
2020-07-10 14:17:51 +00:00
|
|
|
if pl == nil {
|
|
|
|
return nil, errEmptyPlacement
|
|
|
|
}
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
return &PlacementWrapper{pl}, nil
|
2020-07-10 14:17:51 +00:00
|
|
|
}
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
func (v PlacementWrapper) ContainerNodes(ctx context.Context, cid CID) ([]multiaddr.Multiaddr, error) {
|
|
|
|
graph, err := v.pl.Query(ctx, ContainerID(cid))
|
2020-07-10 14:17:51 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "objectPlacer.ContainerNodes failed on graph query")
|
|
|
|
}
|
|
|
|
|
|
|
|
return graph.NodeList()
|
|
|
|
}
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
func (v PlacementWrapper) ContainerNodesInfo(ctx context.Context, cid CID, prev int) ([]netmapcore.Info, error) {
|
|
|
|
graph, err := v.pl.Query(ctx, ContainerID(cid), UsePreviousNetmap(prev))
|
2020-07-10 14:17:51 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "objectPlacer.ContainerNodesInfo failed on graph query")
|
|
|
|
}
|
|
|
|
|
|
|
|
return graph.NodeInfo()
|
|
|
|
}
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
func (v PlacementWrapper) GetNodes(ctx context.Context, addr Address, usePreviousNetMap bool, excl ...multiaddr.Multiaddr) ([]multiaddr.Multiaddr, error) {
|
|
|
|
queryOptions := make([]QueryOption, 1, 2)
|
|
|
|
queryOptions[0] = ContainerID(addr.CID)
|
2020-07-10 14:17:51 +00:00
|
|
|
|
|
|
|
if usePreviousNetMap {
|
2020-07-24 13:54:03 +00:00
|
|
|
queryOptions = append(queryOptions, UsePreviousNetmap(1))
|
2020-07-10 14:17:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
graph, err := v.pl.Query(ctx, queryOptions...)
|
|
|
|
if err != nil {
|
|
|
|
if st, ok := status.FromError(errors.Cause(err)); ok && st.Code() == codes.NotFound {
|
|
|
|
return nil, container.ErrNotFound
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, errors.Wrap(err, "placer.GetNodes failed on graph query")
|
|
|
|
}
|
|
|
|
|
|
|
|
filter := func(group netmap.SFGroup, bucket *netmap.Bucket) *netmap.Bucket {
|
|
|
|
return bucket
|
|
|
|
}
|
|
|
|
|
|
|
|
if !addr.ObjectID.Empty() {
|
|
|
|
filter = func(group netmap.SFGroup, bucket *netmap.Bucket) *netmap.Bucket {
|
|
|
|
return bucket.GetSelection(group.Selectors, addr.ObjectID.Bytes())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return graph.Exclude(excl).Filter(filter).NodeList()
|
|
|
|
}
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
func (v PlacementWrapper) IsContainerNode(ctx context.Context, addr multiaddr.Multiaddr, cid CID, previousNetMap bool) (bool, error) {
|
2020-07-10 14:17:51 +00:00
|
|
|
nodes, err := v.GetNodes(ctx, Address{
|
|
|
|
CID: cid,
|
|
|
|
}, previousNetMap)
|
|
|
|
if err != nil {
|
|
|
|
return false, errors.Wrap(err, "placer.FromContainer failed on placer.GetNodes")
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := range nodes {
|
|
|
|
if nodes[i].Equal(addr) {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
func (v PlacementWrapper) Epoch() uint64 { return v.pl.NetworkState().Epoch }
|