| 2014/10/30 - dynamic buffer management |
| |
| Since HTTP/2 processing will significantly increase the need for buffering, it |
| becomes mandatory to be able to support dynamic buffer allocation. This also |
| means that at any moment some buffer allocation will fail and that a task or an |
| I/O operation will have to be paused for the time needed to allocate a buffer. |
| |
| There are 3 places where buffers are needed : |
| |
| - receive side of a stream interface. A connection notifies about a pending |
| recv() and the SI calls the receive function to put the data into a buffer. |
| Here the buffer will have to be picked from a pool first, and if the |
| allocation fails, the I/O will have to temporarily be disabled, the |
| connection will have to subscribe for buffer release notification to be |
| woken up once a buffer is available again. It's important to keep in mind |
| that buffer availability doesn't necessarily mean a desire to enable recv |
| again, just that recv is not paused anymore for resource reasons. |
| |
| - receive side of a stream interface when the other end point is an applet. |
| The applet wants to write into the buffer and for this the buffer needs to |
| be allocated as well. It is the same as above except that it is the applet |
| which is put to a pause. Since the applet might be at the core of the task |
| itself, it could become tricky to handle the situation correctly. Stats and |
| peers are in this situation. |
| |
| - Tx of a task : some tasks perform spontaneous writes to a buffer. Checks |
| are an example of this. The checks will have to be able to sleep while a |
| buffer is being awaited. |
| |
| One important point is that such pauses must not prevent the task from timing |
| out. There it becomes difficult because in the case of a time out, we could |
| want to emit a timeout error message and for this, require a buffer. So it is |
| important to keep the ability not to send messages upon error processing, and |
| to be able to give up and stop waiting for buffers. |
| |
| The refill mechanism needs to be designed in a thread-safe way because this |
| will become one of the rare cases of inter-task activity. Thus it is important |
| to ensure that checking the state of the task and passing of the freshly |
| released buffer are performed atomically, and that in case the task doesn't |
| want it anymore, it is responsible for passing it to the next one. |
| |