Skip to content

Commit 0c5bdbe

Browse files
authored
Switch to v2 object split scheme (#957)
2 parents 4137b02 + 8328780 commit 0c5bdbe

15 files changed

+470
-169
lines changed

.github/workflows/s3-tests.yml

+6-6
Original file line numberDiff line numberDiff line change
@@ -53,47 +53,47 @@ jobs:
5353
uses: dsaltares/fetch-gh-release-asset@1.1.1
5454
with:
5555
repo: 'nspcc-dev/neofs-node'
56-
version: 'tags/v0.41.1'
56+
version: 'tags/v0.42.0'
5757
file: 'neofs-cli-linux-amd64'
5858
target: 's3-tests/neofs-cli'
5959

6060
- name: Download latest stable neofs-adm
6161
uses: dsaltares/fetch-gh-release-asset@1.1.1
6262
with:
6363
repo: 'nspcc-dev/neofs-node'
64-
version: 'tags/v0.41.1'
64+
version: 'tags/v0.42.0'
6565
file: 'neofs-adm-linux-amd64'
6666
target: 's3-tests/neofs-adm'
6767

6868
- name: Download latest stable neofs-ir
6969
uses: dsaltares/fetch-gh-release-asset@1.1.1
7070
with:
7171
repo: 'nspcc-dev/neofs-node'
72-
version: 'tags/v0.41.1'
72+
version: 'tags/v0.42.0'
7373
file: 'neofs-ir-linux-amd64'
7474
target: 's3-tests/neofs-ir'
7575

7676
- name: Download latest stable neofs-lens
7777
uses: dsaltares/fetch-gh-release-asset@1.1.1
7878
with:
7979
repo: 'nspcc-dev/neofs-node'
80-
version: 'tags/v0.41.1'
80+
version: 'tags/v0.42.0'
8181
file: 'neofs-lens-linux-amd64'
8282
target: 's3-tests/neofs-lens'
8383

8484
- name: Download latest stable neofs-node
8585
uses: dsaltares/fetch-gh-release-asset@1.1.1
8686
with:
8787
repo: 'nspcc-dev/neofs-node'
88-
version: 'tags/v0.41.1'
88+
version: 'tags/v0.42.0'
8989
file: 'neofs-node-linux-amd64'
9090
target: 's3-tests/neofs-node'
9191

9292
- name: Download latest stable neo-go
9393
uses: dsaltares/fetch-gh-release-asset@1.1.1
9494
with:
9595
repo: 'nspcc-dev/neo-go'
96-
version: 'tags/v0.105.1'
96+
version: 'tags/v0.106.0'
9797
file: 'neo-go-linux-amd64'
9898
target: 's3-tests/neo-go'
9999

api/data/info.go

+9-8
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,15 @@ type (
4040
IsDir bool
4141
IsDeleteMarker bool
4242

43-
Bucket string
44-
Name string
45-
Size int64
46-
ContentType string
47-
Created time.Time
48-
HashSum string
49-
Owner user.ID
50-
Headers map[string]string
43+
Bucket string
44+
Name string
45+
Size int64
46+
ContentType string
47+
Created time.Time
48+
HashSum string
49+
Owner user.ID
50+
OwnerPublicKey keys.PublicKey
51+
Headers map[string]string
5152
}
5253

5354
// NotificationInfo store info to send s3 notification.

api/data/tree.go

+38-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package data
22

33
import (
4+
"fmt"
45
"strconv"
6+
"strings"
57
"time"
68

9+
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
710
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
811
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
912
"github.com/nspcc-dev/neofs-sdk-go/user"
@@ -72,10 +75,42 @@ type MultipartInfo struct {
7275
Key string
7376
UploadID string
7477
Owner user.ID
78+
OwnerPubKey keys.PublicKey
7579
Created time.Time
7680
Meta map[string]string
7781
CopiesNumber uint32
78-
SplitID string
82+
}
83+
84+
// LinkObjectPayload contains part info of the complex object.
85+
// This data will be used for linking object construction.
86+
type LinkObjectPayload struct {
87+
OID oid.ID
88+
Size uint32
89+
}
90+
91+
// Marshal converts LinkObjectPayload to string.
92+
func (e *LinkObjectPayload) Marshal() string {
93+
return fmt.Sprintf("%s:%d", e.OID.String(), e.Size)
94+
}
95+
96+
// Unmarshal converts string to LinkObjectPayload.
97+
func (e *LinkObjectPayload) Unmarshal(value string) error {
98+
parts := strings.Split(value, ":")
99+
if len(parts) != 2 {
100+
return fmt.Errorf("invalid format: %s", value)
101+
}
102+
103+
if err := e.OID.DecodeString(parts[0]); err != nil {
104+
return fmt.Errorf("invalid id: %w", err)
105+
}
106+
107+
size, err := strconv.ParseUint(parts[1], 10, 32)
108+
if err != nil {
109+
return fmt.Errorf("invalid size: %w", err)
110+
}
111+
112+
e.Size = uint32(size)
113+
return nil
79114
}
80115

81116
// PartInfo is upload information about part.
@@ -95,8 +130,8 @@ type PartInfo struct {
95130
MultipartHash []byte
96131
// HomoHash contains internal state of the [hash.Hash] to calculate whole object homomorphic payload hash.
97132
HomoHash []byte
98-
// Elements contain [oid.ID] object list for the current part.
99-
Elements []oid.ID
133+
// Elements contain [oid.ID] and size for each element for the current part.
134+
Elements []LinkObjectPayload
100135
}
101136

102137
// ToHeaderString form short part representation to use in S3-Completed-Parts header.

api/handler/multipart_upload.go

+10-12
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"strconv"
88
"time"
99

10-
"github.com/google/uuid"
1110
"github.com/nspcc-dev/neofs-s3-gw/api"
1211
"github.com/nspcc-dev/neofs-s3-gw/api/data"
1312
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
@@ -101,17 +100,14 @@ func (h *handler) CreateMultipartUploadHandler(w http.ResponseWriter, r *http.Re
101100
return
102101
}
103102

104-
uploadID := uuid.New()
105103
additional := []zap.Field{
106-
zap.String("uploadID", uploadID.String()),
107104
zap.String("Key", reqInfo.ObjectName),
108105
}
109106

110107
p := &layer.CreateMultipartParams{
111108
Info: &layer.UploadInfoParams{
112-
UploadID: uploadID.String(),
113-
Bkt: bktInfo,
114-
Key: reqInfo.ObjectName,
109+
Bkt: bktInfo,
110+
Key: reqInfo.ObjectName,
115111
},
116112
Data: &layer.UploadData{},
117113
}
@@ -154,7 +150,8 @@ func (h *handler) CreateMultipartUploadHandler(w http.ResponseWriter, r *http.Re
154150
return
155151
}
156152

157-
if err = h.obj.CreateMultipartUpload(r.Context(), p); err != nil {
153+
uploadID, err := h.obj.CreateMultipartUpload(r.Context(), p)
154+
if err != nil {
158155
h.logAndSendError(w, "could create multipart upload", reqInfo, err, additional...)
159156
return
160157
}
@@ -166,9 +163,10 @@ func (h *handler) CreateMultipartUploadHandler(w http.ResponseWriter, r *http.Re
166163
resp := InitiateMultipartUploadResponse{
167164
Bucket: reqInfo.BucketName,
168165
Key: reqInfo.ObjectName,
169-
UploadID: uploadID.String(),
166+
UploadID: uploadID,
170167
}
171168

169+
additional = append(additional, zap.String("uploadID", uploadID))
172170
if err = api.EncodeToResponse(w, resp); err != nil {
173171
h.logAndSendError(w, "could not encode InitiateMultipartUploadResponse to response", reqInfo, err, additional...)
174172
return
@@ -648,12 +646,12 @@ func encodeListMultipartUploadsToResponse(info *layer.ListMultipartUploadsInfo,
648646
m := MultipartUpload{
649647
Initiated: u.Created.UTC().Format(time.RFC3339),
650648
Initiator: Initiator{
651-
ID: u.Owner.String(),
649+
ID: u.OwnerPubKey.StringCompressed(),
652650
DisplayName: u.Owner.String(),
653651
},
654652
Key: u.Key,
655653
Owner: Owner{
656-
ID: u.Owner.String(),
654+
ID: u.OwnerPubKey.StringCompressed(),
657655
DisplayName: u.Owner.String(),
658656
},
659657
UploadID: u.UploadID,
@@ -671,15 +669,15 @@ func encodeListPartsToResponse(info *layer.ListPartsInfo, params *layer.ListPart
671669
XMLName: xml.Name{},
672670
Bucket: params.Info.Bkt.Name,
673671
Initiator: Initiator{
674-
ID: info.Owner.String(),
672+
ID: info.OwnerPubKey.StringCompressed(),
675673
DisplayName: info.Owner.String(),
676674
},
677675
IsTruncated: info.IsTruncated,
678676
Key: params.Info.Key,
679677
MaxParts: params.MaxParts,
680678
NextPartNumberMarker: info.NextPartNumberMarker,
681679
Owner: Owner{
682-
ID: info.Owner.String(),
680+
ID: info.OwnerPubKey.StringCompressed(),
683681
DisplayName: info.Owner.String(),
684682
},
685683
PartNumberMarker: params.PartNumberMarker,

api/handler/object_list.go

+44-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package handler
22

33
import (
4+
"fmt"
45
"net/http"
56
"net/url"
67
"strconv"
@@ -33,12 +34,18 @@ func (h *handler) ListObjectsV1Handler(w http.ResponseWriter, r *http.Request) {
3334
return
3435
}
3536

36-
if err = api.EncodeToResponse(w, encodeV1(params, list)); err != nil {
37+
encoded, err := encodeV1(params, list)
38+
if err != nil {
39+
h.logAndSendError(w, "encode V1", reqInfo, err)
40+
return
41+
}
42+
43+
if err = api.EncodeToResponse(w, encoded); err != nil {
3744
h.logAndSendError(w, "something went wrong", reqInfo, err)
3845
}
3946
}
4047

41-
func encodeV1(p *layer.ListObjectsParamsV1, list *layer.ListObjectsInfoV1) *ListObjectsV1Response {
48+
func encodeV1(p *layer.ListObjectsParamsV1, list *layer.ListObjectsInfoV1) (*ListObjectsV1Response, error) {
4249
res := &ListObjectsV1Response{
4350
Name: p.BktInfo.Name,
4451
EncodingType: p.Encode,
@@ -52,9 +59,14 @@ func encodeV1(p *layer.ListObjectsParamsV1, list *layer.ListObjectsInfoV1) *List
5259

5360
res.CommonPrefixes = fillPrefixes(list.Prefixes, p.Encode)
5461

55-
res.Contents = fillContentsWithOwner(list.Objects, p.Encode)
62+
content, err := fillContentsWithOwner(list.Objects, p.Encode)
63+
if err != nil {
64+
return nil, fmt.Errorf("fill contents with owner: %w", err)
65+
}
66+
67+
res.Contents = content
5668

57-
return res
69+
return res, nil
5870
}
5971

6072
// ListObjectsV2Handler handles objects listing requests for API version 2.
@@ -77,12 +89,18 @@ func (h *handler) ListObjectsV2Handler(w http.ResponseWriter, r *http.Request) {
7789
return
7890
}
7991

80-
if err = api.EncodeToResponse(w, encodeV2(params, list)); err != nil {
92+
encoded, err := encodeV2(params, list)
93+
if err != nil {
94+
h.logAndSendError(w, "encode V2", reqInfo, err)
95+
return
96+
}
97+
98+
if err = api.EncodeToResponse(w, encoded); err != nil {
8199
h.logAndSendError(w, "something went wrong", reqInfo, err)
82100
}
83101
}
84102

85-
func encodeV2(p *layer.ListObjectsParamsV2, list *layer.ListObjectsInfoV2) *ListObjectsV2Response {
103+
func encodeV2(p *layer.ListObjectsParamsV2, list *layer.ListObjectsInfoV2) (*ListObjectsV2Response, error) {
86104
res := &ListObjectsV2Response{
87105
Name: p.BktInfo.Name,
88106
EncodingType: p.Encode,
@@ -98,9 +116,14 @@ func encodeV2(p *layer.ListObjectsParamsV2, list *layer.ListObjectsInfoV2) *List
98116

99117
res.CommonPrefixes = fillPrefixes(list.Prefixes, p.Encode)
100118

101-
res.Contents = fillContents(list.Objects, p.Encode, p.FetchOwner)
119+
content, err := fillContents(list.Objects, p.Encode, p.FetchOwner)
120+
if err != nil {
121+
return nil, fmt.Errorf("fill content: %w", err)
122+
}
102123

103-
return res
124+
res.Contents = content
125+
126+
return res, nil
104127
}
105128

106129
func parseListObjectsArgsV1(reqInfo *api.ReqInfo) (*layer.ListObjectsParamsV1, error) {
@@ -184,11 +207,11 @@ func fillPrefixes(src []string, encode string) []CommonPrefix {
184207
return dst
185208
}
186209

187-
func fillContentsWithOwner(src []*data.ObjectInfo, encode string) []Object {
210+
func fillContentsWithOwner(src []*data.ObjectInfo, encode string) ([]Object, error) {
188211
return fillContents(src, encode, true)
189212
}
190213

191-
func fillContents(src []*data.ObjectInfo, encode string, fetchOwner bool) []Object {
214+
func fillContents(src []*data.ObjectInfo, encode string, fetchOwner bool) ([]Object, error) {
192215
var dst []Object
193216
for _, obj := range src {
194217
res := Object{
@@ -198,6 +221,15 @@ func fillContents(src []*data.ObjectInfo, encode string, fetchOwner bool) []Obje
198221
ETag: obj.HashSum,
199222
}
200223

224+
if size, ok := obj.Headers[layer.AttributeDecryptedSize]; ok {
225+
sz, err := strconv.ParseInt(size, 10, 64)
226+
if err != nil {
227+
return nil, fmt.Errorf("parse decrypted size %s: %w", size, err)
228+
}
229+
230+
res.Size = sz
231+
}
232+
201233
if fetchOwner {
202234
res.Owner = &Owner{
203235
ID: obj.Owner.String(),
@@ -207,7 +239,7 @@ func fillContents(src []*data.ObjectInfo, encode string, fetchOwner bool) []Obje
207239

208240
dst = append(dst, res)
209241
}
210-
return dst
242+
return dst, nil
211243
}
212244

213245
func (h *handler) ListBucketObjectVersionsHandler(w http.ResponseWriter, r *http.Request) {
@@ -277,7 +309,7 @@ func encodeListObjectVersionsToResponse(info *layer.ListObjectVersionsInfo, buck
277309
Key: ver.ObjectInfo.Name,
278310
LastModified: ver.ObjectInfo.Created.UTC().Format(time.RFC3339),
279311
Owner: Owner{
280-
ID: ver.ObjectInfo.Owner.String(),
312+
ID: ver.ObjectInfo.OwnerPublicKey.StringCompressed(),
281313
DisplayName: ver.ObjectInfo.Owner.String(),
282314
},
283315
Size: ver.ObjectInfo.Size,

api/layer/layer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ type (
226226

227227
DeleteObjects(ctx context.Context, p *DeleteObjectParams) []*VersionedObject
228228

229-
CreateMultipartUpload(ctx context.Context, p *CreateMultipartParams) error
229+
CreateMultipartUpload(ctx context.Context, p *CreateMultipartParams) (string, error)
230230
CompleteMultipartUpload(ctx context.Context, p *CompleteMultipartParams) (*UploadData, *data.ExtendedObjectInfo, error)
231231
UploadPart(ctx context.Context, p *UploadPartParams) (string, error)
232232
UploadPartCopy(ctx context.Context, p *UploadCopyParams) (*data.ObjectInfo, error)

0 commit comments

Comments
 (0)