Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

861 library loading is blocking the main thread #974

Merged
merged 27 commits into from
Sep 21, 2024

Conversation

BPerlakiH
Copy link
Collaborator

@BPerlakiH BPerlakiH commented Sep 12, 2024

Fixes: #861

Summary:

I measured that the longest operation we have, when loading the library is:
[Archive](zim::Archive archive = zim::Archive([url fileSystemRepresentation]);

The way it worked so far:

We opened all the former files that were added to the local library, and passed through this Archive reading and stored it in memory.

After that was done, opening and displaying (any content really from) that ZIM file was quite quick.

The problem:

When we have relatively small files, or not much files added to the library, there's no visible issue.
Problems start when we have large files. Eg. a 100 GB wiki ZIM file, is taking time to open with the aforementioned Archive.

The solution:

Open the Archive on demand. Meaning, if we want a content from a ZIM file, only at that point open the Archive, and store it at that point, as opposed to app start. Subsequent requests to the get content (or metadata) from the same ZIM file will be equally quick as before. This makes the app start a lot faster, since we do not need to open those archives anymore on start.

Handle the side effects:

The side effect is that when we press on a button (eg. to open the home page of a local library ZIM file), won't open it right away, so we need some UI loading indicator that we are "working" on it.

For this I have added 2 new classes, AsyncButton and AsyncButtonView, which can handle alternative loading states, while the underlying task is working.

Handle concurrency:

Formerly most of the ZIM file operations were running on the main thread, which was safe in a way that no other threads were accessing the same: list of Archive or other IO operations outcomes.
The solution for this is a new @globalActor, that is: single instance, and only allows async access to the ZimFileService instance, and this way guarantees that the stored data within is only accessed in a thread safe manner.

Preview on mac:

async_loading_mac.mov

Adjusting search:

The other point to solve was searching. By default we can search in any local ZIM file, or to be precise the ones that were selected by the user to search in. Since the Search is initialised on start, it made sense to do the opening of the ZIM files at that point. This way we don't have a race between app start opening the ZIM archives and the user starting to search. This has also other benefits, as if the user excludes a ZIM file from search results (which is saved to the next app session), we do not need to open that archive. As soon as the user is (re)including that file in search results, the archive will be opened. The asynchronous part of this is handled during the search result loader / spinner:

Screenshot 2024-09-14 at 18 00 03 Screenshot 2024-09-14 at 17 58 52

@BPerlakiH BPerlakiH linked an issue Sep 12, 2024 that may be closed by this pull request
@codecov-commenter
Copy link

codecov-commenter commented Sep 12, 2024

Codecov Report

Attention: Patch coverage is 21.56134% with 211 lines in your changes missing coverage. Please review.

Please upload report for BASE (main@c9043bf). Learn more about missing BASE report.

Files with missing lines Patch % Lines
ViewModel/BrowserViewModel.swift 0.00% 52 Missing ⚠️
Views/ViewModifiers/FileImport.swift 0.00% 32 Missing ⚠️
Views/Library/ZimFileDetail.swift 3.84% 25 Missing ⚠️
Views/Buttons/AsyncButton.swift 0.00% 20 Missing ⚠️
Model/ZimFileService/ZimFileService.mm 43.47% 13 Missing ⚠️
Model/DownloadService.swift 0.00% 9 Missing ⚠️
SwiftUI/Model/LibraryOperations.swift 40.00% 9 Missing ⚠️
Views/BuildingBlocks/ZimFileCell.swift 30.76% 9 Missing ⚠️
App/App_iOS.swift 20.00% 8 Missing ⚠️
App/App_macOS.swift 20.00% 8 Missing ⚠️
... and 8 more
Additional details and impacted files
@@           Coverage Diff           @@
##             main     #974   +/-   ##
=======================================
  Coverage        ?   39.52%           
=======================================
  Files           ?      113           
  Lines           ?     6444           
  Branches        ?        0           
=======================================
  Hits            ?     2547           
  Misses          ?     3897           
  Partials        ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

rgaudin
rgaudin previously approved these changes Sep 13, 2024
Copy link
Member

@rgaudin rgaudin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM ; very useful improvement I'd say.

My only concern being on the UI. Now that it works well, could we imagine the visual spinner to be bound by the button's dimensions?
In the library card example, it works well because the loader is contained inside the card.
On the open homepage button, it doesn't because it's floating on top with the same (larger than the button) dimensions.

Notye: this comment is based on the screencast.

@BPerlakiH
Copy link
Collaborator Author

BPerlakiH commented Sep 14, 2024

@rgaudin the progress bar issue has been addressed:

progress_view_small.mov

@rgaudin
Copy link
Member

rgaudin commented Sep 14, 2024

Yep, looks good now

@kelson42
Copy link
Contributor

@BPerlakiH Can you please rebase?

@BPerlakiH BPerlakiH force-pushed the 861-library-loading-is-blocking-the-main-thread branch from 8b7a3d5 to 2a8a61a Compare September 20, 2024 10:16
@kelson42 kelson42 merged commit 358d7ce into main Sep 21, 2024
4 checks passed
@kelson42 kelson42 deleted the 861-library-loading-is-blocking-the-main-thread branch September 21, 2024 13:39
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.

Library loading is blocking the main thread
4 participants