httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Graham Leggett <minf...@sharp.fm>
Subject Re: mod_proxy vs. serverpush
Date Thu, 05 Jan 2006 21:25:53 GMT
Ruediger Pluem wrote:

> The logic in mod_proxy_http.c of 2.2.x already tries to address this issue by
> flushing the data if no more data is available from the backend right now:
> 
>                 apr_read_type_e mode = APR_NONBLOCK_READ;
>                 int finish = FALSE;
> 
>                 do {
>                     apr_off_t readbytes;
>                     apr_status_t rv;
> 
>                     rv = ap_get_brigade(rp->input_filters, bb,
>                                         AP_MODE_READBYTES, mode,
>                                         conf->io_buffer_size);
> 
>                     /* ap_get_brigade will return success with an empty brigade
>                      * for a non-blocking read which would block: */
>                     if (APR_STATUS_IS_EAGAIN(rv)
>                         || (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb))) {
>                         /* flush to the client and switch to blocking mode */
>                         e = apr_bucket_flush_create(c->bucket_alloc);
>                         APR_BRIGADE_INSERT_TAIL(bb, e);
>                         if (ap_pass_brigade(r->output_filters, bb)
>                             || c->aborted) {
>                             backend->close = 1;
>                             break;
>                         }
>                         apr_brigade_cleanup(bb);
>                         mode = APR_BLOCK_READ;
>                         continue;
>                     }
>                     else if (rv == APR_EOF) {
>                         break;
>                     }
>                     else if (rv != APR_SUCCESS) {
>                         ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c,
>                                       "proxy: error reading response");
>                         break;
>                     }
>                     /* next time try a non-blocking read */
>                     mode = APR_NONBLOCK_READ;
> 
> 
> Anyway, it does not work as expected, as it seems that the condition
> (APR_STATUS_IS_EAGAIN(rv)
>                         || (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb))) {
> never gets true.

I think this if statement covers the case where a non blocking read is 
attempted, and zero bytes are returned, in which case another non 
blocking read might also return zero bytes, causing the loop to spin at 
100% processor usage.

The problem lies in the code further down:

                     /* try send what we read */
                     if (ap_pass_brigade(r->output_filters, bb) != 
APR_SUCCESS
                         || c->aborted) {
                         /* Ack! Phbtt! Die! User aborted! */
                         backend->close = 1;  /* this causes socket 
close below *
/
                         finish = TRUE;
                     }

Without explicitly adding flush buckets to the output filter stack, the 
output filter stack seems to buffer before sending (rational behaviour).

To change this, we would need to add an output flush bucket after each read.

Is this a rational thing to do in the general case? Or should the 
addition of the flush be configurable?

Regards,
Graham
--

Mime
View raw message