Rclone does not delete segments when move object fail with swift Openstack backend

Hi!,
I try move large object between 2 swift cluster backend, but the problem raised when destination's quota have free less than size of object but the free quota larger than segment's size. The some first segments create normally at destination but when destination reached the quota and error raised (error code: 413, message : Too Large Object). After that rclone continue retry but can not because the destination reached limit quota. Finally, rclone finish with error that could not move the object (Failed to move: Too Large Object). I check at destination segment container several segments created and not delete after run.

I try to debug and see the code in swift backend handle updateChunks not delete segment uploaded if the error raise as describe above. After that i try add some code as below (emphasis), the change try check if the error raise during upload segment and delete segments uploaded.

#code

func (o *Object) updateChunks(in0 io.Reader, headers swift.Headers, size int64, contentType string) (string, error) {
// Create the segmentsContainer if it doesn't exist
var err error
err = o.fs.pacer.Call(func() (bool, error) {
var rxHeaders swift.Headers
_, rxHeaders, err = o.fs.c.Container(o.fs.segmentsContainer)
return shouldRetryHeaders(rxHeaders, err)
})
if err == swift.ContainerNotFound {
headers := swift.Headers{}
if o.fs.opt.StoragePolicy != "" {
headers["X-Storage-Policy"] = o.fs.opt.StoragePolicy
}
err = o.fs.pacer.Call(func() (bool, error) {
err = o.fs.c.ContainerCreate(o.fs.segmentsContainer, headers)
return shouldRetry(err)
})
}
if err != nil {
return "", err
}
// Upload the chunks
left := size
i := 0
uniquePrefix := fmt.Sprintf("%s/%d", swift.TimeToFloatString(time.Now()), size)
segmentsPath := fmt.Sprintf("%s%s/%s", o.fs.root, o.remote, uniquePrefix)
in := bufio.NewReader(in0)
segmentInfos := make([]string, 0, ((size / int64(o.fs.opt.ChunkSize)) + 1))
for {
// can we read at least one byte?
if _, err := in.Peek(1); err != nil {
if left > 0 {
return "", err // read less than expected
}
fs.Debugf(o, "Uploading segments into %q seems done (%v)", o.fs.segmentsContainer, err)
break
}
n := int64(o.fs.opt.ChunkSize)
if size != -1 {
n = min(left, n)
headers["Content-Length"] = strconv.FormatInt(n, 10) // set Content-Length as we know it
left -= n
}
segmentReader := io.LimitReader(in, n)
segmentPath := fmt.Sprintf("%s/%08d", segmentsPath, i)
fs.Debugf(o, "Uploading segment file %q into %q", segmentPath, o.fs.segmentsContainer)
err = o.fs.pacer.CallNoRetry(func() (bool, error) {
var rxHeaders swift.Headers
rxHeaders, err = o.fs.c.ObjectPut(o.fs.segmentsContainer, segmentPath, segmentReader, true, "", "", headers)
if err == nil {
segmentInfos = append(segmentInfos, segmentPath)
}
return shouldRetryHeaders(rxHeaders, err)
})
if err != nil {
if len(segmentInfos) > 0 {
for _, v := range segmentInfos {
fs.Debugf(o, "Delete segment file %q on %q", v, o.fs.segmentsContainer)
e := o.fs.c.ObjectDelete(o.fs.segmentsContainer, v)
if e != nil {
fs.Errorf(o, "Error occured in delete segment file %q on %q , error: %q", v, o.fs.segmentsContainer, e)
}
}
segmentInfos = nil
}
return "", err
}
i++
}
// Upload the manifest
headers["X-Object-Manifest"] = urlEncode(fmt.Sprintf("%s/%s", o.fs.segmentsContainer, segmentsPath))
headers["Content-Length"] = "0" // set Content-Length as we know it
emptyReader := bytes.NewReader(nil)
manifestName := o.fs.root + o.remote
err = o.fs.pacer.Call(func() (bool, error) {
var rxHeaders swift.Headers
rxHeaders, err = o.fs.c.ObjectPut(o.fs.container, manifestName, emptyReader, true, "", contentType, headers)
return shouldRetryHeaders(rxHeaders, err)
})
return uniquePrefix + "/", err
}r)
})
return uniquePrefix + "/", err
}

Could anyone help me review and check the code modified? If the describe above is missing check when upload segments fail, could merge it to handle upload segments fail ? I'm newbie in golang :slight_smile:

Thanks,
Luan Nguyen Huu.

Hi All,
Sorry the code above hard to view, the code modifed in https://codeshare.io/arEwO6
in the file I add line 1130, 1152 to 1154, 1158 to 1167 same as emphasis code in original post.

Thanks,
Luan Nguyen Huu.

That change looks about right to me. Do you want to submit it as a pull request?

Hi @ncw,
If the change is not effect the current logic, could you verify change and merge to master?
Finally, I think we need to check error when upload manifest after successful uploaded segments, if the manifest fail we need retry upload manifest or delete segments uploaded and retry processing upload object.

Sincerely thanks,
Luan Nguyen Huu.

Absolutely, but I need it submitted as a pull request: https://github.com/ncw/rclone/pulls - thanks!

Hi @ncw,
I submitted pull request at https://github.com/ncw/rclone/pull/3297

Thank you support me.
Luan Nguyen Huu

1 Like

I'll check it out a bit later today

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.