After the Scheduler split the jobs of System execution and created a schedule, System Executive is responsible for allocating Execution Contexts, dispatching the jobs to threads, perform synchronizations between dependent jobs, and manage the access to the Entity Database.
Control Flow
The Systems and their execution are designed around the manipulation of Entities. Each System sees the merged version of Entity Database passed from its direct ancestors on the reduced task graph. In order to finely control the dataflow, the logics in a System are divided into the following parts:
- Component Access Permissions
- Read/Write masks of Components.
EntityFilter
- The filter that decides the range of Entities seen by this System.
struct Context
- Variables used during the execution.
prepare(Database &, Services &, Context &)
- Initialize the Execution Context. If the System is not implemented based on iterating a range of Entities, this function could be the place to request Services and manipulate the Entity Database.
update(Entity &, EntityInserter &)
- Manipulates the filtered entities. New Entities can be created via the provided inserter. Those new Entities will be merged by the Executive after all subjobs of this System finish.
This opens some opportunities for optimization. For example, if two consecutive Systems operate on the same set of Entities, their update()
functions can be merged so that only one full iteration of the Entity Page List is necessary. If this could be implemented, we can encourage the use of tiny Systems enclosing simple logic then chain them together to form complex logic. Thus our design moves from procedural towards a more declarative way.
Execution Context
Each System can declare a struct
Data Stash
When a new Entity Page is created during the execution of a System, the new page is not immediately inserted at the main Entity Database instance, because there could be other Systems accessing the database simultaneously. Instead, the new pages are linked into an array of linked lists managed by the Executor for each System, we call each linked list the Data Stash for a System, stealing the similar concept from Git. Similarly, when a System is iterating the Entity Pages, it does not only visit those in the Entity Database, but also those pages inserted by the preceding Systems stored in the Data Stashes. We refer to the Entity Pages already committed to the Entity Database as the Trunk Entity Page List. After all the Systems finished their executions, the Data Stashes are merged into the Entity Database by simply resetting the next pointers in the linked list of the Entity Pages.
This design involves two changes regarding the interface to the Entity Database. The page insertion into the database is now delegated to the Executor and deferred to the end of System executions instead of performed at the occasion whenever a new page is requested. Therefore, the Entity Database must expose access to the page allocator directly to the Executor. Another change is the page iterators obtained from the Entity Database is now wrapped in an adapter linking the Data Stashes together with the Trunk Entity Page List.