On 08 Sep 2014, at 7:50 AM, Nick Kew <n...@webthing.com> wrote: >> + /* No problems found, and we were we sent an empty brigade, >> and >> + * did this empty brigade not get passed on by a filter to >> the next >> + * filter in the chain? Compensate by passing the empty >> brigade to >> + * the next filter, so every filter gets a turn to write. >> This >> + * occurs during write completion. >> + */ > > You mean this code can only ever be entered during write completion?
In theory yes, but practically only when the brigade is empty and there is nothing to write. > Else how does this play with a filter that legitimately/necessarily > buffers everything - e.g. XSLT? Right now, that filter will carry on doing that. > Or a brigade containing a single metadata bucket and no data, > introduced by one filter as a signal to another? Then the brigade wouldn’t be empty. Basically what the code does is ensure that every filter in the chain gets called and therefore has an opportunity to write cached data, regardless of whether one filter has elected to not call apr_pass_brigade(). The filters are called in order, and no filters are missed. Ideally, filters should do this, but generally they don’t: /* Do nothing if asked to filter nothing. */ if (APR_BRIGADE_EMPTY(bb)) { return ap_pass_brigade(f->next, bb); } Some filters, like mod_deflate, do this: /* Do nothing if asked to filter nothing. */ if (APR_BRIGADE_EMPTY(bb)) { return APR_SUCCESS; } Others do the same thing by virtue of looping across the brigade bucket by bucket and then exiting - no buckets, we just have an exit. In these cases ap_pass_brigade() is never called, so we detect this by keeping a marker that is changed on every call to ap_pass_brigade(). If the marker wasn’t changed during the call to the filter, we compensate by calling each downstream filter until the marker is changed, or we run out of filters. One thing to think about is whether to to do this unconditionally - in other words send an empty brigade downstream when no downstream ap_pass_brigade() was detected regardless of whether the incoming brigade was empty or not. This covers the case where a buffering filter like the one you describe is reading in data from request N+1, while data in the core from request N is still being streamed over the network (and isn’t, because the core filter never gets called until buffering-filter is done). Request N isn’t delayed waiting for request N+1 to finish. To ensure that we don’t waste cycles we can do this when c->data_in_output_filters is non zero. We can also turn c->data_in_output_filters from a switch usable by the core filter only into a nested counter usable by any filter, so any filter can setaside buckets for any reason, and we’ll do the right thing. Patch attached. Regards, Graham —
httpd-async-fullstack2.patch
Description: Binary data