[#328] container/load: Implement route builder based on placement

Implement route Builder interface on wrapper over the container placement
builder, Component implies exactly one transfer to each of the most weight
nodes of the container (according to some weighing algorithm).
Implementation is planned for use when transferring local estimates of
storage nodes.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2021-01-29 03:04:36 +03:00 committed by Leonard Lyubich
parent d48fb81193
commit 21133aee2f
3 changed files with 99 additions and 0 deletions

View file

@ -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,
}
}

View file

@ -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
}

View file

@ -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)
}