mirror of
https://github.com/versity/versitygw.git
synced 2026-10-22 14:22:40 +00:00
The `sidecar` metadata storer keeps attributes by path rather than on the file. So a new file published at an object's path inherited every attribute it didn't set itself: tags, user metadata, content headers and `x-amz-website-redirect-location`, plus legal hold and retention on version promotion. This hit overwrites by `PutObject`, `CopyObject` and `CompleteMultipartUpload`, new versions and `PutObject` over a delete marker in versioned buckets, and the version made current again by `DeleteObject` with a `versionId`. A plain `PutObject` over a multipart object also kept its `mp-metadata`, so `HeadObject` and `GetObject` with `partNumber` returned the old `PartsCount` and a `Content-Range` beyond the object size. `xattr` was not affected, since its attributes live on the inode and are replaced along with it. Add `ReplaceObject(bucket, object, keep)` to `MetadataStorer`. It is a no-op for `XattrMeta` and `NoMeta`. `SideCar` removes the object's attribute files not named in `keep` and leaves directories in place, since they hold the metadata of objects under `<object>/meta/`. Posix calls it in `PutObject` and `CompleteMultipartUpload` after the version snapshot, and in `DeleteObject` when restoring the latest remaining version. This replaces the scattered deletes of the delete marker, `versionId` and object lock attributes. Attributes that every publish rewrites are kept and overwritten in place: the etag, the checksums, the new `versionId`, `mp-metadata` for multipart uploads, and the restored version's attributes on promotion. This way concurrent readers, such as the lock-free `If-Match` fast-fail check, never see them missing. `PutObject` now re-checks under the publish lock that the object path hasn't become a directory while the body was staged, as `CompleteMultipartUpload` already does. This stops it from removing the attributes of a directory object created by a racing `PUT foo/`.
65 lines
2.1 KiB
Go
65 lines
2.1 KiB
Go
// Copyright 2025 Versity Software
|
|
// This file is licensed under the Apache License, Version 2.0
|
|
// (the "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
package meta
|
|
|
|
import (
|
|
"os"
|
|
)
|
|
|
|
// NoMeta is a metadata storer that does not store metadata.
|
|
// This can be useful for read only mounts where attempting to store metadata
|
|
// would fail.
|
|
type NoMeta struct{}
|
|
|
|
// RetrieveAttribute retrieves the value of a specific attribute for an object or a bucket.
|
|
// always returns ErrNoSuchKey
|
|
func (NoMeta) RetrieveAttribute(_ *os.File, _, _, _ string) ([]byte, error) {
|
|
return nil, ErrNoSuchKey
|
|
}
|
|
|
|
// StoreAttribute stores the value of a specific attribute for an object or a bucket.
|
|
// always returns nil without storing the attribute
|
|
func (NoMeta) StoreAttribute(_ *os.File, _, _, _ string, _ []byte) error {
|
|
return nil
|
|
}
|
|
|
|
// DeleteAttribute removes the value of a specific attribute for an object or a bucket.
|
|
// always returns nil without deleting the attribute
|
|
func (NoMeta) DeleteAttribute(_, _, _ string) error {
|
|
return nil
|
|
}
|
|
|
|
// ListAttributes lists all attributes for an object or a bucket.
|
|
// always returns an empty list of attributes
|
|
func (NoMeta) ListAttributes(_, _ string) ([]string, error) {
|
|
return []string{}, nil
|
|
}
|
|
|
|
// DeleteAttributes removes all attributes for an object or a bucket.
|
|
// always returns nil without deleting any attributes
|
|
func (NoMeta) DeleteAttributes(bucket, object string) error {
|
|
return nil
|
|
}
|
|
|
|
// RenameObject is a no-op because NoMeta does not store metadata.
|
|
func (NoMeta) RenameObject(_, _, _ string) error {
|
|
return nil
|
|
}
|
|
|
|
// ReplaceObject is a no-op because NoMeta does not store metadata.
|
|
func (NoMeta) ReplaceObject(_, _ string, _ []string) error {
|
|
return nil
|
|
}
|