diff --git a/pkg/services/container/announcement/load/route/placement/builder.go b/pkg/services/container/announcement/load/route/placement/builder.go new file mode 100644 index 000000000..061ac5921 --- /dev/null +++ b/pkg/services/container/announcement/load/route/placement/builder.go @@ -0,0 +1,49 @@ +package placementrouter + +import "fmt" + +// Prm groups the required parameters of the Builder's constructor. +// +// All values must comply with the requirements imposed on them. +// Passing incorrect parameter values will result in constructor +// failure (error or panic depending on the implementation). +type Prm struct { + // Calculator of the container members. + // + // Must not be nil. + PlacementBuilder PlacementBuilder +} + +// Builder represents component that routes used container space +// values between nodes from the container. +// +// For correct operation, Builder must be created using +// the constructor (New) based on the required parameters +// and optional components. After successful creation, +// the Builder is immediately ready to work through API. +type Builder struct { + placementBuilder PlacementBuilder +} + +const invalidPrmValFmt = "invalid parameter %s (%T):%v" + +func panicOnPrmValue(n string, v interface{}) { + panic(fmt.Sprintf(invalidPrmValFmt, n, v, v)) +} + +// New creates a new instance of the Builder. +// +// Panics if at least one value of the parameters is invalid. +// +// The created Builder does not require additional +// initialization and is completely ready for work +func New(prm Prm) *Builder { + switch { + case prm.PlacementBuilder == nil: + panicOnPrmValue("RemoteWriterProvider", prm.PlacementBuilder) + } + + return &Builder{ + placementBuilder: prm.PlacementBuilder, + } +} diff --git a/pkg/services/container/announcement/load/route/placement/calls.go b/pkg/services/container/announcement/load/route/placement/calls.go new file mode 100644 index 000000000..61f222d6a --- /dev/null +++ b/pkg/services/container/announcement/load/route/placement/calls.go @@ -0,0 +1,36 @@ +package placementrouter + +import ( + "github.com/nspcc-dev/neofs-api-go/pkg/container" + loadroute "github.com/nspcc-dev/neofs-node/pkg/services/container/announcement/load/route" + "github.com/pkg/errors" +) + +// NextStage composes container nodes for the container and epoch from a, +// and returns the list of nodes with maximum weight (one from each vector). +// +// If passed route has more than one point, then endpoint of the route is reached. +// +// The traversed route is not checked, it is assumed to be correct. +func (b *Builder) NextStage(a container.UsedSpaceAnnouncement, passed []loadroute.ServerInfo) ([]loadroute.ServerInfo, error) { + if len(passed) > 1 { + return nil, nil + } + + placement, err := b.placementBuilder.BuildPlacement(a.Epoch(), a.ContainerID()) + if err != nil { + return nil, errors.Wrapf(err, "could not build placement %s", a.ContainerID()) + } + + res := make([]loadroute.ServerInfo, 0, len(placement)) + + for i := range placement { + if len(placement[i]) == 0 { + continue + } + + res = append(res, placement[i][0]) + } + + return res, nil +} diff --git a/pkg/services/container/announcement/load/route/placement/deps.go b/pkg/services/container/announcement/load/route/placement/deps.go new file mode 100644 index 000000000..ee4397bb3 --- /dev/null +++ b/pkg/services/container/announcement/load/route/placement/deps.go @@ -0,0 +1,14 @@ +package placementrouter + +import ( + "github.com/nspcc-dev/neofs-api-go/pkg/container" + "github.com/nspcc-dev/neofs-api-go/pkg/netmap" +) + +// PlacementBuilder describes interface of NeoFS placement calculator. +type PlacementBuilder interface { + // BuildPlacement must compose and sort (according to a specific algorithm) + // storage nodes from the container with identifier cid using network map + // of particular epoch. + BuildPlacement(epoch uint64, cid *container.ID) ([]netmap.Nodes, error) +}