forked from TrueCloudLab/frostfs-s3-gw
[#669] Optimize getNodeVersion for tags operation
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
e42fbbbe9f
commit
821df3d648
11 changed files with 174 additions and 116 deletions
|
@ -68,12 +68,12 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
p := &layer.HeadObjectParams{
|
srcObjPrm := &layer.HeadObjectParams{
|
||||||
Object: srcObject,
|
Object: srcObject,
|
||||||
VersionID: versionID,
|
VersionID: versionID,
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.BktInfo, err = h.getBucketAndCheckOwner(r, srcBucket, api.AmzSourceExpectedBucketOwner); err != nil {
|
if srcObjPrm.BktInfo, err = h.getBucketAndCheckOwner(r, srcBucket, api.AmzSourceExpectedBucketOwner); err != nil {
|
||||||
h.logAndSendError(w, "couldn't get source bucket", reqInfo, err)
|
h.logAndSendError(w, "couldn't get source bucket", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -97,11 +97,12 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
objInfo, err := h.obj.GetObjectInfo(r.Context(), p)
|
extendedSrcObjInfo, err := h.obj.GetExtendedObjectInfo(r.Context(), srcObjPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not find object", reqInfo, err)
|
h.logAndSendError(w, "could not find object", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
srcObjInfo := extendedSrcObjInfo.ObjectInfo
|
||||||
|
|
||||||
args, err := parseCopyObjectArgs(r.Header)
|
args, err := parseCopyObjectArgs(r.Header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -125,13 +126,16 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
objVersion := &layer.ObjectVersion{
|
tagPrm := &layer.GetObjectTaggingParams{
|
||||||
BktInfo: p.BktInfo,
|
ObjectVersion: &layer.ObjectVersion{
|
||||||
ObjectName: srcObject,
|
BktInfo: srcObjPrm.BktInfo,
|
||||||
VersionID: objInfo.VersionID(),
|
ObjectName: srcObject,
|
||||||
|
VersionID: srcObjInfo.VersionID(),
|
||||||
|
},
|
||||||
|
NodeVersion: extendedSrcObjInfo.NodeVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, tagSet, err = h.obj.GetObjectTagging(r.Context(), objVersion)
|
_, tagSet, err = h.obj.GetObjectTagging(r.Context(), tagPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not get object tagging", reqInfo, err)
|
h.logAndSendError(w, "could not get object tagging", reqInfo, err)
|
||||||
return
|
return
|
||||||
|
@ -144,21 +148,21 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = encryptionParams.MatchObjectEncryption(layer.FormEncryptionInfo(objInfo.Headers)); err != nil {
|
if err = encryptionParams.MatchObjectEncryption(layer.FormEncryptionInfo(srcObjInfo.Headers)); err != nil {
|
||||||
h.logAndSendError(w, "encryption doesn't match object", reqInfo, errors.GetAPIError(errors.ErrBadRequest), zap.Error(err))
|
h.logAndSendError(w, "encryption doesn't match object", reqInfo, errors.GetAPIError(errors.ErrBadRequest), zap.Error(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = checkPreconditions(objInfo, args.Conditional); err != nil {
|
if err = checkPreconditions(srcObjInfo, args.Conditional); err != nil {
|
||||||
h.logAndSendError(w, "precondition failed", reqInfo, errors.GetAPIError(errors.ErrPreconditionFailed))
|
h.logAndSendError(w, "precondition failed", reqInfo, errors.GetAPIError(errors.ErrPreconditionFailed))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if metadata == nil {
|
if metadata == nil {
|
||||||
if len(objInfo.ContentType) > 0 {
|
if len(srcObjInfo.ContentType) > 0 {
|
||||||
objInfo.Headers[api.ContentType] = objInfo.ContentType
|
srcObjInfo.Headers[api.ContentType] = srcObjInfo.ContentType
|
||||||
}
|
}
|
||||||
metadata = objInfo.Headers
|
metadata = srcObjInfo.Headers
|
||||||
} else if contentType := r.Header.Get(api.ContentType); len(contentType) > 0 {
|
} else if contentType := r.Header.Get(api.ContentType); len(contentType) > 0 {
|
||||||
metadata[api.ContentType] = contentType
|
metadata[api.ContentType] = contentType
|
||||||
}
|
}
|
||||||
|
@ -170,11 +174,11 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
params := &layer.CopyObjectParams{
|
params := &layer.CopyObjectParams{
|
||||||
SrcObject: objInfo,
|
SrcObject: srcObjInfo,
|
||||||
ScrBktInfo: p.BktInfo,
|
ScrBktInfo: srcObjPrm.BktInfo,
|
||||||
DstBktInfo: dstBktInfo,
|
DstBktInfo: dstBktInfo,
|
||||||
DstObject: reqInfo.ObjectName,
|
DstObject: reqInfo.ObjectName,
|
||||||
SrcSize: objInfo.Size,
|
SrcSize: srcObjInfo.Size,
|
||||||
Header: metadata,
|
Header: metadata,
|
||||||
Encryption: encryptionParams,
|
Encryption: encryptionParams,
|
||||||
CopiesNuber: copiesNumber,
|
CopiesNuber: copiesNumber,
|
||||||
|
@ -187,16 +191,20 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
additional := []zap.Field{zap.String("src_bucket_name", srcBucket), zap.String("src_object_name", srcObject)}
|
additional := []zap.Field{zap.String("src_bucket_name", srcBucket), zap.String("src_object_name", srcObject)}
|
||||||
if objInfo, err = h.obj.CopyObject(r.Context(), params); err != nil {
|
extendedDstObjInfo, err := h.obj.CopyObject(r.Context(), params)
|
||||||
|
if err != nil {
|
||||||
h.logAndSendError(w, "couldn't copy object", reqInfo, err, additional...)
|
h.logAndSendError(w, "couldn't copy object", reqInfo, err, additional...)
|
||||||
return
|
return
|
||||||
} else if err = api.EncodeToResponse(w, &CopyObjectResponse{LastModified: objInfo.Created.UTC().Format(time.RFC3339), ETag: objInfo.HashSum}); err != nil {
|
}
|
||||||
|
dstObjInfo := extendedDstObjInfo.ObjectInfo
|
||||||
|
|
||||||
|
if err = api.EncodeToResponse(w, &CopyObjectResponse{LastModified: dstObjInfo.Created.UTC().Format(time.RFC3339), ETag: dstObjInfo.HashSum}); err != nil {
|
||||||
h.logAndSendError(w, "something went wrong", reqInfo, err, additional...)
|
h.logAndSendError(w, "something went wrong", reqInfo, err, additional...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if containsACL {
|
if containsACL {
|
||||||
newEaclTable, err := h.getNewEAclTable(r, dstBktInfo, objInfo)
|
newEaclTable, err := h.getNewEAclTable(r, dstBktInfo, dstObjInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not get new eacl table", reqInfo, err)
|
h.logAndSendError(w, "could not get new eacl table", reqInfo, err)
|
||||||
return
|
return
|
||||||
|
@ -215,25 +223,29 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if tagSet != nil {
|
if tagSet != nil {
|
||||||
t := &layer.ObjectVersion{
|
tagPrm := &layer.PutObjectTaggingParams{
|
||||||
BktInfo: dstBktInfo,
|
ObjectVersion: &layer.ObjectVersion{
|
||||||
ObjectName: reqInfo.ObjectName,
|
BktInfo: dstBktInfo,
|
||||||
VersionID: objInfo.VersionID(),
|
ObjectName: reqInfo.ObjectName,
|
||||||
|
VersionID: dstObjInfo.VersionID(),
|
||||||
|
},
|
||||||
|
TagSet: tagSet,
|
||||||
|
NodeVersion: extendedDstObjInfo.NodeVersion,
|
||||||
}
|
}
|
||||||
if _, err = h.obj.PutObjectTagging(r.Context(), t, tagSet); err != nil {
|
if _, err = h.obj.PutObjectTagging(r.Context(), tagPrm); err != nil {
|
||||||
h.logAndSendError(w, "could not upload object tagging", reqInfo, err)
|
h.logAndSendError(w, "could not upload object tagging", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h.log.Info("object is copied",
|
h.log.Info("object is copied",
|
||||||
zap.String("bucket", objInfo.Bucket),
|
zap.String("bucket", dstObjInfo.Bucket),
|
||||||
zap.String("object", objInfo.Name),
|
zap.String("object", dstObjInfo.Name),
|
||||||
zap.Stringer("object_id", objInfo.ID))
|
zap.Stringer("object_id", dstObjInfo.ID))
|
||||||
|
|
||||||
s := &SendNotificationParams{
|
s := &SendNotificationParams{
|
||||||
Event: EventObjectCreatedCopy,
|
Event: EventObjectCreatedCopy,
|
||||||
NotificationInfo: data.NotificationInfoFromObject(objInfo),
|
NotificationInfo: data.NotificationInfoFromObject(dstObjInfo),
|
||||||
BktInfo: dstBktInfo,
|
BktInfo: dstBktInfo,
|
||||||
ReqInfo: reqInfo,
|
ReqInfo: reqInfo,
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,7 +141,7 @@ func createTestObject(hc *handlerContext, bktInfo *data.BucketInfo, objName stri
|
||||||
object.AttributeTimestamp: strconv.FormatInt(time.Now().UTC().Unix(), 10),
|
object.AttributeTimestamp: strconv.FormatInt(time.Now().UTC().Unix(), 10),
|
||||||
}
|
}
|
||||||
|
|
||||||
objInfo, err := hc.Layer().PutObject(hc.Context(), &layer.PutObjectParams{
|
extObjInfo, err := hc.Layer().PutObject(hc.Context(), &layer.PutObjectParams{
|
||||||
BktInfo: bktInfo,
|
BktInfo: bktInfo,
|
||||||
Object: objName,
|
Object: objName,
|
||||||
Size: int64(len(content)),
|
Size: int64(len(content)),
|
||||||
|
@ -150,7 +150,7 @@ func createTestObject(hc *handlerContext, bktInfo *data.BucketInfo, objName stri
|
||||||
})
|
})
|
||||||
require.NoError(hc.t, err)
|
require.NoError(hc.t, err)
|
||||||
|
|
||||||
return objInfo
|
return extObjInfo.ObjectInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareTestRequest(hc *handlerContext, bktName, objName string, body interface{}) (*httptest.ResponseRecorder, *http.Request) {
|
func prepareTestRequest(hc *handlerContext, bktName, objName string, body interface{}) (*httptest.ResponseRecorder, *http.Request) {
|
||||||
|
|
|
@ -399,19 +399,24 @@ func (h *handler) CompleteMultipartUploadHandler(w http.ResponseWriter, r *http.
|
||||||
Parts: reqBody.Parts,
|
Parts: reqBody.Parts,
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadData, objInfo, err := h.obj.CompleteMultipartUpload(r.Context(), c)
|
uploadData, extendedObjInfo, err := h.obj.CompleteMultipartUpload(r.Context(), c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not complete multipart upload", reqInfo, err, additional...)
|
h.logAndSendError(w, "could not complete multipart upload", reqInfo, err, additional...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
objInfo := extendedObjInfo.ObjectInfo
|
||||||
|
|
||||||
if len(uploadData.TagSet) != 0 {
|
if len(uploadData.TagSet) != 0 {
|
||||||
t := &layer.ObjectVersion{
|
tagPrm := &layer.PutObjectTaggingParams{
|
||||||
BktInfo: bktInfo,
|
ObjectVersion: &layer.ObjectVersion{
|
||||||
ObjectName: objInfo.Name,
|
BktInfo: bktInfo,
|
||||||
VersionID: objInfo.VersionID(),
|
ObjectName: objInfo.Name,
|
||||||
|
VersionID: objInfo.VersionID(),
|
||||||
|
},
|
||||||
|
TagSet: uploadData.TagSet,
|
||||||
|
NodeVersion: extendedObjInfo.NodeVersion,
|
||||||
}
|
}
|
||||||
if _, err = h.obj.PutObjectTagging(r.Context(), t, uploadData.TagSet); err != nil {
|
if _, err = h.obj.PutObjectTagging(r.Context(), tagPrm); err != nil {
|
||||||
h.logAndSendError(w, "could not put tagging file of completed multipart upload", reqInfo, err, additional...)
|
h.logAndSendError(w, "could not put tagging file of completed multipart upload", reqInfo, err, additional...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -197,7 +197,7 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName)
|
bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not get bucket info", reqInfo, err)
|
h.logAndSendError(w, "could not get bucket objInfo", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,17 +246,18 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := h.obj.PutObject(r.Context(), params)
|
extendedObjInfo, err := h.obj.PutObject(r.Context(), params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_, err2 := io.Copy(io.Discard, r.Body)
|
_, err2 := io.Copy(io.Discard, r.Body)
|
||||||
err3 := r.Body.Close()
|
err3 := r.Body.Close()
|
||||||
h.logAndSendError(w, "could not upload object", reqInfo, err, zap.Errors("body close errors", []error{err2, err3}))
|
h.logAndSendError(w, "could not upload object", reqInfo, err, zap.Errors("body close errors", []error{err2, err3}))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
objInfo := extendedObjInfo.ObjectInfo
|
||||||
|
|
||||||
s := &SendNotificationParams{
|
s := &SendNotificationParams{
|
||||||
Event: EventObjectCreatedPut,
|
Event: EventObjectCreatedPut,
|
||||||
NotificationInfo: data.NotificationInfoFromObject(info),
|
NotificationInfo: data.NotificationInfoFromObject(objInfo),
|
||||||
BktInfo: bktInfo,
|
BktInfo: bktInfo,
|
||||||
ReqInfo: reqInfo,
|
ReqInfo: reqInfo,
|
||||||
}
|
}
|
||||||
|
@ -265,19 +266,23 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if containsACL {
|
if containsACL {
|
||||||
if newEaclTable, err = h.getNewEAclTable(r, bktInfo, info); err != nil {
|
if newEaclTable, err = h.getNewEAclTable(r, bktInfo, objInfo); err != nil {
|
||||||
h.logAndSendError(w, "could not get new eacl table", reqInfo, err)
|
h.logAndSendError(w, "could not get new eacl table", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t := &layer.ObjectVersion{
|
|
||||||
BktInfo: bktInfo,
|
|
||||||
ObjectName: info.Name,
|
|
||||||
VersionID: info.VersionID(),
|
|
||||||
}
|
|
||||||
if tagSet != nil {
|
if tagSet != nil {
|
||||||
if _, err = h.obj.PutObjectTagging(r.Context(), t, tagSet); err != nil {
|
tagPrm := &layer.PutObjectTaggingParams{
|
||||||
|
ObjectVersion: &layer.ObjectVersion{
|
||||||
|
BktInfo: bktInfo,
|
||||||
|
ObjectName: objInfo.Name,
|
||||||
|
VersionID: objInfo.VersionID(),
|
||||||
|
},
|
||||||
|
TagSet: tagSet,
|
||||||
|
NodeVersion: extendedObjInfo.NodeVersion,
|
||||||
|
}
|
||||||
|
if _, err = h.obj.PutObjectTagging(r.Context(), tagPrm); err != nil {
|
||||||
h.logAndSendError(w, "could not upload object tagging", reqInfo, err)
|
h.logAndSendError(w, "could not upload object tagging", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -297,13 +302,13 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.VersioningEnabled() {
|
if settings.VersioningEnabled() {
|
||||||
w.Header().Set(api.AmzVersionID, info.VersionID())
|
w.Header().Set(api.AmzVersionID, objInfo.VersionID())
|
||||||
}
|
}
|
||||||
if encryption.Enabled() {
|
if encryption.Enabled() {
|
||||||
addSSECHeaders(w.Header(), r.Header)
|
addSSECHeaders(w.Header(), r.Header)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set(api.ETag, info.HashSum)
|
w.Header().Set(api.ETag, objInfo.HashSum)
|
||||||
api.WriteSuccessResponseHeadersOnly(w)
|
api.WriteSuccessResponseHeadersOnly(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,15 +436,16 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
Header: metadata,
|
Header: metadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := h.obj.PutObject(r.Context(), params)
|
extendedObjInfo, err := h.obj.PutObject(r.Context(), params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not upload object", reqInfo, err)
|
h.logAndSendError(w, "could not upload object", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
objInfo := extendedObjInfo.ObjectInfo
|
||||||
|
|
||||||
s := &SendNotificationParams{
|
s := &SendNotificationParams{
|
||||||
Event: EventObjectCreatedPost,
|
Event: EventObjectCreatedPost,
|
||||||
NotificationInfo: data.NotificationInfoFromObject(info),
|
NotificationInfo: data.NotificationInfoFromObject(objInfo),
|
||||||
BktInfo: bktInfo,
|
BktInfo: bktInfo,
|
||||||
ReqInfo: reqInfo,
|
ReqInfo: reqInfo,
|
||||||
}
|
}
|
||||||
|
@ -453,20 +459,23 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
r.Header.Set(api.AmzGrantWrite, "")
|
r.Header.Set(api.AmzGrantWrite, "")
|
||||||
r.Header.Set(api.AmzGrantRead, "")
|
r.Header.Set(api.AmzGrantRead, "")
|
||||||
|
|
||||||
if newEaclTable, err = h.getNewEAclTable(r, bktInfo, info); err != nil {
|
if newEaclTable, err = h.getNewEAclTable(r, bktInfo, objInfo); err != nil {
|
||||||
h.logAndSendError(w, "could not get new eacl table", reqInfo, err)
|
h.logAndSendError(w, "could not get new eacl table", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t := &layer.ObjectVersion{
|
|
||||||
BktInfo: bktInfo,
|
|
||||||
ObjectName: info.Name,
|
|
||||||
VersionID: info.VersionID(),
|
|
||||||
}
|
|
||||||
|
|
||||||
if tagSet != nil {
|
if tagSet != nil {
|
||||||
if _, err = h.obj.PutObjectTagging(r.Context(), t, tagSet); err != nil {
|
tagPrm := &layer.PutObjectTaggingParams{
|
||||||
|
ObjectVersion: &layer.ObjectVersion{
|
||||||
|
BktInfo: bktInfo,
|
||||||
|
ObjectName: objInfo.Name,
|
||||||
|
VersionID: objInfo.VersionID(),
|
||||||
|
},
|
||||||
|
NodeVersion: extendedObjInfo.NodeVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = h.obj.PutObjectTagging(r.Context(), tagPrm); err != nil {
|
||||||
h.logAndSendError(w, "could not upload object tagging", reqInfo, err)
|
h.logAndSendError(w, "could not upload object tagging", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -488,7 +497,7 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
if settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo); err != nil {
|
if settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo); err != nil {
|
||||||
h.log.Warn("couldn't get bucket versioning", zap.String("bucket name", reqInfo.BucketName), zap.Error(err))
|
h.log.Warn("couldn't get bucket versioning", zap.String("bucket name", reqInfo.BucketName), zap.Error(err))
|
||||||
} else if settings.VersioningEnabled() {
|
} else if settings.VersioningEnabled() {
|
||||||
w.Header().Set(api.AmzVersionID, info.VersionID())
|
w.Header().Set(api.AmzVersionID, objInfo.VersionID())
|
||||||
}
|
}
|
||||||
|
|
||||||
if redirectURL := auth.MultipartFormValue(r, "success_action_redirect"); redirectURL != "" {
|
if redirectURL := auth.MultipartFormValue(r, "success_action_redirect"); redirectURL != "" {
|
||||||
|
@ -503,9 +512,9 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
case "201":
|
case "201":
|
||||||
status = http.StatusCreated
|
status = http.StatusCreated
|
||||||
resp := &PostResponse{
|
resp := &PostResponse{
|
||||||
Bucket: info.Bucket,
|
Bucket: objInfo.Bucket,
|
||||||
Key: info.Name,
|
Key: objInfo.Name,
|
||||||
ETag: info.HashSum,
|
ETag: objInfo.HashSum,
|
||||||
}
|
}
|
||||||
w.WriteHeader(status)
|
w.WriteHeader(status)
|
||||||
if _, err = w.Write(api.EncodeResponse(resp)); err != nil {
|
if _, err = w.Write(api.EncodeResponse(resp)); err != nil {
|
||||||
|
@ -515,7 +524,7 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set(api.ETag, info.HashSum)
|
w.Header().Set(api.ETag, objInfo.HashSum)
|
||||||
w.WriteHeader(status)
|
w.WriteHeader(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,13 +38,15 @@ func (h *handler) PutObjectTaggingHandler(w http.ResponseWriter, r *http.Request
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
p := &layer.ObjectVersion{
|
tagPrm := &layer.PutObjectTaggingParams{
|
||||||
BktInfo: bktInfo,
|
ObjectVersion: &layer.ObjectVersion{
|
||||||
ObjectName: reqInfo.ObjectName,
|
BktInfo: bktInfo,
|
||||||
VersionID: reqInfo.URL.Query().Get(api.QueryVersionID),
|
ObjectName: reqInfo.ObjectName,
|
||||||
|
VersionID: reqInfo.URL.Query().Get(api.QueryVersionID),
|
||||||
|
},
|
||||||
|
TagSet: tagSet,
|
||||||
}
|
}
|
||||||
|
nodeVersion, err := h.obj.PutObjectTagging(r.Context(), tagPrm)
|
||||||
nodeVersion, err := h.obj.PutObjectTagging(r.Context(), p, tagSet)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not put object tagging", reqInfo, err)
|
h.logAndSendError(w, "could not put object tagging", reqInfo, err)
|
||||||
return
|
return
|
||||||
|
@ -83,13 +85,15 @@ func (h *handler) GetObjectTaggingHandler(w http.ResponseWriter, r *http.Request
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
p := &layer.ObjectVersion{
|
tagPrm := &layer.GetObjectTaggingParams{
|
||||||
BktInfo: bktInfo,
|
ObjectVersion: &layer.ObjectVersion{
|
||||||
ObjectName: reqInfo.ObjectName,
|
BktInfo: bktInfo,
|
||||||
VersionID: reqInfo.URL.Query().Get(api.QueryVersionID),
|
ObjectName: reqInfo.ObjectName,
|
||||||
|
VersionID: reqInfo.URL.Query().Get(api.QueryVersionID),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
versionID, tagSet, err := h.obj.GetObjectTagging(r.Context(), p)
|
versionID, tagSet, err := h.obj.GetObjectTagging(r.Context(), tagPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not get object tagging", reqInfo, err)
|
h.logAndSendError(w, "could not get object tagging", reqInfo, err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -213,13 +213,13 @@ type (
|
||||||
PutBucketTagging(ctx context.Context, bktInfo *data.BucketInfo, tagSet map[string]string) error
|
PutBucketTagging(ctx context.Context, bktInfo *data.BucketInfo, tagSet map[string]string) error
|
||||||
DeleteBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) error
|
DeleteBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) error
|
||||||
|
|
||||||
GetObjectTagging(ctx context.Context, p *ObjectVersion) (string, map[string]string, error)
|
GetObjectTagging(ctx context.Context, p *GetObjectTaggingParams) (string, map[string]string, error)
|
||||||
PutObjectTagging(ctx context.Context, p *ObjectVersion, tagSet map[string]string) (*data.NodeVersion, error)
|
PutObjectTagging(ctx context.Context, p *PutObjectTaggingParams) (*data.NodeVersion, error)
|
||||||
DeleteObjectTagging(ctx context.Context, p *ObjectVersion) (*data.NodeVersion, error)
|
DeleteObjectTagging(ctx context.Context, p *ObjectVersion) (*data.NodeVersion, error)
|
||||||
|
|
||||||
PutObject(ctx context.Context, p *PutObjectParams) (*data.ObjectInfo, error)
|
PutObject(ctx context.Context, p *PutObjectParams) (*data.ExtendedObjectInfo, error)
|
||||||
|
|
||||||
CopyObject(ctx context.Context, p *CopyObjectParams) (*data.ObjectInfo, error)
|
CopyObject(ctx context.Context, p *CopyObjectParams) (*data.ExtendedObjectInfo, error)
|
||||||
|
|
||||||
ListObjectsV1(ctx context.Context, p *ListObjectsParamsV1) (*ListObjectsInfoV1, error)
|
ListObjectsV1(ctx context.Context, p *ListObjectsParamsV1) (*ListObjectsInfoV1, error)
|
||||||
ListObjectsV2(ctx context.Context, p *ListObjectsParamsV2) (*ListObjectsInfoV2, error)
|
ListObjectsV2(ctx context.Context, p *ListObjectsParamsV2) (*ListObjectsInfoV2, error)
|
||||||
|
@ -228,7 +228,7 @@ type (
|
||||||
DeleteObjects(ctx context.Context, p *DeleteObjectParams) []*VersionedObject
|
DeleteObjects(ctx context.Context, p *DeleteObjectParams) []*VersionedObject
|
||||||
|
|
||||||
CreateMultipartUpload(ctx context.Context, p *CreateMultipartParams) error
|
CreateMultipartUpload(ctx context.Context, p *CreateMultipartParams) error
|
||||||
CompleteMultipartUpload(ctx context.Context, p *CompleteMultipartParams) (*UploadData, *data.ObjectInfo, error)
|
CompleteMultipartUpload(ctx context.Context, p *CompleteMultipartParams) (*UploadData, *data.ExtendedObjectInfo, error)
|
||||||
UploadPart(ctx context.Context, p *UploadPartParams) (string, error)
|
UploadPart(ctx context.Context, p *UploadPartParams) (string, error)
|
||||||
UploadPartCopy(ctx context.Context, p *UploadCopyParams) (*data.ObjectInfo, error)
|
UploadPartCopy(ctx context.Context, p *UploadCopyParams) (*data.ObjectInfo, error)
|
||||||
ListMultipartUploads(ctx context.Context, p *ListMultipartUploadsParams) (*ListMultipartUploadsInfo, error)
|
ListMultipartUploads(ctx context.Context, p *ListMultipartUploadsParams) (*ListMultipartUploadsInfo, error)
|
||||||
|
@ -481,7 +481,7 @@ func (n *layer) GetExtendedObjectInfo(ctx context.Context, p *HeadObjectParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CopyObject from one bucket into another bucket.
|
// CopyObject from one bucket into another bucket.
|
||||||
func (n *layer) CopyObject(ctx context.Context, p *CopyObjectParams) (*data.ObjectInfo, error) {
|
func (n *layer) CopyObject(ctx context.Context, p *CopyObjectParams) (*data.ExtendedObjectInfo, error) {
|
||||||
pr, pw := io.Pipe()
|
pr, pw := io.Pipe()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
|
|
@ -349,7 +349,7 @@ func (x *multiObjectReader) Read(p []byte) (n int, err error) {
|
||||||
return n + next, err
|
return n + next, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *layer) CompleteMultipartUpload(ctx context.Context, p *CompleteMultipartParams) (*UploadData, *data.ObjectInfo, error) {
|
func (n *layer) CompleteMultipartUpload(ctx context.Context, p *CompleteMultipartParams) (*UploadData, *data.ExtendedObjectInfo, error) {
|
||||||
for i := 1; i < len(p.Parts); i++ {
|
for i := 1; i < len(p.Parts); i++ {
|
||||||
if p.Parts[i].PartNumber <= p.Parts[i-1].PartNumber {
|
if p.Parts[i].PartNumber <= p.Parts[i-1].PartNumber {
|
||||||
return nil, nil, errors.GetAPIError(errors.ErrInvalidPartOrder)
|
return nil, nil, errors.GetAPIError(errors.ErrInvalidPartOrder)
|
||||||
|
@ -433,7 +433,7 @@ func (n *layer) CompleteMultipartUpload(ctx context.Context, p *CompleteMultipar
|
||||||
|
|
||||||
r.prm.bktInfo = p.Info.Bkt
|
r.prm.bktInfo = p.Info.Bkt
|
||||||
|
|
||||||
obj, err := n.PutObject(ctx, &PutObjectParams{
|
extObjInfo, err := n.PutObject(ctx, &PutObjectParams{
|
||||||
BktInfo: p.Info.Bkt,
|
BktInfo: p.Info.Bkt,
|
||||||
Object: p.Info.Key,
|
Object: p.Info.Key,
|
||||||
Reader: r,
|
Reader: r,
|
||||||
|
@ -464,7 +464,7 @@ func (n *layer) CompleteMultipartUpload(ctx context.Context, p *CompleteMultipar
|
||||||
n.cache.DeleteObject(addr)
|
n.cache.DeleteObject(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return uploadData, obj, n.treeService.DeleteMultipartUpload(ctx, p.Info.Bkt, multipartInfo.ID)
|
return uploadData, extObjInfo, n.treeService.DeleteMultipartUpload(ctx, p.Info.Bkt, multipartInfo.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *layer) ListMultipartUploads(ctx context.Context, p *ListMultipartUploadsParams) (*ListMultipartUploadsInfo, error) {
|
func (n *layer) ListMultipartUploads(ctx context.Context, p *ListMultipartUploadsParams) (*ListMultipartUploadsInfo, error) {
|
||||||
|
|
|
@ -184,7 +184,7 @@ func ParseCompletedPartHeader(hdr string) (*Part, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutObject stores object into NeoFS, took payload from io.Reader.
|
// PutObject stores object into NeoFS, took payload from io.Reader.
|
||||||
func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*data.ObjectInfo, error) {
|
func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*data.ExtendedObjectInfo, error) {
|
||||||
owner := n.Owner(ctx)
|
owner := n.Owner(ctx)
|
||||||
|
|
||||||
bktSettings, err := n.GetBucketSettings(ctx, p.BktInfo)
|
bktSettings, err := n.GetBucketSettings(ctx, p.BktInfo)
|
||||||
|
@ -294,7 +294,7 @@ func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*data.Object
|
||||||
|
|
||||||
n.cache.PutObjectWithName(owner, extendedObjInfo)
|
n.cache.PutObjectWithName(owner, extendedObjInfo)
|
||||||
|
|
||||||
return objInfo, nil
|
return extendedObjInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *layer) headLastVersionIfNotDeleted(ctx context.Context, bkt *data.BucketInfo, objectName string) (*data.ExtendedObjectInfo, error) {
|
func (n *layer) headLastVersionIfNotDeleted(ctx context.Context, bkt *data.BucketInfo, objectName string) (*data.ExtendedObjectInfo, error) {
|
||||||
|
|
|
@ -32,14 +32,9 @@ func (n *layer) PutLockInfo(ctx context.Context, p *PutLockInfoParams) (err erro
|
||||||
// sometimes node version can be provided from executing context
|
// sometimes node version can be provided from executing context
|
||||||
// if not, then receive node version from tree service
|
// if not, then receive node version from tree service
|
||||||
if versionNode == nil {
|
if versionNode == nil {
|
||||||
// check cache if node version is stored inside extendedObjectVersion
|
versionNode, err = n.getNodeVersionFromCacheOrNeofs(ctx, p.ObjVersion)
|
||||||
versionNode = n.getNodeVersionFromCache(n.Owner(ctx), p.ObjVersion)
|
if err != nil {
|
||||||
if versionNode == nil {
|
return err
|
||||||
// else get node version from tree service
|
|
||||||
versionNode, err = n.getNodeVersion(ctx, p.ObjVersion)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,6 +100,17 @@ func (n *layer) PutLockInfo(ctx context.Context, p *PutLockInfoParams) (err erro
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *layer) getNodeVersionFromCacheOrNeofs(ctx context.Context, objVersion *ObjectVersion) (nodeVersion *data.NodeVersion, err error) {
|
||||||
|
// check cache if node version is stored inside extendedObjectVersion
|
||||||
|
nodeVersion = n.getNodeVersionFromCache(n.Owner(ctx), objVersion)
|
||||||
|
if nodeVersion == nil {
|
||||||
|
// else get node version from tree service
|
||||||
|
return n.getNodeVersion(ctx, objVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeVersion, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (n *layer) putLockObject(ctx context.Context, bktInfo *data.BucketInfo, objID oid.ID, lock *data.ObjectLock, copiesNumber uint32) (oid.ID, error) {
|
func (n *layer) putLockObject(ctx context.Context, bktInfo *data.BucketInfo, objID oid.ID, lock *data.ObjectLock, copiesNumber uint32) (oid.ID, error) {
|
||||||
prm := PrmObjectCreate{
|
prm := PrmObjectCreate{
|
||||||
Container: bktInfo.CID,
|
Container: bktInfo.CID,
|
||||||
|
|
|
@ -11,26 +11,45 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (n *layer) GetObjectTagging(ctx context.Context, p *ObjectVersion) (string, map[string]string, error) {
|
type GetObjectTaggingParams struct {
|
||||||
|
ObjectVersion *ObjectVersion
|
||||||
|
|
||||||
|
// NodeVersion can be nil. If not nil we save one request to tree service.
|
||||||
|
NodeVersion *data.NodeVersion // optional
|
||||||
|
}
|
||||||
|
|
||||||
|
type PutObjectTaggingParams struct {
|
||||||
|
ObjectVersion *ObjectVersion
|
||||||
|
TagSet map[string]string
|
||||||
|
|
||||||
|
// NodeVersion can be nil. If not nil we save one request to tree service.
|
||||||
|
NodeVersion *data.NodeVersion // optional
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *layer) GetObjectTagging(ctx context.Context, p *GetObjectTaggingParams) (string, map[string]string, error) {
|
||||||
|
var err error
|
||||||
owner := n.Owner(ctx)
|
owner := n.Owner(ctx)
|
||||||
|
|
||||||
if len(p.VersionID) != 0 && p.VersionID != data.UnversionedObjectVersionID {
|
if len(p.ObjectVersion.VersionID) != 0 && p.ObjectVersion.VersionID != data.UnversionedObjectVersionID {
|
||||||
if tags := n.cache.GetTagging(owner, objectTaggingCacheKey(p)); tags != nil {
|
if tags := n.cache.GetTagging(owner, objectTaggingCacheKey(p.ObjectVersion)); tags != nil {
|
||||||
return p.VersionID, tags, nil
|
return p.ObjectVersion.VersionID, tags, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
version, err := n.getNodeVersion(ctx, p)
|
nodeVersion := p.NodeVersion
|
||||||
if err != nil {
|
if nodeVersion == nil {
|
||||||
return "", nil, err
|
nodeVersion, err = n.getNodeVersionFromCacheOrNeofs(ctx, p.ObjectVersion)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p.VersionID = version.OID.EncodeToString()
|
p.ObjectVersion.VersionID = nodeVersion.OID.EncodeToString()
|
||||||
|
|
||||||
if tags := n.cache.GetTagging(owner, objectTaggingCacheKey(p)); tags != nil {
|
if tags := n.cache.GetTagging(owner, objectTaggingCacheKey(p.ObjectVersion)); tags != nil {
|
||||||
return p.VersionID, tags, nil
|
return p.ObjectVersion.VersionID, tags, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tags, err := n.treeService.GetObjectTagging(ctx, p.BktInfo, version)
|
tags, err := n.treeService.GetObjectTagging(ctx, p.ObjectVersion.BktInfo, nodeVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errorsStd.Is(err, ErrNodeNotFound) {
|
if errorsStd.Is(err, ErrNodeNotFound) {
|
||||||
return "", nil, errors.GetAPIError(errors.ErrNoSuchKey)
|
return "", nil, errors.GetAPIError(errors.ErrNoSuchKey)
|
||||||
|
@ -38,19 +57,22 @@ func (n *layer) GetObjectTagging(ctx context.Context, p *ObjectVersion) (string,
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
n.cache.PutTagging(owner, objectTaggingCacheKey(p), tags)
|
n.cache.PutTagging(owner, objectTaggingCacheKey(p.ObjectVersion), tags)
|
||||||
|
|
||||||
return p.VersionID, tags, nil
|
return p.ObjectVersion.VersionID, tags, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *layer) PutObjectTagging(ctx context.Context, p *ObjectVersion, tagSet map[string]string) (*data.NodeVersion, error) {
|
func (n *layer) PutObjectTagging(ctx context.Context, p *PutObjectTaggingParams) (nodeVersion *data.NodeVersion, err error) {
|
||||||
version, err := n.getNodeVersion(ctx, p)
|
nodeVersion = p.NodeVersion
|
||||||
if err != nil {
|
if nodeVersion == nil {
|
||||||
return nil, err
|
nodeVersion, err = n.getNodeVersionFromCacheOrNeofs(ctx, p.ObjectVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p.VersionID = version.OID.EncodeToString()
|
p.ObjectVersion.VersionID = nodeVersion.OID.EncodeToString()
|
||||||
|
|
||||||
err = n.treeService.PutObjectTagging(ctx, p.BktInfo, version, tagSet)
|
err = n.treeService.PutObjectTagging(ctx, p.ObjectVersion.BktInfo, nodeVersion, p.TagSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errorsStd.Is(err, ErrNodeNotFound) {
|
if errorsStd.Is(err, ErrNodeNotFound) {
|
||||||
return nil, errors.GetAPIError(errors.ErrNoSuchKey)
|
return nil, errors.GetAPIError(errors.ErrNoSuchKey)
|
||||||
|
@ -58,9 +80,9 @@ func (n *layer) PutObjectTagging(ctx context.Context, p *ObjectVersion, tagSet m
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
n.cache.PutTagging(n.Owner(ctx), objectTaggingCacheKey(p), tagSet)
|
n.cache.PutTagging(n.Owner(ctx), objectTaggingCacheKey(p.ObjectVersion), p.TagSet)
|
||||||
|
|
||||||
return version, nil
|
return nodeVersion, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *layer) DeleteObjectTagging(ctx context.Context, p *ObjectVersion) (*data.NodeVersion, error) {
|
func (n *layer) DeleteObjectTagging(ctx context.Context, p *ObjectVersion) (*data.NodeVersion, error) {
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (tc *testContext) putObject(content []byte) *data.ObjectInfo {
|
func (tc *testContext) putObject(content []byte) *data.ObjectInfo {
|
||||||
objInfo, err := tc.layer.PutObject(tc.ctx, &PutObjectParams{
|
extObjInfo, err := tc.layer.PutObject(tc.ctx, &PutObjectParams{
|
||||||
BktInfo: tc.bktInfo,
|
BktInfo: tc.bktInfo,
|
||||||
Object: tc.obj,
|
Object: tc.obj,
|
||||||
Size: int64(len(content)),
|
Size: int64(len(content)),
|
||||||
|
@ -27,7 +27,7 @@ func (tc *testContext) putObject(content []byte) *data.ObjectInfo {
|
||||||
})
|
})
|
||||||
require.NoError(tc.t, err)
|
require.NoError(tc.t, err)
|
||||||
|
|
||||||
return objInfo
|
return extObjInfo.ObjectInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tc *testContext) getObject(objectName, versionID string, needError bool) (*data.ObjectInfo, []byte) {
|
func (tc *testContext) getObject(objectName, versionID string, needError bool) (*data.ObjectInfo, []byte) {
|
||||||
|
|
Loading…
Reference in a new issue