httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Roy T. Fielding" <field...@kiwi.ICS.UCI.EDU>
Subject Re: Filtering STATUS report :-)
Date Tue, 15 Aug 2000 01:56:54 GMT
>>There shouldn't be a bucket write function.  Any caller that writes to
>>memory must fully understand the management of that memory, so it needs
>>to be un-bucketed first before it can be written to.  That means conversion
>>by copying to a caller-provided buffer or by ap_give_me_a_safe_heap(bucket).
>>Writing directly within the bucket adds a great deal of complication
>>when compared to treating the bucket data as always read-only.  Whether
>>or not a buffer can be written to is as much a function of how it is
>>being shared by other threads within the program as it is where the
>>memory was allocated from.
>
>Ryan maintains that it's a useful optimisation in some restricted
>situations to be able to append directly to a HEAP bucket (e.g. when
>it's the last in the brigade and the request handler is doing a bunch
>of ap_rprintf()s) but I agree that providing it as a supposedly
>general-purpose bucket function is liable to cause trouble.

It is only a useful optimization if the benefit of having it outweighs
the cost of the special-case code needed to use it.  The problem is that
it seduces the filters into special code paths.  Whether it pays off
or not will depend on how much self-writing filter action takes place
in sequence, and I don't think that will happen very often.

In other words, in order for this write function to be useful, the data
must be copied (or translated) at least twice, since the initial copy
won't be in writable heap, and this must happen often enough that it
offsets the extra code to check for it and manage writable bucket data
separately from read-only bucket data.  Since the goal of bucket brigades
is to be zero-copy whenever possible, two-copy situations just don't occur
often enough to be worth the extra code.

>>The setaside function must be provided a buffer (by the caller) to
>>write into and must return some form of status.  Setting aside to the
>>heap won't work for the general case, and is bad practice in any case.
>
>Why? I'd like to know the background to this assertion. At least we
>know that the memory on the heap will be around long enough -- either
>until the next trip down through the filters (e.g. setting aside a
>partial SSI tag), or until the next request provides enough data to
>make it worth doing a write to the network (the request pool is too
>short-lived).

Because it is inefficient and dangerous to allocate from the heap
in a fashion that is linear to the amount of data in the response,
even if the allocation is pool-based.  For example, BUFF stores a
fixed-size buffer (allocated upon creation) which is incrementally
filled until it reaches a certain size (or we get a large write),
at which point we write it all out.  The same buffer is then used
again for the next series of incremental writes.  In order to do the
same within a filter, the filter must be able to allocate a block
of memory on creation and have the setaside function write to a
specific offset of that memory in a bucket-type-specific way.

If allocating from the heap or a pool is sufficient, then the filter
is perfectly capable of doing that itself prior to calling setaside.

Something I didn't mention before is that it is just as broken for a
server to buffer too much data as it is for the server to send out lots
of small packets.  User-perceived latency is the primary performance
metric for Web applications, which means that we should start writing
as soon as we get a reasonable amount of data to write.  A filter will
have to determine what is reasonable, based on its own semantics.

In Onions, I had two brigade buffers in each stream object (filter) -- one
for processed data yet-to-be-written and another for unprocessed data
yet-to-be-filtered.  The current code only defines one brigade buffer.
Some filters only need one buffer, and others don't need any (relying
only on state variables).  That's why filters should have a void pointer
for all state data that is filter-specific.

....Roy

Mime
View raw message