Compare commits
No commits in common. "v0.30.1" and "v0.30.0" have entirely different histories.
10 changed files with 85 additions and 175 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -4,14 +4,6 @@ This document outlines major changes between releases.
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
## [0.30.1] - 2024-07-25
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Redundant system node removal in tree service (#437)
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- Log details on SDK Pool health status change (#439)
|
|
||||||
|
|
||||||
## [0.30.0] - Kangshung -2024-07-19
|
## [0.30.0] - Kangshung -2024-07-19
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
@ -241,5 +233,4 @@ To see CHANGELOG for older versions, refer to https://github.com/nspcc-dev/neofs
|
||||||
[0.29.2]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.29.1...v0.29.2
|
[0.29.2]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.29.1...v0.29.2
|
||||||
[0.29.3]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.29.2...v0.29.3
|
[0.29.3]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.29.2...v0.29.3
|
||||||
[0.30.0]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.29.3...v0.30.0
|
[0.30.0]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.29.3...v0.30.0
|
||||||
[0.30.1]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.30.0...v0.30.1
|
[Unreleased]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.30.0...master
|
||||||
[Unreleased]: https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/compare/v0.30.1...master
|
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
v0.30.1
|
v0.30.0
|
||||||
|
|
|
@ -49,19 +49,17 @@ func (n *Layer) PutBucketCORS(ctx context.Context, p *PutCORSParams) error {
|
||||||
return fmt.Errorf("put system object: %w", err)
|
return fmt.Errorf("put system object: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
objIDsToDelete, err := n.treeService.PutBucketCORS(ctx, p.BktInfo, objID)
|
objIDToDelete, err := n.treeService.PutBucketCORS(ctx, p.BktInfo, objID)
|
||||||
objIDToDeleteNotFound := errorsStd.Is(err, ErrNoNodeToRemove)
|
objIDToDeleteNotFound := errorsStd.Is(err, ErrNoNodeToRemove)
|
||||||
if err != nil && !objIDToDeleteNotFound {
|
if err != nil && !objIDToDeleteNotFound {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !objIDToDeleteNotFound {
|
if !objIDToDeleteNotFound {
|
||||||
for _, id := range objIDsToDelete {
|
if err = n.objectDelete(ctx, p.BktInfo, objIDToDelete); err != nil {
|
||||||
if err = n.objectDelete(ctx, p.BktInfo, id); err != nil {
|
n.reqLogger(ctx).Error(logs.CouldntDeleteCorsObject, zap.Error(err),
|
||||||
n.reqLogger(ctx).Error(logs.CouldntDeleteCorsObject, zap.Error(err),
|
zap.String("cnrID", p.BktInfo.CID.EncodeToString()),
|
||||||
zap.String("cnrID", p.BktInfo.CID.EncodeToString()),
|
zap.String("objID", objIDToDelete.EncodeToString()))
|
||||||
zap.String("objID", id.EncodeToString()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,16 +81,14 @@ func (n *Layer) GetBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) (*d
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Layer) DeleteBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) error {
|
func (n *Layer) DeleteBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) error {
|
||||||
objIDs, err := n.treeService.DeleteBucketCORS(ctx, bktInfo)
|
objID, err := n.treeService.DeleteBucketCORS(ctx, bktInfo)
|
||||||
objIDNotFound := errorsStd.Is(err, ErrNoNodeToRemove)
|
objIDNotFound := errorsStd.Is(err, ErrNoNodeToRemove)
|
||||||
if err != nil && !objIDNotFound {
|
if err != nil && !objIDNotFound {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !objIDNotFound {
|
if !objIDNotFound {
|
||||||
for _, id := range objIDs {
|
if err = n.objectDelete(ctx, bktInfo, objID); err != nil {
|
||||||
if err = n.objectDelete(ctx, bktInfo, id); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ func (t *TreeServiceMock) GetBucketCORS(_ context.Context, bktInfo *data.BucketI
|
||||||
return node.OID, nil
|
return node.OID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TreeServiceMock) PutBucketCORS(_ context.Context, bktInfo *data.BucketInfo, objID oid.ID) ([]oid.ID, error) {
|
func (t *TreeServiceMock) PutBucketCORS(_ context.Context, bktInfo *data.BucketInfo, objID oid.ID) (oid.ID, error) {
|
||||||
systemMap, ok := t.system[bktInfo.CID.EncodeToString()]
|
systemMap, ok := t.system[bktInfo.CID.EncodeToString()]
|
||||||
if !ok {
|
if !ok {
|
||||||
systemMap = make(map[string]*data.BaseNodeVersion)
|
systemMap = make(map[string]*data.BaseNodeVersion)
|
||||||
|
@ -136,10 +136,10 @@ func (t *TreeServiceMock) PutBucketCORS(_ context.Context, bktInfo *data.BucketI
|
||||||
|
|
||||||
t.system[bktInfo.CID.EncodeToString()] = systemMap
|
t.system[bktInfo.CID.EncodeToString()] = systemMap
|
||||||
|
|
||||||
return nil, ErrNoNodeToRemove
|
return oid.ID{}, ErrNoNodeToRemove
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TreeServiceMock) DeleteBucketCORS(context.Context, *data.BucketInfo) ([]oid.ID, error) {
|
func (t *TreeServiceMock) DeleteBucketCORS(context.Context, *data.BucketInfo) (oid.ID, error) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,13 +25,13 @@ type TreeService interface {
|
||||||
|
|
||||||
// PutBucketCORS puts a node to a system tree and returns objectID of a previous cors config which must be deleted in FrostFS.
|
// PutBucketCORS puts a node to a system tree and returns objectID of a previous cors config which must be deleted in FrostFS.
|
||||||
//
|
//
|
||||||
// If object ids to remove is not found returns ErrNoNodeToRemove error.
|
// If object id to remove is not found returns ErrNoNodeToRemove error.
|
||||||
PutBucketCORS(ctx context.Context, bktInfo *data.BucketInfo, objID oid.ID) ([]oid.ID, error)
|
PutBucketCORS(ctx context.Context, bktInfo *data.BucketInfo, objID oid.ID) (oid.ID, error)
|
||||||
|
|
||||||
// DeleteBucketCORS removes a node from a system tree and returns objID which must be deleted in FrostFS.
|
// DeleteBucketCORS removes a node from a system tree and returns objID which must be deleted in FrostFS.
|
||||||
//
|
//
|
||||||
// If object ids to remove is not found returns ErrNoNodeToRemove error.
|
// If object id to remove is not found returns ErrNoNodeToRemove error.
|
||||||
DeleteBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) ([]oid.ID, error)
|
DeleteBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) (oid.ID, error)
|
||||||
|
|
||||||
GetObjectTagging(ctx context.Context, bktInfo *data.BucketInfo, objVersion *data.NodeVersion) (map[string]string, error)
|
GetObjectTagging(ctx context.Context, bktInfo *data.BucketInfo, objVersion *data.NodeVersion) (map[string]string, error)
|
||||||
PutObjectTagging(ctx context.Context, bktInfo *data.BucketInfo, objVersion *data.NodeVersion, tagSet map[string]string) error
|
PutObjectTagging(ctx context.Context, bktInfo *data.BucketInfo, objVersion *data.NodeVersion, tagSet map[string]string) error
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -6,7 +6,7 @@ require (
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240716113920-f517e3949164
|
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240716113920-f517e3949164
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240621131249-49e5270f673e
|
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240621131249-49e5270f673e
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6
|
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240722121227-fa89999d919c
|
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240718141740-ce8270568d36
|
||||||
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240611102930-ac965e8d176a
|
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240611102930-ac965e8d176a
|
||||||
git.frostfs.info/TrueCloudLab/zapjournald v0.0.0-20240124114243-cb2e66427d02
|
git.frostfs.info/TrueCloudLab/zapjournald v0.0.0-20240124114243-cb2e66427d02
|
||||||
github.com/aws/aws-sdk-go v1.44.6
|
github.com/aws/aws-sdk-go v1.44.6
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -44,8 +44,8 @@ git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSV
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0/go.mod h1:RUIKZATQLJ+TaYQa60X2fTDwfuhMfm8Ar60bQ5fr+vU=
|
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0/go.mod h1:RUIKZATQLJ+TaYQa60X2fTDwfuhMfm8Ar60bQ5fr+vU=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6 h1:aGQ6QaAnTerQ5Dq5b2/f9DUQtSqPkZZ/bkMx/HKuLCo=
|
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6 h1:aGQ6QaAnTerQ5Dq5b2/f9DUQtSqPkZZ/bkMx/HKuLCo=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6/go.mod h1:W8Nn08/l6aQ7UlIbpF7FsQou7TVpcRD1ZT1KG4TrFhE=
|
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6/go.mod h1:W8Nn08/l6aQ7UlIbpF7FsQou7TVpcRD1ZT1KG4TrFhE=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240722121227-fa89999d919c h1:8ZS6eUFnOhzUo9stFqwq1Zyq+Y5YNcYAidCGICcZVL4=
|
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240718141740-ce8270568d36 h1:MV/vKJWLQT34RRbXYvkNKFYGNjL5bRNuCQMXkbC7fLI=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240722121227-fa89999d919c/go.mod h1:vluJ/+yQMcq8ZIZZSA7Te+JKClr0lgtRErjICvb8wto=
|
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240718141740-ce8270568d36/go.mod h1:vluJ/+yQMcq8ZIZZSA7Te+JKClr0lgtRErjICvb8wto=
|
||||||
git.frostfs.info/TrueCloudLab/hrw v1.2.1 h1:ccBRK21rFvY5R1WotI6LNoPlizk7qSvdfD8lNIRudVc=
|
git.frostfs.info/TrueCloudLab/hrw v1.2.1 h1:ccBRK21rFvY5R1WotI6LNoPlizk7qSvdfD8lNIRudVc=
|
||||||
git.frostfs.info/TrueCloudLab/hrw v1.2.1/go.mod h1:C1Ygde2n843yTZEQ0FP69jYiuaYV0kriLvP4zm8JuvM=
|
git.frostfs.info/TrueCloudLab/hrw v1.2.1/go.mod h1:C1Ygde2n843yTZEQ0FP69jYiuaYV0kriLvP4zm8JuvM=
|
||||||
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240611102930-ac965e8d176a h1:Bk1fB4cQASPKgAVGCdlBOEp5ohZfDxqK6fZM8eP+Emo=
|
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240611102930-ac965e8d176a h1:Bk1fB4cQASPKgAVGCdlBOEp5ohZfDxqK6fZM8eP+Emo=
|
||||||
|
|
|
@ -237,12 +237,8 @@ func (x *FrostFS) CreateObject(ctx context.Context, prm layer.PrmObjectCreate) (
|
||||||
prmPut.UseKey(prm.PrivateKey)
|
prmPut.UseKey(prm.PrivateKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := x.pool.PutObject(ctx, prmPut)
|
idObj, err := x.pool.PutObject(ctx, prmPut)
|
||||||
if err = handleObjectError("save object via connection pool", err); err != nil {
|
return idObj, handleObjectError("save object via connection pool", err)
|
||||||
return oid.ID{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.ObjectID, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// wraps io.ReadCloser and transforms Read errors related to access violation
|
// wraps io.ReadCloser and transforms Read errors related to access violation
|
||||||
|
|
|
@ -142,13 +142,11 @@ const (
|
||||||
CouldntCacheSubject = "couldn't cache subject info"
|
CouldntCacheSubject = "couldn't cache subject info"
|
||||||
UserGroupsListIsEmpty = "user groups list is empty, subject not found"
|
UserGroupsListIsEmpty = "user groups list is empty, subject not found"
|
||||||
CouldntCacheUserKey = "couldn't cache user key"
|
CouldntCacheUserKey = "couldn't cache user key"
|
||||||
ObjectTaggingNodeHasMultipleIDs = "object tagging node has multiple ids"
|
FoundSeveralBucketCorsNodes = "found several bucket cors nodes, latest be used"
|
||||||
BucketTaggingNodeHasMultipleIDs = "bucket tagging node has multiple ids"
|
FoundSeveralObjectTaggingNodes = "found several object tagging nodes, latest be used"
|
||||||
BucketSettingsNodeHasMultipleIDs = "bucket settings node has multiple ids"
|
FoundSeveralBucketTaggingNodes = "found several bucket tagging nodes, latest be used"
|
||||||
BucketCORSNodeHasMultipleIDs = "bucket cors node has multiple ids"
|
FoundSeveralBucketSettingsNodes = "found several bucket settings nodes, latest be used"
|
||||||
SystemNodeHasMultipleIDs = "system node has multiple ids"
|
|
||||||
FailedToRemoveOldSystemNode = "failed to remove old system node"
|
|
||||||
UnexpectedMultiNodeIDsInSubTreeMultiParts = "unexpected multi node ids in sub tree multi parts"
|
UnexpectedMultiNodeIDsInSubTreeMultiParts = "unexpected multi node ids in sub tree multi parts"
|
||||||
FoundSeveralSystemNodes = "found several system nodes"
|
FoundSeveralSystemNodes = "found several system nodes, latest be used"
|
||||||
FailedToParsePartInfo = "failed to parse part info"
|
FailedToParsePartInfo = "failed to parse part info"
|
||||||
)
|
)
|
||||||
|
|
|
@ -53,11 +53,6 @@ type (
|
||||||
Meta map[string]string
|
Meta map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
multiSystemNode struct {
|
|
||||||
// the first element is latest
|
|
||||||
nodes []*treeNode
|
|
||||||
}
|
|
||||||
|
|
||||||
GetNodesParams struct {
|
GetNodesParams struct {
|
||||||
BktInfo *data.BucketInfo
|
BktInfo *data.BucketInfo
|
||||||
TreeID string
|
TreeID string
|
||||||
|
@ -273,45 +268,6 @@ func newNodeVersionFromTreeNode(log *zap.Logger, filePath string, treeNode *tree
|
||||||
return version, nil
|
return version, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMultiNode(nodes []NodeResponse) (*multiSystemNode, error) {
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
index int
|
|
||||||
maxTimestamp uint64
|
|
||||||
)
|
|
||||||
|
|
||||||
if len(nodes) == 0 {
|
|
||||||
return nil, errors.New("multi node must have at least one node")
|
|
||||||
}
|
|
||||||
|
|
||||||
treeNodes := make([]*treeNode, len(nodes))
|
|
||||||
|
|
||||||
for i, node := range nodes {
|
|
||||||
if treeNodes[i], err = newTreeNode(node); err != nil {
|
|
||||||
return nil, fmt.Errorf("parse system node response: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if timestamp := getMaxTimestamp(node); timestamp > maxTimestamp {
|
|
||||||
index = i
|
|
||||||
maxTimestamp = timestamp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
treeNodes[0], treeNodes[index] = treeNodes[index], treeNodes[0]
|
|
||||||
|
|
||||||
return &multiSystemNode{
|
|
||||||
nodes: treeNodes,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *multiSystemNode) Latest() *treeNode {
|
|
||||||
return m.nodes[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *multiSystemNode) Old() []*treeNode {
|
|
||||||
return m.nodes[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMultipartInfoFromTreeNode(log *zap.Logger, filePath string, treeNode *treeNode) (*data.MultipartInfo, error) {
|
func newMultipartInfoFromTreeNode(log *zap.Logger, filePath string, treeNode *treeNode) (*data.MultipartInfo, error) {
|
||||||
uploadID, _ := treeNode.Get(uploadIDKV)
|
uploadID, _ := treeNode.Get(uploadIDKV)
|
||||||
if uploadID == "" {
|
if uploadID == "" {
|
||||||
|
@ -438,13 +394,11 @@ func newPartInfo(node NodeResponse) (*data.PartInfo, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) GetSettingsNode(ctx context.Context, bktInfo *data.BucketInfo) (*data.BucketSettings, error) {
|
func (c *Tree) GetSettingsNode(ctx context.Context, bktInfo *data.BucketInfo) (*data.BucketSettings, error) {
|
||||||
multiNode, err := c.getSystemNode(ctx, bktInfo, settingsFileName)
|
node, err := c.getSystemNode(ctx, bktInfo, []string{settingsFileName})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("couldn't get node: %w", err)
|
return nil, fmt.Errorf("couldn't get node: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
node := multiNode.Latest()
|
|
||||||
|
|
||||||
settings := &data.BucketSettings{Versioning: data.VersioningUnversioned}
|
settings := &data.BucketSettings{Versioning: data.VersioningUnversioned}
|
||||||
if versioningValue, ok := node.Get(versioningKV); ok {
|
if versioningValue, ok := node.Get(versioningKV); ok {
|
||||||
settings.Versioning = versioningValue
|
settings.Versioning = versioningValue
|
||||||
|
@ -468,7 +422,7 @@ func (c *Tree) GetSettingsNode(ctx context.Context, bktInfo *data.BucketInfo) (*
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) PutSettingsNode(ctx context.Context, bktInfo *data.BucketInfo, settings *data.BucketSettings) error {
|
func (c *Tree) PutSettingsNode(ctx context.Context, bktInfo *data.BucketInfo, settings *data.BucketSettings) error {
|
||||||
multiNode, err := c.getSystemNode(ctx, bktInfo, settingsFileName)
|
node, err := c.getSystemNode(ctx, bktInfo, []string{settingsFileName})
|
||||||
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
||||||
if err != nil && !isErrNotFound {
|
if err != nil && !isErrNotFound {
|
||||||
return fmt.Errorf("couldn't get node: %w", err)
|
return fmt.Errorf("couldn't get node: %w", err)
|
||||||
|
@ -481,35 +435,28 @@ func (c *Tree) PutSettingsNode(ctx context.Context, bktInfo *data.BucketInfo, se
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
latest := multiNode.Latest()
|
ind := node.GetLatestNodeIndex()
|
||||||
ind := latest.GetLatestNodeIndex()
|
if node.IsSplit() {
|
||||||
if latest.IsSplit() {
|
c.reqLogger(ctx).Warn(logs.FoundSeveralBucketSettingsNodes)
|
||||||
c.reqLogger(ctx).Error(logs.BucketSettingsNodeHasMultipleIDs, zap.Uint64s("ids", latest.ID))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = c.service.MoveNode(ctx, bktInfo, systemTree, latest.ID[ind], 0, meta); err != nil {
|
return c.service.MoveNode(ctx, bktInfo, systemTree, node.ID[ind], 0, meta)
|
||||||
return fmt.Errorf("move settings node: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.cleanOldNodes(ctx, multiNode.Old(), bktInfo)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) GetBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) (oid.ID, error) {
|
func (c *Tree) GetBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) (oid.ID, error) {
|
||||||
node, err := c.getSystemNode(ctx, bktInfo, corsFilename)
|
node, err := c.getSystemNode(ctx, bktInfo, []string{corsFilename})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return oid.ID{}, err
|
return oid.ID{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return node.Latest().ObjID, nil
|
return node.ObjID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) PutBucketCORS(ctx context.Context, bktInfo *data.BucketInfo, objID oid.ID) ([]oid.ID, error) {
|
func (c *Tree) PutBucketCORS(ctx context.Context, bktInfo *data.BucketInfo, objID oid.ID) (oid.ID, error) {
|
||||||
multiNode, err := c.getSystemNode(ctx, bktInfo, corsFilename)
|
node, err := c.getSystemNode(ctx, bktInfo, []string{corsFilename})
|
||||||
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
||||||
if err != nil && !isErrNotFound {
|
if err != nil && !isErrNotFound {
|
||||||
return nil, fmt.Errorf("couldn't get node: %w", err)
|
return oid.ID{}, fmt.Errorf("couldn't get node: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
meta := make(map[string]string)
|
meta := make(map[string]string)
|
||||||
|
@ -518,64 +465,35 @@ func (c *Tree) PutBucketCORS(ctx context.Context, bktInfo *data.BucketInfo, objI
|
||||||
|
|
||||||
if isErrNotFound {
|
if isErrNotFound {
|
||||||
if _, err = c.service.AddNode(ctx, bktInfo, systemTree, 0, meta); err != nil {
|
if _, err = c.service.AddNode(ctx, bktInfo, systemTree, 0, meta); err != nil {
|
||||||
return nil, err
|
return oid.ID{}, err
|
||||||
}
|
}
|
||||||
return nil, layer.ErrNoNodeToRemove
|
return oid.ID{}, layer.ErrNoNodeToRemove
|
||||||
}
|
}
|
||||||
|
|
||||||
latest := multiNode.Latest()
|
ind := node.GetLatestNodeIndex()
|
||||||
ind := latest.GetLatestNodeIndex()
|
if node.IsSplit() {
|
||||||
if latest.IsSplit() {
|
c.reqLogger(ctx).Warn(logs.FoundSeveralBucketCorsNodes)
|
||||||
c.reqLogger(ctx).Error(logs.BucketCORSNodeHasMultipleIDs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = c.service.MoveNode(ctx, bktInfo, systemTree, latest.ID[ind], 0, meta); err != nil {
|
return node.ObjID, c.service.MoveNode(ctx, bktInfo, systemTree, node.ID[ind], 0, meta)
|
||||||
return nil, fmt.Errorf("move cors node: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
objToDelete := make([]oid.ID, 1, len(multiNode.nodes))
|
|
||||||
objToDelete[0] = latest.ObjID
|
|
||||||
|
|
||||||
objToDelete = append(objToDelete, c.cleanOldNodes(ctx, multiNode.Old(), bktInfo)...)
|
|
||||||
|
|
||||||
return objToDelete, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) DeleteBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) ([]oid.ID, error) {
|
func (c *Tree) DeleteBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) (oid.ID, error) {
|
||||||
multiNode, err := c.getSystemNode(ctx, bktInfo, corsFilename)
|
node, err := c.getSystemNode(ctx, bktInfo, []string{corsFilename})
|
||||||
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
if err != nil && !errors.Is(err, layer.ErrNodeNotFound) {
|
||||||
if err != nil && !isErrNotFound {
|
return oid.ID{}, err
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if isErrNotFound {
|
if node != nil {
|
||||||
return nil, layer.ErrNoNodeToRemove
|
|
||||||
}
|
|
||||||
|
|
||||||
objToDelete := c.cleanOldNodes(ctx, multiNode.nodes, bktInfo)
|
|
||||||
if len(objToDelete) != len(multiNode.nodes) {
|
|
||||||
return nil, fmt.Errorf("clean old cors nodes: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return objToDelete, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Tree) cleanOldNodes(ctx context.Context, nodes []*treeNode, bktInfo *data.BucketInfo) []oid.ID {
|
|
||||||
res := make([]oid.ID, 0, len(nodes))
|
|
||||||
|
|
||||||
for _, node := range nodes {
|
|
||||||
ind := node.GetLatestNodeIndex()
|
ind := node.GetLatestNodeIndex()
|
||||||
if node.IsSplit() {
|
if node.IsSplit() {
|
||||||
c.reqLogger(ctx).Error(logs.SystemNodeHasMultipleIDs, zap.String("FileName", node.Meta[FileNameKey]), zap.Uint64s("ids", node.ID))
|
c.reqLogger(ctx).Warn(logs.FoundSeveralBucketCorsNodes)
|
||||||
}
|
|
||||||
if err := c.service.RemoveNode(ctx, bktInfo, systemTree, node.ID[ind]); err != nil {
|
|
||||||
c.reqLogger(ctx).Warn(logs.FailedToRemoveOldSystemNode, zap.String("FileName", node.Meta[FileNameKey]), zap.Uint64("id", node.ID[ind]))
|
|
||||||
} else {
|
|
||||||
res = append(res, node.ObjID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return node.ObjID, c.service.RemoveNode(ctx, bktInfo, systemTree, node.ID[ind])
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return oid.ID{}, layer.ErrNoNodeToRemove
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) GetObjectTagging(ctx context.Context, bktInfo *data.BucketInfo, objVersion *data.NodeVersion) (map[string]string, error) {
|
func (c *Tree) GetObjectTagging(ctx context.Context, bktInfo *data.BucketInfo, objVersion *data.NodeVersion) (map[string]string, error) {
|
||||||
|
@ -623,7 +541,7 @@ func (c *Tree) PutObjectTagging(ctx context.Context, bktInfo *data.BucketInfo, o
|
||||||
|
|
||||||
ind := tagNode.GetLatestNodeIndex()
|
ind := tagNode.GetLatestNodeIndex()
|
||||||
if tagNode.IsSplit() {
|
if tagNode.IsSplit() {
|
||||||
c.reqLogger(ctx).Error(logs.ObjectTaggingNodeHasMultipleIDs)
|
c.reqLogger(ctx).Warn(logs.FoundSeveralObjectTaggingNodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.service.MoveNode(ctx, bktInfo, versionTree, tagNode.ID[ind], objVersion.ID, treeTagSet)
|
return c.service.MoveNode(ctx, bktInfo, versionTree, tagNode.ID[ind], objVersion.ID, treeTagSet)
|
||||||
|
@ -634,14 +552,14 @@ func (c *Tree) DeleteObjectTagging(ctx context.Context, bktInfo *data.BucketInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) GetBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) (map[string]string, error) {
|
func (c *Tree) GetBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) (map[string]string, error) {
|
||||||
multiNode, err := c.getSystemNode(ctx, bktInfo, bucketTaggingFilename)
|
node, err := c.getSystemNode(ctx, bktInfo, []string{bucketTaggingFilename})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tags := make(map[string]string)
|
tags := make(map[string]string)
|
||||||
|
|
||||||
for key, val := range multiNode.Latest().Meta {
|
for key, val := range node.Meta {
|
||||||
if strings.HasPrefix(key, userDefinedTagPrefix) {
|
if strings.HasPrefix(key, userDefinedTagPrefix) {
|
||||||
tags[strings.TrimPrefix(key, userDefinedTagPrefix)] = val
|
tags[strings.TrimPrefix(key, userDefinedTagPrefix)] = val
|
||||||
}
|
}
|
||||||
|
@ -651,7 +569,7 @@ func (c *Tree) GetBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) (
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) PutBucketTagging(ctx context.Context, bktInfo *data.BucketInfo, tagSet map[string]string) error {
|
func (c *Tree) PutBucketTagging(ctx context.Context, bktInfo *data.BucketInfo, tagSet map[string]string) error {
|
||||||
multiNode, err := c.getSystemNode(ctx, bktInfo, bucketTaggingFilename)
|
node, err := c.getSystemNode(ctx, bktInfo, []string{bucketTaggingFilename})
|
||||||
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
||||||
if err != nil && !isErrNotFound {
|
if err != nil && !isErrNotFound {
|
||||||
return fmt.Errorf("couldn't get node: %w", err)
|
return fmt.Errorf("couldn't get node: %w", err)
|
||||||
|
@ -669,19 +587,12 @@ func (c *Tree) PutBucketTagging(ctx context.Context, bktInfo *data.BucketInfo, t
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
latest := multiNode.Latest()
|
ind := node.GetLatestNodeIndex()
|
||||||
ind := latest.GetLatestNodeIndex()
|
if node.IsSplit() {
|
||||||
if latest.IsSplit() {
|
c.reqLogger(ctx).Warn(logs.FoundSeveralBucketTaggingNodes)
|
||||||
c.reqLogger(ctx).Error(logs.BucketTaggingNodeHasMultipleIDs, zap.Uint64s("ids", latest.ID))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = c.service.MoveNode(ctx, bktInfo, systemTree, latest.ID[ind], 0, treeTagSet); err != nil {
|
return c.service.MoveNode(ctx, bktInfo, systemTree, node.ID[ind], 0, treeTagSet)
|
||||||
return fmt.Errorf("move bucket tagging node: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.cleanOldNodes(ctx, multiNode.Old(), bktInfo)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) DeleteBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) error {
|
func (c *Tree) DeleteBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) error {
|
||||||
|
@ -704,8 +615,6 @@ func (c *Tree) getTreeNodes(ctx context.Context, bktInfo *data.BucketInfo, nodeI
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// consider using map[string][]*treeNode
|
|
||||||
// to be able to remove unused node, that can be added during split
|
|
||||||
treeNodes := make(map[string]*treeNode, len(keys))
|
treeNodes := make(map[string]*treeNode, len(keys))
|
||||||
|
|
||||||
for _, s := range subtree {
|
for _, s := range subtree {
|
||||||
|
@ -780,6 +689,26 @@ func getLatestVersionNode(nodes []NodeResponse) (NodeResponse, error) {
|
||||||
return nodes[targetIndexNode], nil
|
return nodes[targetIndexNode], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getLatestNode(nodes []NodeResponse) NodeResponse {
|
||||||
|
if len(nodes) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index int
|
||||||
|
maxTimestamp uint64
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, node := range nodes {
|
||||||
|
if timestamp := getMaxTimestamp(node); timestamp > maxTimestamp {
|
||||||
|
index = i
|
||||||
|
maxTimestamp = timestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes[index]
|
||||||
|
}
|
||||||
|
|
||||||
func getMaxTimestamp(node NodeResponse) uint64 {
|
func getMaxTimestamp(node NodeResponse) uint64 {
|
||||||
var maxTimestamp uint64
|
var maxTimestamp uint64
|
||||||
|
|
||||||
|
@ -1629,11 +1558,11 @@ func metaFromMultipart(info *data.MultipartInfo, fileName string) map[string]str
|
||||||
return info.Meta
|
return info.Meta
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Tree) getSystemNode(ctx context.Context, bktInfo *data.BucketInfo, name string) (*multiSystemNode, error) {
|
func (c *Tree) getSystemNode(ctx context.Context, bktInfo *data.BucketInfo, path []string) (*treeNode, error) {
|
||||||
p := &GetNodesParams{
|
p := &GetNodesParams{
|
||||||
BktInfo: bktInfo,
|
BktInfo: bktInfo,
|
||||||
TreeID: systemTree,
|
TreeID: systemTree,
|
||||||
Path: []string{name},
|
Path: path,
|
||||||
LatestOnly: false,
|
LatestOnly: false,
|
||||||
AllAttrs: true,
|
AllAttrs: true,
|
||||||
}
|
}
|
||||||
|
@ -1648,10 +1577,10 @@ func (c *Tree) getSystemNode(ctx context.Context, bktInfo *data.BucketInfo, name
|
||||||
return nil, layer.ErrNodeNotFound
|
return nil, layer.ErrNodeNotFound
|
||||||
}
|
}
|
||||||
if len(nodes) != 1 {
|
if len(nodes) != 1 {
|
||||||
c.reqLogger(ctx).Warn(logs.FoundSeveralSystemNodes, zap.String("name", name))
|
c.reqLogger(ctx).Warn(logs.FoundSeveralSystemNodes, zap.String("path", strings.Join(path, "/")))
|
||||||
}
|
}
|
||||||
|
|
||||||
return newMultiNode(nodes)
|
return newTreeNode(getLatestNode(nodes))
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterMultipartNodes(nodes []NodeResponse) []NodeResponse {
|
func filterMultipartNodes(nodes []NodeResponse) []NodeResponse {
|
||||||
|
|
Loading…
Add table
Reference in a new issue