forked from TrueCloudLab/frostfs-node
[#1064] putsvc: Add EC put
Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
This commit is contained in:
parent
39da643354
commit
1c5e0f90aa
11 changed files with 452 additions and 23 deletions
|
@ -16,6 +16,7 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network"
|
||||
|
@ -25,6 +26,7 @@ import (
|
|||
tracingPkg "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/tracing"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-observability/tracing"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum"
|
||||
containerSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
"git.frostfs.info/TrueCloudLab/tzhash/tz"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
|
@ -32,7 +34,10 @@ import (
|
|||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var errInvalidPayloadChecksum = errors.New("incorrect payload checksum")
|
||||
var (
|
||||
errInvalidPayloadChecksum = errors.New("incorrect payload checksum")
|
||||
errInvalidECObject = errors.New("object must be splitted to EC parts")
|
||||
)
|
||||
|
||||
type putSingleRequestSigner struct {
|
||||
req *objectAPI.PutSingleRequest
|
||||
|
@ -148,12 +153,20 @@ func (s *Service) validatePutSingleObject(ctx context.Context, obj *objectSDK.Ob
|
|||
|
||||
func (s *Service) saveToNodes(ctx context.Context, obj *objectSDK.Object, req *objectAPI.PutSingleRequest, meta object.ContentMeta) error {
|
||||
localOnly := req.GetMetaHeader().GetTTL() <= 1
|
||||
placementOptions, err := s.getPutSinglePlacementOptions(obj, req.GetBody().GetCopiesNumber(), localOnly)
|
||||
placement, err := s.getPutSinglePlacementOptions(obj, req.GetBody().GetCopiesNumber(), localOnly)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
iter := s.cfg.newNodeIterator(placementOptions)
|
||||
if placement.isEC {
|
||||
return s.saveToECReplicas(ctx, placement, obj, req, meta)
|
||||
}
|
||||
|
||||
return s.saveToREPReplicas(ctx, placement, obj, localOnly, req, meta)
|
||||
}
|
||||
|
||||
func (s *Service) saveToREPReplicas(ctx context.Context, placement putSinglePlacement, obj *objectSDK.Object, localOnly bool, req *objectAPI.PutSingleRequest, meta object.ContentMeta) error {
|
||||
iter := s.cfg.newNodeIterator(placement.placementOptions)
|
||||
iter.extraBroadcastEnabled = needAdditionalBroadcast(obj, localOnly)
|
||||
|
||||
signer := &putSingleRequestSigner{
|
||||
|
@ -167,38 +180,83 @@ func (s *Service) saveToNodes(ctx context.Context, obj *objectSDK.Object, req *o
|
|||
})
|
||||
}
|
||||
|
||||
func (s *Service) getPutSinglePlacementOptions(obj *objectSDK.Object, copiesNumber []uint32, localOnly bool) ([]placement.Option, error) {
|
||||
var result []placement.Option
|
||||
if len(copiesNumber) > 0 {
|
||||
result = append(result, placement.WithCopyNumbers(copiesNumber))
|
||||
func (s *Service) saveToECReplicas(ctx context.Context, placement putSinglePlacement, obj *objectSDK.Object, req *objectAPI.PutSingleRequest, meta object.ContentMeta) error {
|
||||
if obj.Type() == objectSDK.TypeRegular && obj.ECHeader() == nil {
|
||||
return errInvalidECObject
|
||||
}
|
||||
|
||||
commonPrm, err := svcutil.CommonPrmFromV2(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key, err := s.cfg.keyStorage.GetKey(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
signer := &putSingleRequestSigner{
|
||||
req: req,
|
||||
keyStorage: s.keyStorage,
|
||||
signer: &sync.Once{},
|
||||
}
|
||||
|
||||
w := ecWriter{
|
||||
cfg: s.cfg,
|
||||
placementOpts: placement.placementOptions,
|
||||
objMeta: meta,
|
||||
objMetaValid: true,
|
||||
commonPrm: commonPrm,
|
||||
container: placement.container,
|
||||
key: key,
|
||||
relay: func(ctx context.Context, ni client.NodeInfo, mac client.MultiAddressClient) error {
|
||||
return s.redirectPutSingleRequest(ctx, signer, obj, ni, mac)
|
||||
},
|
||||
}
|
||||
return w.WriteObject(ctx, obj)
|
||||
}
|
||||
|
||||
type putSinglePlacement struct {
|
||||
placementOptions []placement.Option
|
||||
isEC bool
|
||||
container containerSDK.Container
|
||||
}
|
||||
|
||||
func (s *Service) getPutSinglePlacementOptions(obj *objectSDK.Object, copiesNumber []uint32, localOnly bool) (putSinglePlacement, error) {
|
||||
var result putSinglePlacement
|
||||
|
||||
cnrID, ok := obj.ContainerID()
|
||||
if !ok {
|
||||
return nil, errors.New("missing container ID")
|
||||
return result, errors.New("missing container ID")
|
||||
}
|
||||
cnrInfo, err := s.cnrSrc.Get(cnrID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get container by ID: %w", err)
|
||||
return result, fmt.Errorf("could not get container by ID: %w", err)
|
||||
}
|
||||
result = append(result, placement.ForContainer(cnrInfo.Value))
|
||||
result.container = cnrInfo.Value
|
||||
result.isEC = container.IsECContainer(cnrInfo.Value) && object.IsECSupported(obj)
|
||||
if len(copiesNumber) > 0 && !result.isEC {
|
||||
result.placementOptions = append(result.placementOptions, placement.WithCopyNumbers(copiesNumber))
|
||||
}
|
||||
result.placementOptions = append(result.placementOptions, placement.ForContainer(cnrInfo.Value))
|
||||
|
||||
objID, ok := obj.ID()
|
||||
if !ok {
|
||||
return nil, errors.New("missing object ID")
|
||||
return result, errors.New("missing object ID")
|
||||
}
|
||||
result = append(result, placement.ForObject(objID))
|
||||
if obj.ECHeader() != nil {
|
||||
objID = obj.ECHeader().Parent()
|
||||
}
|
||||
result.placementOptions = append(result.placementOptions, placement.ForObject(objID))
|
||||
|
||||
latestNetmap, err := netmap.GetLatestNetworkMap(s.netMapSrc)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get latest network map: %w", err)
|
||||
return result, fmt.Errorf("could not get latest network map: %w", err)
|
||||
}
|
||||
builder := placement.NewNetworkMapBuilder(latestNetmap)
|
||||
if localOnly {
|
||||
result = append(result, placement.SuccessAfter(1))
|
||||
result.placementOptions = append(result.placementOptions, placement.SuccessAfter(1))
|
||||
builder = svcutil.NewLocalPlacement(builder, s.netmapKeys)
|
||||
}
|
||||
result = append(result, placement.UseBuilder(builder))
|
||||
result.placementOptions = append(result.placementOptions, placement.UseBuilder(builder))
|
||||
return result, nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue