]> git.hungrycats.org Git - bees/commitdiff
task: flatten queues of dependent Tasks
authorZygo Blaxell <bees@furryterror.org>
Sun, 12 Jan 2025 18:54:54 +0000 (13:54 -0500)
committerZygo Blaxell <bees@furryterror.org>
Sun, 12 Jan 2025 19:05:44 +0000 (14:05 -0500)
Suppose Task A, B, and C are created in that order, and currently running.
Task T acquires Exclusion E.  Task B, A, and C attempt to acquire the
same Exclusion, in that order, but fail because Task T holds it.

The result is Task T with a post-exec queue:

        T, [ B, A, C ]  sort_requested

Now suppose Task U acquires Exclusion F, then Task T attempts to acquire
Exclusion F.  Task T fails to acquire F, so T is inserted into U's
post-exec queue.  The result at the end of the execution of T is a tree:

        U, [ T ]  sort_requested
             \-> [ B, A, C ] sort_requested

Task T exits after failing to acquire a lock.  When T exits, T will
sort its post-exec queue and submit the post-exec queue for execution
immediately:

        Worker 1: U, [ T ]  sort_requested
        Worker 2: A, B, C

This isn't ideal because T, A, B, and C all depend on at least one
common Exclusion, so they are likely to immediately conflict with T
when U exits and T runs again.

Ideally, A, B, and C would at least remain in a common queue with T,
and ideally that queue is sorted.

Instead of inserting T into U's post-exec queue, insert T and all
of T's post-exec queue, which creates a single flattened Task list:

        U, [ T, B, A, C ]   sort_requested

Then when U exits, it will sort [ T, B, A, C ] into [ A, B, C, T ],
and run all of the queued Tasks in age priority order:

        U exited, [ T, B, A, C ]   sort_requested

        U exited, [ A, B, C, T ]

        [ A, B, C, T ] on TaskConsumer queue

Signed-off-by: Zygo Blaxell <bees@furryterror.org>
lib/task.cc

index 6bbf165528f85b450c09afec0f7749a764e550c6..d0b58948cc41d694b5505d5d8e14c9776574e5c0 100644 (file)
@@ -331,8 +331,11 @@ namespace crucible {
                PairLock lock(m_mutex, task->m_mutex);
                if (!task->m_run_now) {
                        task->m_run_now = true;
+                       // Move the task and its post-exec queue to follow this task,
+                       // and request a sort of the flattened list.
                        m_sort_queue = true;
-                       append_nolock(task);
+                       m_post_exec_queue.push_back(task);
+                       m_post_exec_queue.splice(m_post_exec_queue.end(), task->m_post_exec_queue);
                }
        }