Skip to content

fix(dav): keep upload session while its chunks are being assembled - #63122

Open
solracsf wants to merge 1 commit into
masterfrom
fix/upload-session-delete-race
Open

fix(dav): keep upload session while its chunks are being assembled#63122
solracsf wants to merge 1 commit into
masterfrom
fix/upload-session-delete-race

Conversation

@solracsf

Copy link
Copy Markdown
Member

Summary

The final MOVE of a chunked upload streams the chunks into the destination one after another, opening each only when it gets there. A client that gives up on the upload - the desktop client does this when the assembly MOVE answers with an ambiguous 502 - deletes the upload session, which pulls the remaining chunks out from under the assembly that is still reading them. The assembly then fails on a chunk that no longer exists, and the upload has to be retried from the start.

This PR holds an exclusive lock for the duration of the assembly and take the same lock before deleting a session, so a delete that arrives mid-assembly is answered with 423 instead of destroying the chunks. The lock sits on a path with nothing behind it, the way createFile() guards its part file, so it does not collide with the deletion of the session that ends a successful move.

The lock is held through the file locking provider rather than a distributed cache, so it also works on instances that have no memcache configured. Two paths remain outside it by design: the background upload cleanup job deletes sessions through the filesystem API, but only ever expires sessions whose files are all older than the TTL, and the lock itself expires with the locking provider's TTL, which bounds how long a crashed assembly keeps its session undeletable.

Checklist

AI (if applicable)

  • The content of this PR was partly or fully generated using AI

…ng assembled

The final MOVE of a chunked upload streams the chunks into the destination one
after another, opening each only when it gets there. A client that gives up on
the upload - the desktop client does this when the assembly MOVE answers with an
ambiguous 502 - deletes the upload session, which pulls the remaining chunks out
from under the assembly that is still reading them. The assembly then fails on a
chunk that no longer exists, and the upload has to be retried from the start.

Hold an exclusive lock for the duration of the assembly and take the same lock
before deleting a session, so a delete that arrives mid-assembly is answered
with 423 instead of destroying the chunks. The lock sits on a path with nothing
behind it, the way createFile() guards its part file, so it does not collide
with the deletion of the session that ends a successful move.

The lock is held through the file locking provider rather than a distributed
cache, so it also works on instances that have no memcache configured. Two
paths remain outside it by design: the background upload cleanup job deletes
sessions through the filesystem API, but only ever expires sessions whose files
are all older than the TTL, and the lock itself expires with the locking
provider's TTL, which bounds how long a crashed assembly keeps its session
undeletable.

Signed-off-by: Git'Fellow <12234510+solracsf@users.noreply.github.com>
@solracsf solracsf added this to the Nextcloud 35 milestone Aug 10, 2026
@solracsf
solracsf requested a review from a team as a code owner August 10, 2026 12:44
@solracsf
solracsf requested review from Altahrim and salmart-dev and removed request for a team August 10, 2026 12:44
@solracsf solracsf added the bug label Aug 10, 2026
@solracsf solracsf self-assigned this Aug 10, 2026
@nextcloud-bot nextcloud-bot mentioned this pull request Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error assembling chunks - chunks deleted too soon?

1 participant