Repository navigation
fix(file-provider): Properly handle cancellations - #11001
claucambra wants to merge 40 commits into
Conversation
|
@claucambra Please rebase onto |
67f30c7 to
a27c618
Compare
Rebased and resolved now |
a27c618 to
8336b0f
Compare
i2h3
left a comment
There was a problem hiding this comment.
Reviewed at 8336b0f. Main points:
- A cancelled fetch is persisted as
.downloadError, which blocks later depth-1 metadata updates for that item (Item+Fetch.swift). - A chunked upload cancelled during assembly reports cancellation although the server committed the file (Upload.swift).
- Upload cancellation has no tests; the new upload mock hooks are unused.
The rest are edge cases and test-robustness notes. The NetworkOperationCancellation helper and the thumbnail batching look correct to me (Darwin invokes cancellationHandler asynchronously, so no lock re-entrancy; registrations are sequential).
Hygiene: only 2 of 22 commits carry an Assisted-by: trailer while the PR declares AI assistance; please add it where it applies. At ~2.4k changed lines across uploads, downloads, thumbnails, capabilities and account waits, splitting the helper + uploads from the download changes would ease review. The failing classic-client PermissionsTest is unrelated.
Review prepared with AI assistance (Claude Code) and checked against the head commit.
0138514 to
adce455
Compare
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com> Assisted-by: Codex:GPT-6
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com> Assisted-by: Codex:GPT-6
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
… acquisition Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…celled item fetch Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…der from overwriting what is newer state Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…ad contents Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…ail instead of hanging Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…d overlapping names Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…imeout, waiting for actual registration Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…ack to normal, downloaded set to false, no session error Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
… for later changes Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…m NextcloudKit Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…chunked uploads through upload, create and modify Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…en more than one task depends on it Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…erly waiting for account setup Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…ownload Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Require the release that preserves committed chunk-upload results when cancellation arrives during assembly. Assisted-by: Codex:GPT-6 Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Verify create and modify persist completed chunked uploads despite cancellation, including the server identity, ETag and chunk cleanup. Reopen Realm after the async modify before checking chunk rows so the existing exclusion test does not access a Realm from another thread. Assisted-by: Codex:GPT-6 Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
adce455 to
5890733
Compare
|
There was a problem hiding this comment.
- b4361ca clears
deletedon unchanged rows in every non-paginated depth-1 read, which brings back local-only deletions (inline). cancelledWaiterDoesNotWaitForAccountTimeoutstill hangs instead of failing if cancellation regresses (inline).- 4 of 40 commits mention
Assisted-by: Codex:GPT-6, and in each a blank line separates it fromSigned-off-by, so git parses only one of the two as a trailer. Please add the trailer to every commit with AI-assisted content, in the same block asSigned-off-by.
Review prepared with AI assistance (Claude Code) and checked against the head commit.
| if existingMetadata.status == Status.normal.rawValue, !existingMetadata.isInSameDatabaseStoreableRemoteState(updatedMetadata) { | ||
| // Clear a stale deleted flag even when the server returns unchanged metadata. | ||
| if existingMetadata.status == Status.normal.rawValue, | ||
| existingMetadata.deleted || !existingMetadata.isInSameDatabaseStoreableRemoteState(updatedMetadata) |
There was a problem hiding this comment.
This clears deleted on every unchanged .normal row in each non-paginated depth-1 read (working-set scan, change enumeration, directory fetch). Some tombstones are local-only on purpose while the server copy stays unchanged: deleting an ignored file (Item+Delete.swift:64-69) and consuming the excluded-from-sync marker of a bundle (Item+Delete.swift:49-61). The next read of their parent now reports them again through didUpdate, so a deleted ignored file comes back and an excluded bundle's server copy is re-reported at the path of the user's local copy. The paginated path already did this through addItemMetadataPreservingLocalState, but this change extends it to the frequent paths, and the cancellation fix does not need it. If the package case from my earlier comment needs a live child row, could fetchDirectoryContents upsert the listed child before beginDownload, as base did with addItemMetadata? A general tombstone change would fit its own PR, with tests that an ignored file and an excluded bundle stay deleted after their parent is read.
| var iterator = waiting.makeAsyncIterator() | ||
| _ = await iterator.next() | ||
| task.cancel() | ||
| await #expect(throws: CancellationError.self) { try await task.value } |
There was a problem hiding this comment.
If onCancel in awaitAccount stops resuming the waiter, which is what this test guards, task.value never returns: the timeout is UInt64.max, nothing calls signalAccountReady(), and awaiting an unstructured task's value does not react to .timeLimit cancelling the test. The Tests job has no timeout-minutes, so CI would hang rather than fail. Wrapping it as Task<Bool, Never> (true when CancellationError was thrown) so testTaskValue(of:) can bound it, plus defer { ext.signalAccountReady() } as in the next test, would make it fail instead.



Resolves
Second fix for #10579
Summary
Ensures cancellation propagates through File Provider uploads, downloads, and thumbnail fetches. Previously, cancellation did not consistently reach the surrounding operation or its supporting network requests, allowing cancelled operations to continue, update database state, and potentially report success
Checklist
AI (if applicable)