httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Graham Leggett <minf...@sharp.fm>
Subject Re: [Patch] Async write completion for the full connection filter stack
Date Mon, 08 Sep 2014 15:25:56 GMT
On 08 Sep 2014, at 7:50 AM, Nick Kew <nick@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
—

Mime
View raw message