forked from TrueCloudLab/frostfs-node
Evgenii Stratonikov
0e31c12e63
Drop duplicate entities. Format entities. Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com> Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
145 lines
3.3 KiB
Go
145 lines
3.3 KiB
Go
package loadroute
|
|
|
|
import (
|
|
"context"
|
|
"encoding/hex"
|
|
"sync"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
loadcontroller "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/container/announcement/load/controller"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// InitWriter initializes and returns Writer that sends each value to its next route point.
|
|
//
|
|
// If route is present, then it is taken into account,
|
|
// and the value will be sent to its continuation. Otherwise, the route will be laid
|
|
// from scratch and the value will be sent to its primary point.
|
|
//
|
|
// After building a list of remote points of the next leg of the route, the value is sent
|
|
// sequentially to all of them. If any transmissions (even all) fail, an error will not
|
|
// be returned.
|
|
//
|
|
// Close of the composed Writer calls Close method on each internal Writer generated in
|
|
// runtime and never returns an error.
|
|
//
|
|
// Always returns nil error.
|
|
func (r *Router) InitWriter(route []loadcontroller.ServerInfo) (loadcontroller.Writer, error) {
|
|
if len(route) == 0 {
|
|
route = []loadcontroller.ServerInfo{r.localSrvInfo}
|
|
}
|
|
|
|
return &loadWriter{
|
|
router: r,
|
|
route: route,
|
|
mRoute: make(map[routeKey]*valuesRoute),
|
|
mServers: make(map[string]loadcontroller.Writer),
|
|
}, nil
|
|
}
|
|
|
|
type routeKey struct {
|
|
epoch uint64
|
|
|
|
cid string
|
|
}
|
|
|
|
type valuesRoute struct {
|
|
route []loadcontroller.ServerInfo
|
|
|
|
values []container.SizeEstimation
|
|
}
|
|
|
|
type loadWriter struct {
|
|
router *Router
|
|
|
|
route []loadcontroller.ServerInfo
|
|
|
|
routeMtx sync.RWMutex
|
|
mRoute map[routeKey]*valuesRoute
|
|
|
|
mServers map[string]loadcontroller.Writer
|
|
}
|
|
|
|
func (w *loadWriter) Put(a container.SizeEstimation) error {
|
|
w.routeMtx.Lock()
|
|
defer w.routeMtx.Unlock()
|
|
|
|
key := routeKey{
|
|
epoch: a.Epoch(),
|
|
cid: a.Container().EncodeToString(),
|
|
}
|
|
|
|
routeValues, ok := w.mRoute[key]
|
|
if !ok {
|
|
route, err := w.router.routeBuilder.NextStage(a, w.route)
|
|
if err != nil {
|
|
return err
|
|
} else if len(route) == 0 {
|
|
route = []loadcontroller.ServerInfo{nil}
|
|
}
|
|
|
|
routeValues = &valuesRoute{
|
|
route: route,
|
|
values: []container.SizeEstimation{a},
|
|
}
|
|
|
|
w.mRoute[key] = routeValues
|
|
}
|
|
|
|
for _, remoteInfo := range routeValues.route {
|
|
var key string
|
|
|
|
if remoteInfo != nil {
|
|
key = hex.EncodeToString(remoteInfo.PublicKey())
|
|
}
|
|
|
|
remoteWriter, ok := w.mServers[key]
|
|
if !ok {
|
|
provider, err := w.router.remoteProvider.InitRemote(remoteInfo)
|
|
if err != nil {
|
|
w.router.log.Debug(logs.RouteCouldNotInitializeWriterProvider,
|
|
zap.String("error", err.Error()),
|
|
)
|
|
|
|
continue // best effort
|
|
}
|
|
|
|
remoteWriter, err = provider.InitWriter(w.route)
|
|
if err != nil {
|
|
w.router.log.Debug(logs.RouteCouldNotInitializeWriter,
|
|
zap.String("error", err.Error()),
|
|
)
|
|
|
|
continue // best effort
|
|
}
|
|
|
|
w.mServers[key] = remoteWriter
|
|
}
|
|
|
|
err := remoteWriter.Put(a)
|
|
if err != nil {
|
|
w.router.log.Debug(logs.RouteCouldNotPutTheValue,
|
|
zap.String("error", err.Error()),
|
|
)
|
|
}
|
|
|
|
// continue best effort
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (w *loadWriter) Close(ctx context.Context) error {
|
|
for key, wRemote := range w.mServers {
|
|
err := wRemote.Close(ctx)
|
|
if err != nil {
|
|
w.router.log.Debug(logs.RouteCouldNotCloseRemoteServerWriter,
|
|
zap.String("key", key),
|
|
zap.String("error", err.Error()),
|
|
)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|