PERF: index scheduler tasks instead of linearly scanning them for every context snapshot #168

Open
opened 2026-09-09 15:05:20 +00:00 by nsaspy · 0 comments
Owner

Finding

The state-snapshot roster loop calls scheduler.get_task_by_uuid(ctx.id) once for every live context. TaskScheduler delegates to a task collection whose implementation is:

return next((task for task in self.tasks if task.uuid == task_uuid), None)

For task contexts, snapshot construction then calls scheduler.serialize_task(ctx.id), which resolves the task again before serializing it.

The global state path is therefore O(number_of_contexts × number_of_tasks) for classification alone, on top of the other full-roster costs tracked in #19/#20. get_task_by_name has the same linear lookup pattern for other callers.

Direction

Maintain task indexes under the scheduler's existing lock:

  • UUID -> task
  • name -> task where uniqueness semantics permit
  • context_id -> task if context/task mapping is distinct from UUID

Update indexes transactionally on load/create/update/rename/remove/reload rather than rebuilding in read paths. Snapshot code should iterate/lookup materialized task metadata once.

Acceptance

  • UUID lookup is O(1) expected time and does not scan self.tasks.
  • Context-to-task classification in state snapshot is O(contexts + tasks), not O(contexts × tasks).
  • Task serialization does not perform a second redundant linear lookup after classification.
  • Rename/update/remove/reload keep indexes and ordered task storage consistent under concurrency.
  • Duplicate-name behavior is explicitly defined/tested if a name index is added.
  • Benchmarks cover 1k contexts × 1k tasks and demonstrate bounded lookup time.
  • Coordinate with #19 so roster serialization itself is not done on every log push.

Mirrored from lost-rob0t/a0-symbolics#30 via tracker sync.

## Finding The state-snapshot roster loop calls `scheduler.get_task_by_uuid(ctx.id)` once for every live context. `TaskScheduler` delegates to a task collection whose implementation is: ```python return next((task for task in self.tasks if task.uuid == task_uuid), None) ``` For task contexts, snapshot construction then calls `scheduler.serialize_task(ctx.id)`, which resolves the task again before serializing it. The global state path is therefore O(number_of_contexts × number_of_tasks) for classification alone, on top of the other full-roster costs tracked in #19/#20. `get_task_by_name` has the same linear lookup pattern for other callers. ## Direction Maintain task indexes under the scheduler's existing lock: - UUID -> task - name -> task where uniqueness semantics permit - context_id -> task if context/task mapping is distinct from UUID Update indexes transactionally on load/create/update/rename/remove/reload rather than rebuilding in read paths. Snapshot code should iterate/lookup materialized task metadata once. ## Acceptance - [ ] UUID lookup is O(1) expected time and does not scan `self.tasks`. - [ ] Context-to-task classification in state snapshot is O(contexts + tasks), not O(contexts × tasks). - [ ] Task serialization does not perform a second redundant linear lookup after classification. - [ ] Rename/update/remove/reload keep indexes and ordered task storage consistent under concurrency. - [ ] Duplicate-name behavior is explicitly defined/tested if a name index is added. - [ ] Benchmarks cover 1k contexts × 1k tasks and demonstrate bounded lookup time. - [ ] Coordinate with #19 so roster serialization itself is not done on every log push. --- *Mirrored from [`lost-rob0t/a0-symbolics#30`](https://github.com/lost-rob0t/a0-symbolics/issues/30)* via tracker sync.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
nsaspy/a0-symbolics#168
No description provided.