From 20ab57bf7ec3b271d474799a68dd226e5e8da1ca Mon Sep 17 00:00:00 2001 From: Anton Nikiforov Date: Mon, 22 Apr 2024 09:51:20 +0300 Subject: [PATCH] [#214] object: Implement `Get\Head` requests for EC object Signed-off-by: Anton Nikiforov --- client/object_get.go | 5 ++++ go.mod | 2 +- go.sum | 4 +-- object/ecinfo.go | 69 ++++++++++++++++++++++++++++++++++++++++++++ object/error.go | 18 ++++++++++++ object/error_test.go | 43 +++++++++++++++++++++++++++ pool/pool.go | 4 +++ 7 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 object/ecinfo.go diff --git a/client/object_get.go b/client/object_get.go index 363c1ec..a97fa76 100644 --- a/client/object_get.go +++ b/client/object_get.go @@ -150,6 +150,9 @@ func (x *ObjectReader) ReadHeader(dst *object.Object) bool { case *v2object.SplitInfo: x.err = object.NewSplitInfoError(object.NewSplitInfoFromV2(v)) return false + case *v2object.ECInfo: + x.err = object.NewECInfoError(object.NewECInfoFromV2(v)) + return false case *v2object.GetObjectPartInit: partInit = v } @@ -502,6 +505,8 @@ func (c *Client) ObjectHead(ctx context.Context, prm PrmObjectHead) (*ResObjectH return nil, fmt.Errorf("unexpected header type %T", v) case *v2object.SplitInfo: return nil, object.NewSplitInfoError(object.NewSplitInfoFromV2(v)) + case *v2object.ECInfo: + return nil, object.NewECInfoError(object.NewECInfoFromV2(v)) case *v2object.HeaderWithSignature: res.hdr = v } diff --git a/go.mod b/go.mod index 0c9cdbf..b5bc388 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module git.frostfs.info/TrueCloudLab/frostfs-sdk-go go 1.20 require ( - git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240327095603-491a47e7fe24 + git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240422151450-df9b65324a4c git.frostfs.info/TrueCloudLab/frostfs-contract v0.0.0-20230307110621-19a8ef2d02fb git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 git.frostfs.info/TrueCloudLab/hrw v1.2.1 diff --git a/go.sum b/go.sum index d3ecf3b..1a30d38 100644 --- a/go.sum +++ b/go.sum @@ -31,8 +31,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240327095603-491a47e7fe24 h1:uIkl0mKWwDICUZTbNWZ38HLYDBI9rMgdAhYQWZ0C9iQ= -git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240327095603-491a47e7fe24/go.mod h1:OBDSr+DqV1z4VDouoX3YMleNc4DPBVBWTG3WDT2PK1o= +git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240422151450-df9b65324a4c h1:RFDrNsF2e+EJfaB8lZrRRxNjQkLfM09gnEyudvGuc10= +git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240422151450-df9b65324a4c/go.mod h1:OBDSr+DqV1z4VDouoX3YMleNc4DPBVBWTG3WDT2PK1o= git.frostfs.info/TrueCloudLab/frostfs-contract v0.0.0-20230307110621-19a8ef2d02fb h1:S/TrbOOu9qEXZRZ9/Ddw7crnxbBUQLo68PSzQWYrc9M= git.frostfs.info/TrueCloudLab/frostfs-contract v0.0.0-20230307110621-19a8ef2d02fb/go.mod h1:nkR5gaGeez3Zv2SE7aceP0YwxG2FzIB5cGKpQO2vV2o= git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk= diff --git a/object/ecinfo.go b/object/ecinfo.go new file mode 100644 index 0000000..85345a7 --- /dev/null +++ b/object/ecinfo.go @@ -0,0 +1,69 @@ +package object + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" + "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" +) + +type ECChunk object.ECChunk + +func (c *ECChunk) SetID(id oid.ID) { + objV2 := new(refs.ObjectID) + id.WriteToV2(objV2) + c.ID = *objV2 +} + +// ToV2 converts ECChunk to v2 ECChunk message. +// +// Nil ECChunk converts to nil. +func (c *ECChunk) ToV2() *object.ECChunk { + return (*object.ECChunk)(c) +} + +func NewECChunkFromV2(v2 *object.ECChunk) *ECChunk { + return (*ECChunk)(v2) +} + +type ECInfo object.ECInfo + +// NewECInfoFromV2 wraps v2 ECInfo message to ECInfo. +// +// Nil object.ECInfo converts to nil. +func NewECInfoFromV2(v2 *object.ECInfo) *ECInfo { + return (*ECInfo)(v2) +} + +// NewECInfo creates and initializes blank ECInfo. +func NewECInfo() *ECInfo { + return NewECInfoFromV2(new(object.ECInfo)) +} + +// ToV2 converts ECInfo to v2 ECInfo message. +// +// Nil ECInfo converts to nil. +func (s *ECInfo) ToV2() *object.ECInfo { + return (*object.ECInfo)(s) +} + +func (s *ECInfo) Marshal() ([]byte, error) { + return (*object.ECInfo)(s).StableMarshal(nil), nil +} + +func (s *ECInfo) Unmarshal(data []byte) error { + return (*object.ECInfo)(s).Unmarshal(data) +} + +// MarshalJSON implements json.Marshaler. +func (s *ECInfo) MarshalJSON() ([]byte, error) { + return (*object.ECInfo)(s).MarshalJSON() +} + +// UnmarshalJSON implements json.Unmarshaler. +func (s *ECInfo) UnmarshalJSON(data []byte) error { + return (*object.ECInfo)(s).UnmarshalJSON(data) +} + +func (s *ECInfo) AddChunk(chunk ECChunk) { + s.Chunks = append(s.Chunks, *chunk.ToV2()) +} diff --git a/object/error.go b/object/error.go index 96048c2..8db1d94 100644 --- a/object/error.go +++ b/object/error.go @@ -17,3 +17,21 @@ func (s *SplitInfoError) SplitInfo() *SplitInfo { func NewSplitInfoError(v *SplitInfo) *SplitInfoError { return &SplitInfoError{si: v} } + +type ECInfoError struct { + ei *ECInfo +} + +const ecInfoErrorMsg = "object not found, ec info has been provided" + +func (e *ECInfoError) Error() string { + return ecInfoErrorMsg +} + +func (e *ECInfoError) ECInfo() *ECInfo { + return e.ei +} + +func NewECInfoError(v *ECInfo) *ECInfoError { + return &ECInfoError{ei: v} +} diff --git a/object/error_test.go b/object/error_test.go index a0774b0..0e52b39 100644 --- a/object/error_test.go +++ b/object/error_test.go @@ -1,9 +1,12 @@ package object_test import ( + "crypto/rand" "errors" "testing" + objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" + "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" "github.com/stretchr/testify/require" ) @@ -31,3 +34,43 @@ func generateSplitInfo() *object.SplitInfo { return si } + +func TestNewECInfoError(t *testing.T) { + var ( + ei = generateECInfo() + + err error = object.NewECInfoError(ei) + expectedErr *object.ECInfoError + ) + + require.True(t, errors.As(err, &expectedErr)) + + eiErr, ok := err.(*object.ECInfoError) + require.True(t, ok) + require.Equal(t, ei, eiErr.ECInfo()) +} + +func generateECInfo() *object.ECInfo { + ei := object.NewECInfo() + ei.Chunks = append(ei.Chunks, objectV2.ECChunk{ + ID: generateV2ID(), + Index: 0, + Total: 2, + }) + ei.Chunks = append(ei.Chunks, objectV2.ECChunk{ + ID: generateV2ID(), + Index: 1, + Total: 2, + }) + return ei +} + +func generateV2ID() refs.ObjectID { + var buf [32]byte + _, _ = rand.Read(buf[:]) + + var id refs.ObjectID + id.SetValue(buf[:]) + + return id +} diff --git a/pool/pool.go b/pool/pool.go index 7392e48..a4ffff1 100644 --- a/pool/pool.go +++ b/pool/pool.go @@ -1182,6 +1182,10 @@ func needCountError(ctx context.Context, err error) bool { if errors.As(err, &siErr) { return false } + var eiErr *object.ECInfoError + if errors.As(err, &eiErr) { + return false + } if errors.Is(ctx.Err(), context.Canceled) { return false