From 88c392d0244b1620179f8569845286a85a8ec1ac Mon Sep 17 00:00:00 2001 From: Denis Kirillov Date: Tue, 28 Jun 2022 16:35:05 +0300 Subject: [PATCH] [#490] Optimize GetObjectTaggingAndLock Signed-off-by: Denis Kirillov --- api/handler/acl.go | 6 +++--- api/handler/attributes.go | 11 ++++------- api/handler/copy.go | 7 +++---- api/handler/get.go | 8 ++++---- api/handler/head.go | 15 ++++++--------- api/handler/multipart_upload.go | 6 +++--- api/layer/compound.go | 13 +++++++------ api/layer/layer.go | 6 +++--- api/layer/object.go | 22 ++++++++++++++++------ api/layer/versioning_test.go | 6 +++--- 10 files changed, 52 insertions(+), 48 deletions(-) diff --git a/api/handler/acl.go b/api/handler/acl.go index 36a5de61..4c245087 100644 --- a/api/handler/acl.go +++ b/api/handler/acl.go @@ -307,7 +307,7 @@ func (h *handler) GetObjectACLHandler(w http.ResponseWriter, r *http.Request) { return } - if err = api.EncodeToResponse(w, h.encodeObjectACL(bucketACL, reqInfo.BucketName, objInfo.Version())); err != nil { + if err = api.EncodeToResponse(w, h.encodeObjectACL(bucketACL, reqInfo.BucketName, objInfo.ObjectInfo.Version())); err != nil { h.logAndSendError(w, "failed to encode response", reqInfo, err) } } @@ -363,7 +363,7 @@ func (h *handler) PutObjectACLHandler(w http.ResponseWriter, r *http.Request) { VersionID: versionID, } - objInfo, err := h.obj.GetObjectInfo(r.Context(), p) + extendedInfo, err := h.obj.GetObjectInfo(r.Context(), p) if err != nil { h.logAndSendError(w, "could not get object info", reqInfo, err) return @@ -377,7 +377,7 @@ func (h *handler) PutObjectACLHandler(w http.ResponseWriter, r *http.Request) { if updated { s := &SendNotificationParams{ Event: EventObjectACLPut, - ObjInfo: objInfo, + ObjInfo: extendedInfo.ObjectInfo, BktInfo: bktInfo, ReqInfo: reqInfo, } diff --git a/api/handler/attributes.go b/api/handler/attributes.go index 377be5e9..5c0c9fdb 100644 --- a/api/handler/attributes.go +++ b/api/handler/attributes.go @@ -66,12 +66,7 @@ var validAttributes = map[string]struct{}{ } func (h *handler) GetObjectAttributesHandler(w http.ResponseWriter, r *http.Request) { - var ( - err error - info *data.ObjectInfo - - reqInfo = api.GetReqInfo(r.Context()) - ) + reqInfo := api.GetReqInfo(r.Context()) params, err := parseGetObjectAttributeArgs(r) if err != nil { @@ -91,10 +86,12 @@ func (h *handler) GetObjectAttributesHandler(w http.ResponseWriter, r *http.Requ VersionID: params.VersionID, } - if info, err = h.obj.GetObjectInfo(r.Context(), p); err != nil { + extendedInfo, err := h.obj.GetObjectInfo(r.Context(), p) + if err != nil { h.logAndSendError(w, "could not fetch object info", reqInfo, err) return } + info := extendedInfo.ObjectInfo if err = checkPreconditions(info, params.Conditional); err != nil { h.logAndSendError(w, "precondition failed", reqInfo, err) diff --git a/api/handler/copy.go b/api/handler/copy.go index 366ab015..d260430c 100644 --- a/api/handler/copy.go +++ b/api/handler/copy.go @@ -7,7 +7,6 @@ import ( "time" "github.com/nspcc-dev/neofs-s3-gw/api" - "github.com/nspcc-dev/neofs-s3-gw/api/data" "github.com/nspcc-dev/neofs-s3-gw/api/errors" "github.com/nspcc-dev/neofs-s3-gw/api/layer" "github.com/nspcc-dev/neofs-sdk-go/session" @@ -34,8 +33,6 @@ func path2BucketObject(path string) (bucket, prefix string) { func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) { var ( versionID string - err error - info *data.ObjectInfo metadata map[string]string sessionTokenEACL *session.Container @@ -92,10 +89,12 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) { } } - if info, err = h.obj.GetObjectInfo(r.Context(), p); err != nil { + extendedInfo, err := h.obj.GetObjectInfo(r.Context(), p) + if err != nil { h.logAndSendError(w, "could not find object", reqInfo, err) return } + info := extendedInfo.ObjectInfo if err = checkPreconditions(info, args.Conditional); err != nil { h.logAndSendError(w, "precondition failed", reqInfo, errors.GetAPIError(errors.ErrPreconditionFailed)) diff --git a/api/handler/get.go b/api/handler/get.go index 04a7ab98..6ea478f8 100644 --- a/api/handler/get.go +++ b/api/handler/get.go @@ -98,8 +98,6 @@ func writeHeaders(h http.Header, info *data.ObjectInfo, tagSetLength int) { func (h *handler) GetObjectHandler(w http.ResponseWriter, r *http.Request) { var ( - err error - info *data.ObjectInfo params *layer.RangeParams reqInfo = api.GetReqInfo(r.Context()) @@ -123,10 +121,12 @@ func (h *handler) GetObjectHandler(w http.ResponseWriter, r *http.Request) { VersionID: reqInfo.URL.Query().Get(api.QueryVersionID), } - if info, err = h.obj.GetObjectInfo(r.Context(), p); err != nil { + extendedInfo, err := h.obj.GetObjectInfo(r.Context(), p) + if err != nil { h.logAndSendError(w, "could not find object", reqInfo, err) return } + info := extendedInfo.ObjectInfo if err = checkPreconditions(info, conditional); err != nil { h.logAndSendError(w, "precondition failed", reqInfo, err) @@ -144,7 +144,7 @@ func (h *handler) GetObjectHandler(w http.ResponseWriter, r *http.Request) { VersionID: info.Version(), } - tagSet, lockInfo, err := h.obj.GetObjectTaggingAndLock(r.Context(), t) + tagSet, lockInfo, err := h.obj.GetObjectTaggingAndLock(r.Context(), t, extendedInfo.NodeVersion) if err != nil && !errors.IsS3Error(err, errors.ErrNoSuchKey) { h.logAndSendError(w, "could not get object meta data", reqInfo, err) return diff --git a/api/handler/head.go b/api/handler/head.go index fb980ebe..5ebd3aa1 100644 --- a/api/handler/head.go +++ b/api/handler/head.go @@ -26,12 +26,7 @@ func getRangeToDetectContentType(maxSize int64) *layer.RangeParams { } func (h *handler) HeadObjectHandler(w http.ResponseWriter, r *http.Request) { - var ( - err error - info *data.ObjectInfo - - reqInfo = api.GetReqInfo(r.Context()) - ) + reqInfo := api.GetReqInfo(r.Context()) bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName) if err != nil { @@ -51,10 +46,12 @@ func (h *handler) HeadObjectHandler(w http.ResponseWriter, r *http.Request) { VersionID: reqInfo.URL.Query().Get(api.QueryVersionID), } - if info, err = h.obj.GetObjectInfo(r.Context(), p); err != nil { - h.logAndSendError(w, "could not fetch object info", reqInfo, err) + extendedInfo, err := h.obj.GetObjectInfo(r.Context(), p) + if err != nil { + h.logAndSendError(w, "could not find object", reqInfo, err) return } + info := extendedInfo.ObjectInfo if err = checkPreconditions(info, conditional); err != nil { h.logAndSendError(w, "precondition failed", reqInfo, err) @@ -67,7 +64,7 @@ func (h *handler) HeadObjectHandler(w http.ResponseWriter, r *http.Request) { VersionID: info.Version(), } - tagSet, lockInfo, err := h.obj.GetObjectTaggingAndLock(r.Context(), t) + tagSet, lockInfo, err := h.obj.GetObjectTaggingAndLock(r.Context(), t, extendedInfo.NodeVersion) if err != nil && !errors.IsS3Error(err, errors.ErrNoSuchKey) { h.logAndSendError(w, "could not get object meta data", reqInfo, err) return diff --git a/api/handler/multipart_upload.go b/api/handler/multipart_upload.go index 221b17bf..3b884112 100644 --- a/api/handler/multipart_upload.go +++ b/api/handler/multipart_upload.go @@ -260,7 +260,7 @@ func (h *handler) UploadPartCopy(w http.ResponseWriter, r *http.Request) { return } - srcInfo, err := h.obj.GetObjectInfo(r.Context(), &layer.HeadObjectParams{ + extSrcInfo, err := h.obj.GetObjectInfo(r.Context(), &layer.HeadObjectParams{ BktInfo: srcBktInfo, Object: srcObject, VersionID: versionID, @@ -282,7 +282,7 @@ func (h *handler) UploadPartCopy(w http.ResponseWriter, r *http.Request) { return } - if err = checkPreconditions(srcInfo, args.Conditional); err != nil { + if err = checkPreconditions(extSrcInfo.ObjectInfo, args.Conditional); err != nil { h.logAndSendError(w, "precondition failed", reqInfo, errors.GetAPIError(errors.ErrPreconditionFailed), additional...) return @@ -294,7 +294,7 @@ func (h *handler) UploadPartCopy(w http.ResponseWriter, r *http.Request) { Bkt: bktInfo, Key: reqInfo.ObjectName, }, - SrcObjInfo: srcInfo, + SrcObjInfo: extSrcInfo.ObjectInfo, SrcBktInfo: srcBktInfo, PartNumber: partNumber, Range: srcRange, diff --git a/api/layer/compound.go b/api/layer/compound.go index 8645116f..c42abae5 100644 --- a/api/layer/compound.go +++ b/api/layer/compound.go @@ -9,7 +9,7 @@ import ( "go.uber.org/zap" ) -func (n *layer) GetObjectTaggingAndLock(ctx context.Context, objVersion *ObjectVersion) (map[string]string, *data.LockInfo, error) { +func (n *layer) GetObjectTaggingAndLock(ctx context.Context, objVersion *ObjectVersion, nodeVersion *data.NodeVersion) (map[string]string, *data.LockInfo, error) { var ( err error tags map[string]string @@ -22,13 +22,14 @@ func (n *layer) GetObjectTaggingAndLock(ctx context.Context, objVersion *ObjectV return tags, lockInfo, nil } - version, err := n.getNodeVersion(ctx, objVersion) - if err != nil { - return nil, nil, err + if nodeVersion == nil { + nodeVersion, err = n.getNodeVersion(ctx, objVersion) + if err != nil { + return nil, nil, err + } } - objVersion.VersionID = version.OID.EncodeToString() - tags, lockInfo, err = n.treeService.GetObjectTaggingAndLock(ctx, objVersion.BktInfo.CID, version) + tags, lockInfo, err = n.treeService.GetObjectTaggingAndLock(ctx, objVersion.BktInfo.CID, nodeVersion) if err != nil { if errorsStd.Is(err, ErrNodeNotFound) { return nil, nil, errors.GetAPIError(errors.ErrNoSuchKey) diff --git a/api/layer/layer.go b/api/layer/layer.go index bdb42d33..55dae465 100644 --- a/api/layer/layer.go +++ b/api/layer/layer.go @@ -215,7 +215,7 @@ type ( DeleteBucket(ctx context.Context, p *DeleteBucketParams) error GetObject(ctx context.Context, p *GetObjectParams) error - GetObjectInfo(ctx context.Context, p *HeadObjectParams) (*data.ObjectInfo, error) + GetObjectInfo(ctx context.Context, p *HeadObjectParams) (*data.ExtendedObjectInfo, error) GetLockInfo(ctx context.Context, obj *ObjectVersion) (*data.LockInfo, error) PutLockInfo(ctx context.Context, p *ObjectVersion, lock *data.ObjectLock) error @@ -252,7 +252,7 @@ type ( // Compound methods for optimizations // GetObjectTaggingAndLock unifies GetObjectTagging and GetLock methods in single tree service invocation. - GetObjectTaggingAndLock(ctx context.Context, p *ObjectVersion) (map[string]string, *data.LockInfo, error) + GetObjectTaggingAndLock(ctx context.Context, p *ObjectVersion, nodeVersion *data.NodeVersion) (map[string]string, *data.LockInfo, error) } ) @@ -428,7 +428,7 @@ func (n *layer) GetObject(ctx context.Context, p *GetObjectParams) error { } // GetObjectInfo returns meta information about the object. -func (n *layer) GetObjectInfo(ctx context.Context, p *HeadObjectParams) (*data.ObjectInfo, error) { +func (n *layer) GetObjectInfo(ctx context.Context, p *HeadObjectParams) (*data.ExtendedObjectInfo, error) { if len(p.VersionID) == 0 { return n.headLastVersionIfNotDeleted(ctx, p.BktInfo, p.Object) } diff --git a/api/layer/object.go b/api/layer/object.go index e0fd9565..d230624e 100644 --- a/api/layer/object.go +++ b/api/layer/object.go @@ -236,10 +236,10 @@ func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*data.Object return objInfo, nil } -func (n *layer) headLastVersionIfNotDeleted(ctx context.Context, bkt *data.BucketInfo, objectName string) (*data.ObjectInfo, error) { +func (n *layer) headLastVersionIfNotDeleted(ctx context.Context, bkt *data.BucketInfo, objectName string) (*data.ExtendedObjectInfo, error) { if addr := n.namesCache.Get(bkt.Name + "/" + objectName); addr != nil { if objInfo := n.objCache.GetObject(*addr); objInfo != nil { - return objInfo, nil + return &data.ExtendedObjectInfo{ObjectInfo: objInfo}, nil } } @@ -272,10 +272,14 @@ func (n *layer) headLastVersionIfNotDeleted(ctx context.Context, bkt *data.Bucke zap.Error(err)) } - return objInfo, nil + return &data.ExtendedObjectInfo{ + ObjectInfo: objInfo, + NodeVersion: node, + IsLatest: true, + }, nil } -func (n *layer) headVersion(ctx context.Context, bkt *data.BucketInfo, p *HeadObjectParams) (*data.ObjectInfo, error) { +func (n *layer) headVersion(ctx context.Context, bkt *data.BucketInfo, p *HeadObjectParams) (*data.ExtendedObjectInfo, error) { var err error var foundVersion *data.NodeVersion if p.VersionID == UnversionedObjectVersionID { @@ -304,7 +308,10 @@ func (n *layer) headVersion(ctx context.Context, bkt *data.BucketInfo, p *HeadOb } if objInfo := n.objCache.GetObject(newAddress(bkt.CID, foundVersion.OID)); objInfo != nil { - return objInfo, nil + return &data.ExtendedObjectInfo{ + ObjectInfo: objInfo, + NodeVersion: foundVersion, + }, nil } meta, err := n.objectHead(ctx, bkt, foundVersion.OID) @@ -325,7 +332,10 @@ func (n *layer) headVersion(ctx context.Context, bkt *data.BucketInfo, p *HeadOb zap.Error(err)) } - return objInfo, nil + return &data.ExtendedObjectInfo{ + ObjectInfo: objInfo, + NodeVersion: foundVersion, + }, nil } // objectDelete puts tombstone object into neofs. diff --git a/api/layer/versioning_test.go b/api/layer/versioning_test.go index d3dd8f06..23cd32c4 100644 --- a/api/layer/versioning_test.go +++ b/api/layer/versioning_test.go @@ -31,7 +31,7 @@ func (tc *testContext) putObject(content []byte) *data.ObjectInfo { } func (tc *testContext) getObject(objectName, versionID string, needError bool) (*data.ObjectInfo, []byte) { - objInfo, err := tc.layer.GetObjectInfo(tc.ctx, &HeadObjectParams{ + extendedInfo, err := tc.layer.GetObjectInfo(tc.ctx, &HeadObjectParams{ BktInfo: tc.bktInfo, Object: objectName, VersionID: versionID, @@ -44,13 +44,13 @@ func (tc *testContext) getObject(objectName, versionID string, needError bool) ( content := bytes.NewBuffer(nil) err = tc.layer.GetObject(tc.ctx, &GetObjectParams{ - ObjectInfo: objInfo, + ObjectInfo: extendedInfo.ObjectInfo, Writer: content, BucketInfo: tc.bktInfo, }) require.NoError(tc.t, err) - return objInfo, content.Bytes() + return extendedInfo.ObjectInfo, content.Bytes() } func (tc *testContext) deleteObject(objectName, versionID string) {