forked from TrueCloudLab/frostfs-s3-gw
[#196] Add tagging caching
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
987185b9e1
commit
5502fb97c3
5 changed files with 96 additions and 108 deletions
6
api/cache/buckets.go
vendored
6
api/cache/buckets.go
vendored
|
@ -71,7 +71,7 @@ func (b *BucketInfo) SettingsObjectName() string {
|
|||
return bktVersionSettingsObject
|
||||
}
|
||||
|
||||
// SettingsObjectKey is key to use in SystemCache.
|
||||
func (b *BucketInfo) SettingsObjectKey() string {
|
||||
return b.Name + bktVersionSettingsObject
|
||||
// SystemObjectKey is key to use in SystemCache.
|
||||
func (b *BucketInfo) SystemObjectKey(obj string) string {
|
||||
return b.Name + obj
|
||||
}
|
||||
|
|
|
@ -30,6 +30,11 @@ func (h *handler) PutObjectTaggingHandler(w http.ResponseWriter, r *http.Request
|
|||
return
|
||||
}
|
||||
|
||||
if err = h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
|
||||
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
p := &layer.HeadObjectParams{
|
||||
Bucket: reqInfo.BucketName,
|
||||
Object: reqInfo.ObjectName,
|
||||
|
@ -56,6 +61,11 @@ func (h *handler) PutObjectTaggingHandler(w http.ResponseWriter, r *http.Request
|
|||
func (h *handler) GetObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {
|
||||
reqInfo := api.GetReqInfo(r.Context())
|
||||
|
||||
if err := h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
|
||||
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
p := &layer.HeadObjectParams{
|
||||
Bucket: reqInfo.BucketName,
|
||||
Object: reqInfo.ObjectName,
|
||||
|
@ -89,6 +99,11 @@ func (h *handler) DeleteObjectTaggingHandler(w http.ResponseWriter, r *http.Requ
|
|||
VersionID: reqInfo.URL.Query().Get("versionId"),
|
||||
}
|
||||
|
||||
if err := h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
|
||||
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
objInfo, err := h.obj.GetObjectInfo(r.Context(), p)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "could not get object info", reqInfo, err)
|
||||
|
@ -111,6 +126,11 @@ func (h *handler) PutBucketTaggingHandler(w http.ResponseWriter, r *http.Request
|
|||
return
|
||||
}
|
||||
|
||||
if err = h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
|
||||
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.obj.PutBucketTagging(r.Context(), reqInfo.BucketName, tagSet); err != nil {
|
||||
h.logAndSendError(w, "could not put object tagging", reqInfo, err)
|
||||
}
|
||||
|
@ -119,6 +139,11 @@ func (h *handler) PutBucketTaggingHandler(w http.ResponseWriter, r *http.Request
|
|||
func (h *handler) GetBucketTaggingHandler(w http.ResponseWriter, r *http.Request) {
|
||||
reqInfo := api.GetReqInfo(r.Context())
|
||||
|
||||
if err := h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
|
||||
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
tagSet, err := h.obj.GetBucketTagging(r.Context(), reqInfo.BucketName)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "could not get object tagging", reqInfo, err)
|
||||
|
@ -132,6 +157,10 @@ func (h *handler) GetBucketTaggingHandler(w http.ResponseWriter, r *http.Request
|
|||
|
||||
func (h *handler) DeleteBucketTaggingHandler(w http.ResponseWriter, r *http.Request) {
|
||||
reqInfo := api.GetReqInfo(r.Context())
|
||||
if err := h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
|
||||
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
|
||||
return
|
||||
}
|
||||
if err := h.obj.DeleteBucketTagging(r.Context(), reqInfo.BucketName); err != nil {
|
||||
h.logAndSendError(w, "could not delete object tagging", reqInfo, err)
|
||||
}
|
||||
|
|
|
@ -348,28 +348,6 @@ func (n *layer) GetObjectInfo(ctx context.Context, p *HeadObjectParams) (*Object
|
|||
return n.headVersion(ctx, bkt, p.VersionID)
|
||||
}
|
||||
|
||||
func (n *layer) getSettingsObjectInfo(ctx context.Context, bkt *cache.BucketInfo) (*ObjectInfo, error) {
|
||||
if meta := n.systemCache.Get(bkt.SettingsObjectKey()); meta != nil {
|
||||
return objInfoFromMeta(bkt, meta), nil
|
||||
}
|
||||
|
||||
oid, err := n.objectFindID(ctx, &findParams{cid: bkt.CID, attr: objectSystemAttributeName, val: bkt.SettingsObjectName()})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
meta, err := n.objectHead(ctx, bkt.CID, oid)
|
||||
if err != nil {
|
||||
n.log.Error("could not fetch object head", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
if err = n.systemCache.Put(bkt.SettingsObjectKey(), meta); err != nil {
|
||||
n.log.Error("couldn't cache system object", zap.Error(err))
|
||||
}
|
||||
|
||||
return objInfoFromMeta(bkt, meta), nil
|
||||
}
|
||||
|
||||
// PutObject into storage.
|
||||
func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*ObjectInfo, error) {
|
||||
bkt, err := n.GetBucketInfo(ctx, p.Bucket)
|
||||
|
@ -458,19 +436,30 @@ func (n *layer) PutBucketTagging(ctx context.Context, bucketName string, tagSet
|
|||
|
||||
// DeleteObjectTagging from storage.
|
||||
func (n *layer) DeleteObjectTagging(ctx context.Context, p *ObjectInfo) error {
|
||||
return n.deleteSystemObject(ctx, p.CID(), p.TagsObject())
|
||||
}
|
||||
|
||||
func (n *layer) deleteSystemObject(ctx context.Context, bktCID *cid.ID, name string) error {
|
||||
oid, err := n.objectFindID(ctx, &findParams{cid: bktCID, attr: objectSystemAttributeName, val: name})
|
||||
bktInfo, err := n.GetBucketInfo(ctx, p.Bucket)
|
||||
if err != nil {
|
||||
if errors.IsS3Error(err, errors.ErrNoSuchKey) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
return n.deleteSystemObject(ctx, bktInfo, p.TagsObject())
|
||||
}
|
||||
|
||||
return n.objectDelete(ctx, bktCID, oid)
|
||||
func (n *layer) deleteSystemObject(ctx context.Context, bktInfo *cache.BucketInfo, name string) error {
|
||||
var oid *object.ID
|
||||
if meta := n.systemCache.Get(bktInfo.SystemObjectKey(name)); meta != nil {
|
||||
oid = meta.ID()
|
||||
} else {
|
||||
var err error
|
||||
oid, err = n.objectFindID(ctx, &findParams{cid: bktInfo.CID, attr: objectSystemAttributeName, val: name})
|
||||
if err != nil {
|
||||
if errors.IsS3Error(err, errors.ErrNoSuchKey) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
n.systemCache.Delete(bktInfo.SystemObjectKey(name))
|
||||
return n.objectDelete(ctx, bktInfo.CID, oid)
|
||||
}
|
||||
|
||||
// DeleteBucketTagging from storage.
|
||||
|
@ -480,13 +469,21 @@ func (n *layer) DeleteBucketTagging(ctx context.Context, bucketName string) erro
|
|||
return err
|
||||
}
|
||||
|
||||
return n.deleteSystemObject(ctx, bktInfo.CID, formBucketTagObjectName(bucketName))
|
||||
return n.deleteSystemObject(ctx, bktInfo, formBucketTagObjectName(bucketName))
|
||||
}
|
||||
|
||||
func (n *layer) putSystemObject(ctx context.Context, bktInfo *cache.BucketInfo, objName string, metadata map[string]string, prefix string) (*object.ID, error) {
|
||||
oldOID, err := n.objectFindID(ctx, &findParams{cid: bktInfo.CID, attr: objectSystemAttributeName, val: objName})
|
||||
if err != nil && !errors.IsS3Error(err, errors.ErrNoSuchKey) {
|
||||
return nil, err
|
||||
func (n *layer) putSystemObject(ctx context.Context, bktInfo *cache.BucketInfo, objName string, metadata map[string]string, prefix string) (*object.Object, error) {
|
||||
var (
|
||||
err error
|
||||
oldOID *object.ID
|
||||
)
|
||||
if meta := n.systemCache.Get(bktInfo.SystemObjectKey(objName)); meta != nil {
|
||||
oldOID = meta.ID()
|
||||
} else {
|
||||
oldOID, err = n.objectFindID(ctx, &findParams{cid: bktInfo.CID, attr: objectSystemAttributeName, val: objName})
|
||||
if err != nil && !errors.IsS3Error(err, errors.ErrNoSuchKey) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
attributes := make([]*object.Attribute, 0, 3)
|
||||
|
@ -526,19 +523,27 @@ func (n *layer) putSystemObject(ctx context.Context, bktInfo *cache.BucketInfo,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = n.objectHead(ctx, bktInfo.CID, oid); err != nil {
|
||||
meta, err := n.objectHead(ctx, bktInfo.CID, oid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = n.systemCache.Put(bktInfo.SystemObjectKey(objName), meta); err != nil {
|
||||
n.log.Error("couldn't cache system object", zap.Error(err))
|
||||
}
|
||||
if oldOID != nil {
|
||||
if err = n.objectDelete(ctx, bktInfo.CID, oldOID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return oid, nil
|
||||
return meta, nil
|
||||
}
|
||||
|
||||
func (n *layer) getSystemObject(ctx context.Context, bkt *cache.BucketInfo, objName string) (*ObjectInfo, error) {
|
||||
if meta := n.systemCache.Get(bkt.SystemObjectKey(objName)); meta != nil {
|
||||
return objInfoFromMeta(bkt, meta), nil
|
||||
}
|
||||
|
||||
oid, err := n.objectFindID(ctx, &findParams{cid: bkt.CID, attr: objectSystemAttributeName, val: objName})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -548,8 +553,11 @@ func (n *layer) getSystemObject(ctx context.Context, bkt *cache.BucketInfo, objN
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = n.systemCache.Put(bkt.SystemObjectKey(objName), meta); err != nil {
|
||||
n.log.Error("couldn't cache system object", zap.Error(err))
|
||||
}
|
||||
|
||||
return objectInfoFromMeta(bkt, meta, "", ""), nil
|
||||
return objInfoFromMeta(bkt, meta), nil
|
||||
}
|
||||
|
||||
// CopyObject from one bucket into another bucket.
|
||||
|
@ -619,7 +627,7 @@ func (n *layer) deleteObject(ctx context.Context, bkt *cache.BucketInfo, obj *Ve
|
|||
if err = n.objectDelete(ctx, bkt.CID, id); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = n.DeleteObjectTagging(ctx, &ObjectInfo{id: id, bucketID: bkt.CID, Name: obj.Name}); err != nil {
|
||||
if err = n.DeleteObjectTagging(ctx, &ObjectInfo{id: id, Bucket: bkt.Name, Name: obj.Name}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,13 +5,10 @@ import (
|
|||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/client"
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/object"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/api/cache"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/api/errors"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type objectVersions struct {
|
||||
|
@ -120,68 +117,22 @@ func (v *objectVersions) getVersion(oid *object.ID) *ObjectInfo {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *layer) PutBucketVersioning(ctx context.Context, p *PutVersioningParams) (*ObjectInfo, error) {
|
||||
bucketInfo, err := n.GetBucketInfo(ctx, p.Bucket)
|
||||
bktInfo, err := n.GetBucketInfo(ctx, p.Bucket)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
objectInfo, err := n.getSettingsObjectInfo(ctx, bucketInfo)
|
||||
if err != nil {
|
||||
n.log.Warn("couldn't get bucket version settings object, new one will be created",
|
||||
zap.String("bucket_name", bucketInfo.Name),
|
||||
zap.Stringer("cid", bucketInfo.CID),
|
||||
zap.Error(err))
|
||||
metadata := map[string]string{
|
||||
attrSettingsVersioningEnabled: strconv.FormatBool(p.Settings.VersioningEnabled),
|
||||
}
|
||||
|
||||
attributes := make([]*object.Attribute, 0, 3)
|
||||
|
||||
filename := object.NewAttribute()
|
||||
filename.SetKey(objectSystemAttributeName)
|
||||
filename.SetValue(bucketInfo.SettingsObjectName())
|
||||
|
||||
createdAt := object.NewAttribute()
|
||||
createdAt.SetKey(object.AttributeTimestamp)
|
||||
createdAt.SetValue(strconv.FormatInt(time.Now().UTC().Unix(), 10))
|
||||
|
||||
versioningIgnore := object.NewAttribute()
|
||||
versioningIgnore.SetKey(attrVersionsIgnore)
|
||||
versioningIgnore.SetValue(strconv.FormatBool(true))
|
||||
|
||||
settingsVersioningEnabled := object.NewAttribute()
|
||||
settingsVersioningEnabled.SetKey(attrSettingsVersioningEnabled)
|
||||
settingsVersioningEnabled.SetValue(strconv.FormatBool(p.Settings.VersioningEnabled))
|
||||
|
||||
attributes = append(attributes, filename, createdAt, versioningIgnore, settingsVersioningEnabled)
|
||||
|
||||
raw := object.NewRaw()
|
||||
raw.SetOwnerID(bucketInfo.Owner)
|
||||
raw.SetContainerID(bucketInfo.CID)
|
||||
raw.SetAttributes(attributes...)
|
||||
|
||||
ops := new(client.PutObjectParams).WithObject(raw.Object())
|
||||
oid, err := n.pool.PutObject(ctx, ops, n.BearerOpt(ctx))
|
||||
meta, err := n.putSystemObject(ctx, bktInfo, bktInfo.SettingsObjectName(), metadata, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
meta, err := n.objectHead(ctx, bucketInfo.CID, oid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = n.systemCache.Put(bucketInfo.SettingsObjectKey(), meta); err != nil {
|
||||
n.log.Error("couldn't cache system object", zap.Error(err))
|
||||
}
|
||||
|
||||
if objectInfo != nil {
|
||||
if err = n.objectDelete(ctx, bucketInfo.CID, objectInfo.ID()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return objectInfoFromMeta(bucketInfo, meta, "", ""), nil
|
||||
return objInfoFromMeta(bktInfo, meta), nil
|
||||
}
|
||||
|
||||
func (n *layer) GetBucketVersioning(ctx context.Context, bucketName string) (*BucketSettings, error) {
|
||||
|
@ -296,7 +247,7 @@ func contains(list []string, elem string) bool {
|
|||
}
|
||||
|
||||
func (n *layer) getBucketSettings(ctx context.Context, bktInfo *cache.BucketInfo) (*BucketSettings, error) {
|
||||
objInfo, err := n.getSettingsObjectInfo(ctx, bktInfo)
|
||||
objInfo, err := n.getSystemObject(ctx, bktInfo, bktInfo.SettingsObjectName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -359,21 +359,21 @@ Compatibility: 0/19/22
|
|||
|
||||
## Tagging
|
||||
|
||||
Compatibility: 0/8/11
|
||||
Compatibility: 9/8/11
|
||||
|
||||
| | Test | s3-gw | aws s3 |
|
||||
|----|------------------------------------------------------------|-------|--------|
|
||||
| 1 | s3tests_boto3.functional.test_s3.test_set_bucket_tagging | FAIL | FAIL |
|
||||
| 2 | s3tests_boto3.functional.test_s3.test_get_obj_tagging | ERROR | ok |
|
||||
| 3 | s3tests_boto3.functional.test_s3.test_get_obj_head_tagging | ERROR | ok |
|
||||
| 4 | s3tests_boto3.functional.test_s3.test_put_max_tags | ERROR | ok |
|
||||
| 2 | s3tests_boto3.functional.test_s3.test_get_obj_tagging | ok | ok |
|
||||
| 3 | s3tests_boto3.functional.test_s3.test_get_obj_head_tagging | ok | ok |
|
||||
| 4 | s3tests_boto3.functional.test_s3.test_put_max_tags | ok | ok |
|
||||
| 5 | s3tests_boto3.functional.test_s3.test_put_excess_tags | FAIL | FAIL |
|
||||
| 6 | s3tests_boto3.functional.test_s3.test_put_max_kvsize_tags | ERROR | ok |
|
||||
| 7 | s3tests_boto3.functional.test_s3.test_put_excess_key_tags | FAIL | ok |
|
||||
| 8 | s3tests_boto3.functional.test_s3.test_put_excess_val_tags | FAIL | ok |
|
||||
| 9 | s3tests_boto3.functional.test_s3.test_put_modify_tags | ERROR | FAIL |
|
||||
| 10 | s3tests_boto3.functional.test_s3.test_put_delete_tags | ERROR | ok |
|
||||
| 11 | s3tests_boto3.functional.test_s3.test_put_obj_with_tags | ERROR | ok |
|
||||
| 6 | s3tests_boto3.functional.test_s3.test_put_max_kvsize_tags | ok | ok |
|
||||
| 7 | s3tests_boto3.functional.test_s3.test_put_excess_key_tags | ok | ok |
|
||||
| 8 | s3tests_boto3.functional.test_s3.test_put_excess_val_tags | ok | ok |
|
||||
| 9 | s3tests_boto3.functional.test_s3.test_put_modify_tags | ok | FAIL |
|
||||
| 10 | s3tests_boto3.functional.test_s3.test_put_delete_tags | ok | ok |
|
||||
| 11 | s3tests_boto3.functional.test_s3.test_put_obj_with_tags | ok | ok |
|
||||
|
||||
## Versioning
|
||||
|
||||
|
|
Loading…
Reference in a new issue