[vlc-devel] [PATCH 00/13] Execute medialib queries out of the UI thread
Romain Vimont
rom1v at videolabs.io
Mon Nov 23 17:30:14 CET 2020
Currently, the Qt interface for medialibrary executes database queries from the
UI thread. As a consequence, every I/O blocking results in a freeze of the
whole VLC interface. In practice, on my computer, during medialibrary
indexation, it is common that VLC is frozen for tens of seconds (e.g. 45
seconds) on scrolling or click on a tab.
There are two major (and independent) issues:
1. I/O on the UI thread (#22687)
2. database lock starvation while indexing
This patchsets aims to fix the first one.
Even if the average query duration might sometimes be acceptable (at least with
an SSD), there may be I/O delay peaks making the UI laggy. Such I/O latency
should never freeze the whole application. Therefore, VLC should never execute
I/O (in particular database queries) from the UI thread. The problem is made
obvious when the database lock is held for tens of seconds for other queries.
The main difficulty in solving this problem lies in being able to destroy the
list model (on the UI thread) which initiated the database queries without
blocking (i.e. without waiting for the requests to finish), leaking or
undefined behavior.
## Patchset description
After some minor cleanups/preparation (patches 1 to 4), the real first step
consists in extracting a list cache, independant of the list model, in order to
avoid mixing independent concerns (patches 5 to 7). The cache strategy is left
unchanged (1 local page of 100 items aligned on multiples of 100) for now.
Next, data loaders are separated from the list model instances (patch 8).
This paves the way to destroy the list models without waiting for any pending
requests (which would block the UI thread).
Then, medialib queries are executed from a separate thread pool (patches 9 to
12), tied to the medialib instance (so it can outlive list models, but not the
medialib, required for executing queries). An AsyncTask API (patch 10) helps
executing a task on a thread pool and retrieve the result on the main thread,
and properly handle the case where the receiver is destroyed while a processing
is still running.
Finally, patch 13 declares QML images asynchronous to avoid more small freezes
on thumbnail/cover display.
## Remaining work
After these changes, the UI is not frozen by database queries anymore. However,
some database queries may still be very long, due to database lock starvation
while indexing. I will investigate this separate problem later.
There is still some work related to asynchronous loading:
- the UI should show that some background tasks are running (to let the user
know that the visible data is not up-to-date)
- a "cache miss" item should be designed (currently, it shows "unknown name"
with a cone)
- the cache strategy is suboptimal (if items of consecutive cache pages are
visible simultaneously, the cache will invalidate its data on each refresh);
- there are still "small" freezes sometimes (~250ms), but not always, when
updating the UI list once the database query result is available; it
requires more investigations
- the list model abstract class (MLSlidingWindowModel) is templated, causing
big compilation times on every change (which probably does not work the cost,
since the concrete classes use QVariant to expose the data to Qt anyway)
Branch: https://code.videolan.org/rom1v/vlc/commits/asyncml.v1
Regards
Romain Vimont (13):
qt: medialib: make fetch() const
qt: medialib: remove unused get()
qt: medialib: do not count on item()
qt: medialib: pass explicit query parameters
qt: medialib: introduce list cache
qt: medialib: use list cache from MLBaseModel
qt: medialib: pass loader via a raw pointer
qt: medialib: implement separate data loaders
qt: medialib: define a medialib thread pool
qt: medialib: introduce async task
qt: medialib: make cache load() asynchronous
qt: medialib: make cache count() asynchronous
qt: load QML images asynchronously
modules/gui/qt/Makefile.am | 6 +
modules/gui/qt/medialibrary/medialib.cpp | 3 +
modules/gui/qt/medialibrary/medialib.hpp | 4 +
modules/gui/qt/medialibrary/mlalbummodel.cpp | 48 ++-
modules/gui/qt/medialibrary/mlalbummodel.hpp | 12 +-
.../gui/qt/medialibrary/mlalbumtrackmodel.cpp | 62 ++--
.../gui/qt/medialibrary/mlalbumtrackmodel.hpp | 12 +-
modules/gui/qt/medialibrary/mlartistmodel.cpp | 61 ++--
modules/gui/qt/medialibrary/mlartistmodel.hpp | 12 +-
modules/gui/qt/medialibrary/mlbasemodel.cpp | 54 ++-
modules/gui/qt/medialibrary/mlbasemodel.hpp | 160 +++++----
modules/gui/qt/medialibrary/mlgenremodel.cpp | 53 +--
modules/gui/qt/medialibrary/mlgenremodel.hpp | 12 +-
modules/gui/qt/medialibrary/mlqueryparams.cpp | 14 +
modules/gui/qt/medialibrary/mlqueryparams.hpp | 68 ++++
.../gui/qt/medialibrary/mlrecentsmodel.cpp | 74 ++--
.../gui/qt/medialibrary/mlrecentsmodel.hpp | 20 +-
.../qt/medialibrary/mlrecentsvideomodel.cpp | 70 ++--
.../qt/medialibrary/mlrecentsvideomodel.hpp | 24 +-
modules/gui/qt/medialibrary/mlurlmodel.cpp | 53 +--
modules/gui/qt/medialibrary/mlurlmodel.hpp | 12 +-
modules/gui/qt/medialibrary/mlvideomodel.cpp | 50 +--
modules/gui/qt/medialibrary/mlvideomodel.hpp | 12 +-
.../qt/medialibrary/qml/ArtistTopBanner.qml | 1 +
.../qml/MusicAlbumsGridExpandDelegate.qml | 1 +
.../medialibrary/qml/VideoInfoExpandPanel.qml | 1 +
modules/gui/qt/util/asynctask.hpp | 250 +++++++++++++
modules/gui/qt/util/listcache.hpp | 337 ++++++++++++++++++
modules/gui/qt/widgets/qml/RoundImage.qml | 1 +
29 files changed, 1200 insertions(+), 287 deletions(-)
create mode 100644 modules/gui/qt/medialibrary/mlqueryparams.cpp
create mode 100644 modules/gui/qt/medialibrary/mlqueryparams.hpp
create mode 100644 modules/gui/qt/util/asynctask.hpp
create mode 100644 modules/gui/qt/util/listcache.hpp
--
2.29.2
More information about the vlc-devel
mailing list