mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-30 00:40:44 +01:00
s3: return x-amz-copy-source-version-id from CopyObject and UploadPartCopy (#12181)
* s3: return x-amz-copy-source-version-id from CopyObject and UploadPartCopy * s3: cover x-amz-copy-source-version-id on latest copies and part copies The explicit-version case was already covered; add a .versions pointer fixture so the unversioned request resolves the latest version and asserts the header on CopyObject, plus the same assertion on UploadPartCopy. * s3: carry the resolved id on a version file that lacks it A .versions child written before the version-id attribute resolves to an empty source version even though the pointer or the rescan already knows it. Stamp the id on the returned entry so copy and get readers report it; the version copy tests now drop the attribute to cover that shape. * s3: report the null version in x-amz-copy-source-version-id A regular-path source in a versioning-configured bucket is the null version; echo it like every other version id, matching the GET path and AWS. Unversioned sources still report no header. * s3: report the version a self-copy retry actually read --------- Co-authored-by: user.email <chrislusf@users.noreply.github.com>
This commit is contained in:
1 parent
48782e2b30
commit
6225e0a705
3 files changed
+223
-1
No files matched your search
@@ -2078,7 +2078,23 @@ func (s3a *S3ApiServer) doGetLatestObjectVersion(bucket, object string, maxRetri
|
||||
return nil, fmt.Errorf("failed to get latest version file %s: %v", latestVersionPath, err)
|
||||
}
|
||||
|
||||
return latestVersionEntry, nil
|
||||
return attachResolvedVersionId(latestVersionEntry, latestVersionId), nil
|
||||
}
|
||||
|
||||
// attachResolvedVersionId stamps the resolved id on a versioned child that
|
||||
// predates the version-id attribute, so readers see the id the pointer or the
|
||||
// rescan already recovered without re-deriving it from the file name.
|
||||
func attachResolvedVersionId(entry *filer_pb.Entry, versionId string) *filer_pb.Entry {
|
||||
if entry == nil || versionId == "" {
|
||||
return entry
|
||||
}
|
||||
if entry.Extended == nil {
|
||||
entry.Extended = make(map[string][]byte)
|
||||
}
|
||||
if len(entry.Extended[s3_constants.ExtVersionIdKey]) == 0 {
|
||||
entry.Extended[s3_constants.ExtVersionIdKey] = []byte(versionId)
|
||||
}
|
||||
return entry
|
||||
}
|
||||
|
||||
// recoverLatestVersionWithoutPointer handles a .versions directory that exists
|
||||
@@ -2249,6 +2265,8 @@ func (s3a *S3ApiServer) healStaleLatestVersionPointer(bucket, normalizedObject s
|
||||
return nil, fmt.Errorf("%w: no remaining version in %s", filer_pb.ErrNotFound, versionsDir)
|
||||
}
|
||||
|
||||
latestEntry = attachResolvedVersionId(latestEntry, latestVersionId)
|
||||
|
||||
// The persist is CAS-style (mirroring clearStaleLatestVersionPointer) so a
|
||||
// stale repair cannot supersede a concurrent writer: the rescan takes time,
|
||||
// during which a PUT or delete may have atomically advanced the pointer on
|
||||
|
||||
Reference in new issue
Block a user