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

Asynchronous execution of download actions #1118

Merged
merged 49 commits into from
Jul 19, 2024
Merged

Conversation

veloman-yunkan
Copy link
Collaborator

@veloman-yunkan veloman-yunkan commented May 24, 2024

Should fix #1094.

This PR solves issues caused by the fact that aria2c is a single threaded application (processing incoming data, including RPC requests, using the polled I/O approach) and it becomes unresponsive when saving to slow storage (such as old USB sticks).

The solution is based on issuing all (with one exception, see footnote ¹) requests to aria2c asynchronously, on a separate working thread. Before this PR only download status updates were processed asynchronously. Now download actions (start, pause, resume, cancel) are also executed asynchronously.

Now, after the user initiates a download action (for example, by clicking the download button) all download-related actions for that book are disabled until the response to that request is received.

The PR starts with a lot of refactoring, consolidating most of the download-related code in a separate pair of h/cpp source files.
It also contains a few minor otherwise unrelated fixes/improvements.

This PR depends on kiwix/libkiwix#1097 - mainly through some code that was moved from kiwix-desktop to libkiwix, though that part could in principle be extracted into a separate PR that may be merged later on.


¹ The only place where aria2c requests are executed in the main thread is during the creation of kiwix::Downloader. That loophole is worked around by kiwix/libkiwix#1097 (on which this PR also depends in one of the last commits) - all downloads are paused by modifying the aria2 session file so that aria2c stays idle and thus responsive.

@kelson42
Copy link
Collaborator

kelson42 commented Jun 2, 2024

@veloman-yunkan This is an attempt to fix #916 ?

@veloman-yunkan
Copy link
Collaborator Author

@kelson42 I was rather focused on #1094 but (at least some of) the underlying problems may be the same

@veloman-yunkan veloman-yunkan force-pushed the robust_download_management branch 2 times, most recently from 9a97f69 to 25b66e6 Compare June 30, 2024 09:56
@veloman-yunkan veloman-yunkan changed the title [WIP] Robust download management Asynchronous execution of download actions Jun 30, 2024
@veloman-yunkan veloman-yunkan marked this pull request as ready for review June 30, 2024 10:35
@veloman-yunkan
Copy link
Collaborator Author

@ShaopengLin @sgourdas I invite you to look at this PR as a educational material on refactoring. It illustrates how a major change can be made incrementally by carrying out significant amount of groundwork that facilitates implementing the sought goal. Please also feel free to do a real review and provide feedback!

@veloman-yunkan
Copy link
Collaborator Author

@ShaopengLin @sgourdas I invite you to look at this PR as a educational material on refactoring. It illustrates how a major change can be made incrementally by carrying out significant amount of groundwork that facilitates implementing the sought goal. Please also feel free to do a real review and provide feedback!

One known issue with this PR is that it is very big. But breaking it up into smaller ones is possible upon request. Yet it is better that the reviewers can see the full picture and can participate in deciding if and how the decomposition should be performed.

@veloman-yunkan
Copy link
Collaborator Author

@kelson42 Can you please perform some independent testing? I did it by downloading to a KIWIX/WIKIMEDIA branded USB stick from the hackathon. Note that libkiwix should be built using kiwix/libkiwix#1097.

Copy link
Member

@mgautierfr mgautierfr left a comment

Choose a reason for hiding this comment

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

Nice PR. I have seen only few changes.

On functional side, now when closing kiwix-desktop with a ongoing download, at restart the download is paused. Would be nice to have it automatically restarted (especially as a downloading zim is not visible in local library, the default view).
But can be made in another PR, this one is big enough.

@@ -82,7 +82,7 @@ DownloadManager::~DownloadManager()

// At this point the thread may be stuck waiting for data.
// Let's wake it up.
m_requestQueue.enqueue("");
m_requestQueue.enqueue({UPDATE, ""});
Copy link
Member

Choose a reason for hiding this comment

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

Would it be better to have a PING action instead of using the (empty) id ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The id component will still need to be provided, so it won't look much prettier here.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe hide it in a wake_up or notify method ?

src/contentmanager.cpp Outdated Show resolved Hide resolved
src/downloadmanagement.h Show resolved Hide resolved
@veloman-yunkan
Copy link
Collaborator Author

The changes were inserted as fixup commits at the correct locations in the PR history.

@veloman-yunkan
Copy link
Collaborator Author

On functional side, now when closing kiwix-desktop with a ongoing download, at restart the download is paused. Would be nice to have it automatically restarted (especially as a downloading zim is not visible in local library, the default view).
But can be made in another PR, this one is big enough.

Agree. There are also a couple of edge cases like the book appearing in an obscure state when the app exits while the download request has been enqueued but not yet submitted to aria2 (this is easily cleared via the "Delete book" action but may be confusing to the user). I think that those too better be fixed in a separate PR.

Copy link
Collaborator

@ShaopengLin ShaopengLin left a comment

Choose a reason for hiding this comment

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

I will comment on some immediate observations. I will do the learning on our downloader architecture and intricacies in my own time as it will probably take a while. (Might be too long for this PR)

src/contentmanagerdelegate.cpp Outdated Show resolved Hide resolved
src/contentmanager.cpp Show resolved Hide resolved
@kelson42
Copy link
Collaborator

@veloman-yunkan I have tested briefly and it works better than before and I was not able to detect any bug... but can you please fix so "Download" and the downloading progression are horizontaly center in the column? They are not (anymore?)
image

@veloman-yunkan
Copy link
Collaborator Author

@veloman-yunkan I have tested briefly and it works better than before and I was not able to detect any bug... but can you please fix so "Download" and the downloading progression are horizontaly center in the column? They are not (anymore?) image

Let's first merge this PR, and we can pursue purely aesthetic issues afterwards.

@kelson42
Copy link
Collaborator

kelson42 commented Jul 15, 2024

There is one problem: if i click on download, it does not download straight. It should.

@mgautierfr
Copy link
Member

I have just answered on your answer of my comment (comment of comment of comment...)
Except that (and you may continue without my comment) I agree with the code. As we have already stated, there is few issue but can be fixed in another PRs.

At least, you can rebase-fixup before a final approval.

@mgautierfr
Copy link
Member

There is one problem: if i click on download, it does not download straight. It should.

That is the root cause of the PR. Sometime aria2 takes time to start the download.
And before this PR, it was freezing the UI.
This PR is not fixing aria2 (not sure we can), it move the start (and other operation) in a separated thread to not freeze UI. But it doesn't start the download faster.

How much time is "not download straight" ?

If download info becomes stale (due to slow responses from aria)
the download speed is shown as ---.

Known issues:
  - A stale download is refreshed only due to a GUI event (such
    as scrolling or mouse hover).
Made the download updater thread process requests from a queue.

Such a scheme paves the path to performing all download actions
asynchronously by placing them onto the queue (which will eliminate
non-responsiveness of the application when those commands hit the
problem with slow responses from aria2c).
Pausing a download now changes its state to PAUSE_REQUESTED and the
pause request is enqueued for asynchronous execution. Similarly,
resuming a download changes its state to RESUME_REQUESTED and the resume
request is enqueued for asynchronous execution.

In the PAUSE_REQUESTED and RESUME_REQUESTED states download actions
are disabled.

Known issues:
 - The PAUSE_REQUESTED state may be incorrectly restored to DOWNLOADING
   if at the time of pausing an earlier UPDATE request for the same
   download preceded it in the queue or was being executed. After
   the response to the said UPDATE request is received it results
   in the DownloadState being reset to the previous state. But after
   the pause request is processed a subsequent UPDATE request will
   change the state to PAUSED. In GUI this looks as follows (assuming
   slow responses from aria2c, allowing to observe the events in slow
   motion):

   1. Pause button is pressed
   2. Pause button and download progress info (the textual one) disappear
   3. Pause button and download progress info (the textual one) re-appear
   4. Download switches to paused state without any further user actions

   A similar problem exists for resuming the download.

   The solution is to convert the request queue to a priority queue
   where download actions are given precedence over update actions.
   However this will not eliminate the problem completely since a
   pause/resume action may be issued while an update request is being
   processed by aria2c (the likelyhood of which greatly increases if
   aria is mostly stuck struggling with slow storage). The latter
   case will be addressed by tracking the timestamps of the requests
   and ignoring the download status from those update requests that
   were issued before the user action requests.
During the previous commit indentation of some lines was preserved
in order to minimize the diff. Now it is fixed.
... provided that download actions are inserted into the queue *before* existing
update requests.
Separated checks that can be performed early (independent of aria2c
services). When the download initiation is converted to a 2-stage
procedure (similar to how it was done for pausing/resuming/cancelling
a download) those checks better be performed synchronously in the main
thread.
Extracted from ContentManager::downloadBook() the part that should be
executed asynchronously into a new function
`ContentManager::startDownload()`.
Preparing to handle errors originating in the (future) asynchronous
execution of `ContentManager::startDownload()`.
@kelson42
Copy link
Collaborator

Rebasing to benefit of the CI fix

@kelson42
Copy link
Collaborator

@veloman-yunkan I have tested briefly and it works better than before and I was not able to detect any bug... but can you please fix so "Download" and the downloading progression are horizontaly center in the column? They are not (anymore?) image

Let's first merge this PR, and we can pursue purely aesthetic issues afterwards.

I have open #1145

@kelson42
Copy link
Collaborator

@veloman-yunkan @mgautierfr Are we good to merge?! Beside a discussion still open I see nothing left but not formal approval either?!

Copy link
Collaborator

@kelson42 kelson42 left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Member

@mgautierfr mgautierfr left a comment

Choose a reason for hiding this comment

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

LGTM

@kelson42 kelson42 merged commit 3ee2537 into main Jul 19, 2024
4 checks passed
@kelson42 kelson42 deleted the robust_download_management branch July 19, 2024 09:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Kiwix windows 64 bit freezes when trying to download file more than 20 mb
5 participants