mirror of
https://github.com/pgsty/minio.git
synced 2026-11-11 01:55:30 +03:00
fix(restore): preserve versions across cleanup and failed reads
Reject replacement markers and legacy objects before restored-copy cleanup can mutate their type or data. Prevent restore lookups and failure cleanup from purging dangling versions, preserve Transition on metadata rereads, and return without writing when the initial restore read fails. Add real-disk regressions for stale null tasks, minority metadata, initial and cleanup read failures, and stored marker/legacy types. Keep ordinary dangling cleanup and marker purge as positive controls. Signed-off-by: Feng Ruohang <rh@vonng.com>
This commit is contained in:
+15
-2
@@ -509,6 +509,11 @@ func joinErrs(errs []error) string {
|
||||
}
|
||||
|
||||
func (er erasureObjects) deleteIfDangling(ctx context.Context, bucket, object string, metaArr []FileInfo, errs []error, dataErrsByPart map[int][]int, opts ObjectOptions) (FileInfo, error) {
|
||||
// Restore and restored-copy cleanup must preserve the version on read
|
||||
// failure, including lookups and failure cleanup that reread metadata.
|
||||
if opts.Transition.ExpireRestored || opts.Transition.RestoreRequest != nil {
|
||||
return FileInfo{}, errErasureReadQuorum
|
||||
}
|
||||
m, ok := isObjectDangling(metaArr, errs, dataErrsByPart)
|
||||
if !ok {
|
||||
// We only come here if we cannot figure out if the object
|
||||
@@ -2136,6 +2141,12 @@ func (er erasureObjects) DeleteObject(ctx context.Context, bucket, object string
|
||||
}
|
||||
}
|
||||
|
||||
// A queued null restore may now address a replacement delete marker.
|
||||
// Such errors carry ObjectInfo, but never authorize cache cleanup.
|
||||
if opts.Transition.ExpireRestored && (gerr != nil || goi.DeleteMarker) {
|
||||
return objInfo, VersionNotFound{Bucket: bucket, Object: object, VersionID: opts.VersionID}
|
||||
}
|
||||
|
||||
if opts.EvalMetadataFn != nil {
|
||||
dsc, err := opts.EvalMetadataFn(&goi, gerr)
|
||||
if err != nil {
|
||||
@@ -2641,7 +2652,8 @@ func (er erasureObjects) updateRestoreMetadata(ctx context.Context, bucket, obje
|
||||
delete(oi.UserDefined, xhttp.AmzRestore)
|
||||
|
||||
if _, err := er.CopyObject(ctx, bucket, object, bucket, object, oi, ObjectOptions{
|
||||
VersionID: oi.VersionID,
|
||||
VersionID: oi.VersionID,
|
||||
Transition: opts.Transition,
|
||||
}, ObjectOptions{
|
||||
VersionID: oi.VersionID,
|
||||
}); err != nil {
|
||||
@@ -2665,7 +2677,8 @@ func (er erasureObjects) restoreTransitionedObject(ctx context.Context, bucket s
|
||||
// get the file info on disk for transitioned object
|
||||
actualfi, _, _, err := er.getObjectFileInfo(ctx, bucket, object, opts, false)
|
||||
if err != nil {
|
||||
return setRestoreHeaderFn(oi, toObjectErr(err, bucket, object))
|
||||
// No version was read, so there is no restore metadata to update.
|
||||
return toObjectErr(err, bucket, object)
|
||||
}
|
||||
|
||||
oi = actualfi.ToObjectInfo(bucket, object, opts.Versioned || opts.VersionSuspended)
|
||||
|
||||
Reference in New Issue
Block a user