-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Lambda Scheme
This is article on new scheme of database access.
There are lots of objects which need to use database access. Most of
that type of access is provided by respective *DAO
(DAO
means data
access object) objects. Instances of each *DAO
object consist in
TrackCollection
class. TrackCollection
holds also database
connection and populates it on all DAO
s.
In Mixxx 1.11 if you want to conduct database access you must:
- Get pointer to respective DAO
- Prepare query and data
- Apply query from the point where you are right now
- Populate query results (if it's necessary)
The main problem of such scheme is conducting the db access mostly from the Main thread. That's why while query's pending we face UI locking.
The main requirement is avoid hanging of UI (or minimize hanging up to 16 ms, but not more).
There are lots of inherited complexity in the db usage:
- Threads are evil =)
- The db connection cannot be populated on different threads
- We must have just one access point to db in perfect case
We propose new scheme of the db accessing. This scheme requires usage of lambdas which was presented in new C++11.
We are going to leave all DAO
class hierarchy and leave behaviour
mostly the same, except one important moment -- conduct all database
access in separate thread.
Object TrackCollection
becomes our separate thread. It is creating in
Library
, also connects to database, holds this connection, initializes
all DAO
objects and begins its own event loop (while
in run()
method).
We got into cycle body every time someone places lambda to queue by
callin callAsync()
. Here we dequeue lambda and execute it (in
TrackCollection
s thread).
What do I need to do with some code to apply new scheme?
- Get pointer to
TrackCollection
s thread - Surround your code by respective call of
callAsync
where the first parameter will be lambda with its cathes values (most common -- this).
It guarantees your code will be placed into queue and executed as soon
as possible in TrackCollection
s thread. Must admit that this is
asynchronous function. It means that all operations on placing
lambda into queue happen in less than 16 ms and execution from your
context goes on. We can't say exactly when lambda will be executed (as
soon as it is placed to queue and becomes at the top of queue).
See Rules and arrangements using lambdas scheme for database access
If you can't move on until code in lambda executes. For example, when you need results of some query in initialization of your class. So you may use some kind of "callSync" -- do it with locks. The algorithm is quite easy:
- In your context create (even in stack)
QMutex mutex
- Do
mutex.lock()
- Do as usual you do with
callAsync()
, but with little correction in lambda: add&mutex
to lambdas catchlist; addmutex.unlock()
at the end of your lambda code (it must be surrounded by lambda) - After
callSync
code domutex.lock()
and imidiatelymutex.unlock()
Completing this instruction, we do as it was previously, but with pause of further execution until respective lambda will be executed and respective mutex will be unlocked. Beware your lambda must wait whole queue.
Other way to implement such behaviour is to emit signals like for accessing UI.
There is the upper bound for lambda queue (MAX_LAMBDA_COUNT
). Someone
someday could wait in callAsync
if there is no empty positions in
lambdas queue.
Mixxx is a free and open-source DJ software.
Manual
Hardware Compatibility
Reporting Bugs
Getting Involved
Contribution Guidelines
Coding Guidelines
Using Git
Developer Guide
Creating Skins
Contributing Mappings
Mixxx Controls
MIDI Scripting
Components JS
HID Scripting