Skip to content

MediaLibrary: Add priority access mechanism

Romain Vimont requested to merge rom1v/medialibrary:priority_access into master

In addition to read-lock and write-lock, add a "priority access" mechanism. The goal is to give priority to UI requests.

Several callers may acquire a "priority access". As soon as at least one caller has priority access, all non-priority callers are blocked on lock_read() and lock_write(), until all priority accesses are released. However, they can continue executing their current requests following the traditional RW-lock rules.

Acquiring a priority access is "immediate". It is different from a lock in that it never blocks but makes other clients wait.

Context

When the VLC UI loads a list of items, it generates many read requests to the medialibrary, each one protected by a read-lock, but not globally protected by a single lock/unlock. As a consequence, during indexation, many write requests were executed between these read requests, causing the loading time to explode (several tens of seconds instead of milliseconds).

Alternative considered: exclusive lock

To avoid interleaving of read requests from the UI and write requests from the indexation, I first wrote a PoC to expose an exclusive lock in the medialib API. The UI took the exclusive lock for executing all its read requests within a single lock. This solved the performance issue.

However, an exclusive lock for solving this problem was not very suitable in theory:

  • if there was already read-requests running, taking an exclusive lock delayed the request (while the goal is to make it faster), often for no reason because requests for the UI are typically read-requests
  • an exclusive lock prevents several read-requests in parallel (useful for updating several parts of the UI loaded by background threads)
  • the implementation actually exposed the internal write lock, which had to be made recursive (and only the write-lock of the RW-lock was made recursive, the read-lock was not because it's more difficult/inefficient, which is a bit odd)
  • semantically, taking a write lock (exclusive lock) for read-requests, because its side-effects (prevent unwanted request interleaving) improve performance, sounds a bit hacky.

Priority access

To avoid these drawbacks, this MR implements a "priority access" instead. It is different from a lock in that it never blocks the caller but makes other (non-priority) clients wait. In bulk:

  • a client can acquire a priority access the same way it acquires locks (auto _ = ml->acquirePriorityAccess())
  • acquiring a priority access is always "immediate" (the caller will never "wait")
  • any number of clients can acquire a priority access simultaneously
  • when there is at least one client with priority access, all non-priority clients will block on lock_read() or lock_write() until all priority accesses are released
  • if other non-priority clients already acquired a read-lock or a write-lock when a client acquire a priority access, they can continue to execute their requests, following the traditional RW-lock rules
  • the priority clients may still be blocked on lock_read() and lock_write() by others (priority or non-priority) clients due to traditional RW-lock rules

In practice, indexation requests don't have priority access, so they are all blocked when a UI request, which will take the priority access, is started.

Like with the "exclusive lock" PoC, the list results is retrieved very quickly even when indexing is running.

Edited by Romain Vimont

Merge request reports