refactor(mobile): iOS introduce ImageRequest base class with unified cancellation and finish helpers#27489
refactor(mobile): iOS introduce ImageRequest base class with unified cancellation and finish helpers#27489
Conversation
|
Label error. Requires exactly 1 of: changelog:.*. Found: 📱mobile. A maintainer will add the required label. |
| var isCancelled: Bool { | ||
| lock.withLock { _isCancelled } | ||
| } |
There was a problem hiding this comment.
@mertalev back to your review questions in the other PR:
yes this does need a lock.
The swift docs say that the swift memory model has a conflict if all three conditions are met:
The accesses aren't both reads, and aren't both atomic. They access the same location in memory. Their durations overlap.
_isCancelled is written in cancel() (potentially from the Dart/main thread) and read in isCancelled (from the OperationQueue worker thread).
That's a concurrent write + read on the same memory address.
Swift also clarifies that plain variable access is not atomic:
An access is atomic if it’s a call to an atomic operation on Atomic or AtomicLazyReference, or if it uses only C atomic operations; otherwise it’s nonatomic. For a list of C atomic functions, see the stdatomic(3) man page.
So, a plain Bool write/read is nonatomic, without the lock we have two nonatomic, overlapping, one read, a written...means undefined behaviour.
This was actually a "bug" that was in the pre existing code.
| lock.withLock { _isCancelled } | ||
| } | ||
|
|
||
| init(callback: @escaping (Result<[String: Int64]?, any Error>) -> Void) { |
2875ac9 to
656c7c2
Compare
828dd8a to
44d0653
Compare
|
I'm not sure about this PR. It seems to be bundling a lot of distinct responsibilities into |
79897a8 to
d5e23c0
Compare
|
@mertalev Thx for pointing out the issues. I fixed the memory issue, but more importantly I moved the image processing stuff back into the Impl files. Do you think it's better now? My idea behind the callback was:
I can also remove the callback clearing, and we run it again always in the BlockOperations before returning from our worker threads. But that would also mean, when cancelling we would have to check if the current block operation exists and is not yet running, because then we would have to call the callback then there too. And now that I have already touched the code again, I also moved #27524 into here. |
|
Closing this in favour of #27672 |
Description
After PR #27486, LocalImageRequest and RemoteImageRequest each still duplicated the same boilerplate: an isCancelled flag, a stored callback, a cancel() method, and identical malloc/vImage_Buffer blocks in their respective ImageApiImpl.
This PR adds the ImageRequest base class with:
The Remote and Local ImageRequest implement the Base class.
Behaviour changes that this PR includes:
the pigeon callback is now called directly when setting isCancelled to true. Not when the thread runs and sees that isCancelled is true and terminates the operation.
I think we can already communicate to flutter that the operation is cancelled and we don't have to wait on the thread to actually return or?
How Has This Been Tested?
Checklist:
src/services/uses repositories implementations for database calls, filesystem operations, etc.src/repositories/is pretty basic/simple and does not have any immich specific logic (that belongs insrc/services/)Please describe to which degree, if any, an LLM was used in creating this pull request.
/