|
5 | 5 | Inside the File engine |
6 | 6 | ###################### |
7 | 7 |
|
| 8 | +One of the important characteristics of the **File engine** is that publishers and subscribers can interact with the |
| 9 | +DTL in a completely **desynchronized** way. Publishers can write down Variables into files, close the engine, and even |
| 10 | +disconnect themselves from the DTL before subscribers start to read the Variable from these files. However, when |
| 11 | +subscribers aim to retrieve Variables from the DTL while the publishers are exporting them, they must wait for the data |
| 12 | +to be fully written on storage (or more precisely for the simulation of the corresponding I/O operations to be over) |
| 13 | +before being able to read it. These two situations implies the implementation of additional checks related to which |
| 14 | +actors (i.e., publishers and/or subscribers) are currently using the File engine and of internal synchronization |
| 15 | +mechanisms. |
| 16 | + |
| 17 | +On the publisher side |
| 18 | +--------------------- |
| 19 | + |
| 20 | +The first publisher to call to :cpp:func:`begin_transaction` marks that a new :ref:`Concept_Transaction` is in progress |
| 21 | +and increments an internal transaction counter. Then, from the second transaction using that File engine only, the |
| 22 | +publishers check whether the previous transaction is over. To this end, the publishers are blocked on a **condition |
| 23 | +variable**, until all the **write activities** from that transaction are completed. Once the publishers are unblocked, |
| 24 | +they proceed with the current transaction, i.e., handling the calls to :cpp:func:`put` made in the simulator's code. |
| 25 | + |
| 26 | +These calls to :cpp:func:`put` are delegated by the :ref:`Concept_Engine` to the selected :ref:`Concept_Transport`. For |
| 27 | +each call to :cpp:func:`put`, a publisher simply determines, based on the part of the :ref:`Concept_Variable` it |
| 28 | +locally owns and the **selection** made by the user, how many bytes it has to write and in which file (determined by |
| 29 | +the name of the :ref:`Concept_Stream`) to write them. With the **default File transport method**, each publisher |
| 30 | +creates and writes to a file called ``data.i``, where ``i`` is the unique index of the publisher. |
| 31 | + |
| 32 | +The most important call is thus that to :cpp:func:`end_transaction` where the I/O activities are created and started. |
| 33 | +In this function, each publisher goes over all the write operation it registered during the different calls to the |
| 34 | +:cpp:func:`put` functions made in this transaction, and creates the corresponding simulated I/O activities by calling |
| 35 | +the ``File::write_async()`` function of the |
| 36 | +`FSMod file system module <https://github.com/simgrid/file-system-module>`_. These calls are made in **detached** mode, |
| 37 | +meaning that the publisher starts an **asynchronous write**, can forget about it, and proceeds with the next Variable. |
| 38 | +DTLMod also leverages the **signal/callback** mechanism provided by SimGrid to attach a callback triggered on the |
| 39 | +completion of a given asynchronous write activity. This callback does two things: 1) Notify all the actors waiting for |
| 40 | +the completion of that activity that it is now completed; and 2) Remove this activity from the list of **pending |
| 41 | +activities** maintained by the publisher that created it. |
| 42 | + |
| 43 | +The last action performed in :cpp:func:`end_transaction` is only done by the **last publisher** to call the function. |
| 44 | +This actor marks the :ref:`Concept_Transaction` as over, increments an internal counter of completed transactions, and |
| 45 | +most importantly, notifies subscribers to that Stream that this transaction is complete. Note that the fact that a |
| 46 | +transaction is complete and the subscribers are notified does not mean that the corresponding I/O actictivites (i.e., |
| 47 | +writing into files) are complete and that the subscribers can start reading the files to get Variables. However, it |
| 48 | +means that the publishers have all the publishers have determined what and where to write and that the subscribers are |
| 49 | +allowed to use this information to create their I/O activities (i.e., reading from files) as explained in the |
| 50 | +:ref:`File_sub_side` section. |
| 51 | + |
| 52 | +To determine which publisher is the last to call the :cpp:func:`end_transaction` function, DTLMod relies on a |
| 53 | +synchronization barrier for all the publishers using this Engine. This barrier is created in the very first to |
| 54 | +:cpp:func:`end_transaction`. |
| 55 | + |
| 56 | +The last operation performed on the publisher side of a File Engine is to **close** the engine by calling the |
| 57 | +:cpp:func:`close` function. The publishers first have to wait for the completion of the I/O activities strated by the |
| 58 | +last transaction performed on this engine, i.e., they are blocked on a condition variable and wait to be notified of |
| 59 | +the respective completion of these activities. Then the last publisher to call the :cpp:func:`close` function actually |
| 60 | +closes the Engine, as well as all the opened files on the simulated file system. Finally, if the |
| 61 | +:cpp:func:`set_metadata_export` function has been called for the :ref:`Concept_Stream` that created the Engine, this |
| 62 | +publisher export a summary of all the I/O operations performed during the lifetime of the Engine. |
| 63 | + |
| 64 | +.. _File_sub_side: |
| 65 | + |
| 66 | +On the subscriber side |
| 67 | +---------------------- |
| 68 | + |
8 | 69 | TBD |
0 commit comments