Looking at the pattern of calls to ap_core_output_filter() in the event MPM, it occurred to me that it may be straightforward to hand off the writing of the request to an async completion thread in a lot of useful real-world cases.

In function check_pipeline_flush() in http_request.c, a flush bucket is passed to the output filter stack if there's no pipelined request ready to be read (or if keep-alives aren't enabled for the connection). When this occurs, two things
are true:
  * One or more complete responses--and no partial responses--have been
    sent to the output filter stack for this connection.
* If these responses have not been sent to the client, they will now be sent in their entirety before the httpd attempts to do any further reads from this
    connection.

Instead of sending a flush bucket to the output filter stack in this scenario,
though, perhaps we could send a new metadata bucket that denotes "end
of output until everything currently in the pipeline has been written." Upon receiving this bucket, core_output_filter would register the connection with
a pollset to watch for writability.

A write completion thread would poll in an endless loop, writing data from each set-aside brigade whenever its corresponding connection became writable. Upon sending the last bucket of a set-aside brigade to the network, the completion
thread would put the connection in either CONN_STATE_LINGER or
CONN_STATE_CHECK_REQUEST_LINE_READABLE state (depending on
whether keepalives were enabled) and re-register the connection with the
event MPM's main pollset to wait for readability or timeout.

The pollset used to wait for writability could be the same pollset that's currently used to watch for readability and timeouts. Similarly, the write completion
thread could be combined with the current listener thread.

I'm eager to hear some feedback on this idea:
* Will it work?  Or am I overlooking some design flaw?
* Will it help?  I.e., will it make a noticeable improvement in the
  connections-to-threads ratio?
* What about the access logger?  If the writing of responses were
  completed asynchronously, a request could be logged before its
  response was sent--or, worse yet, before the sending of its
  response failed due to, say, the client closing the connection early.
  One solution that comes to mind is to have the write completion
  thread invoke the access logger--perhaps triggered by a metadata
  bucket in the output brigade.

-Brian

Reply via email to