Browse Source

[core] improve handling of suboptimal backend wr

more efficiently handle reading of suboptimal backend write behavior

check to accumulate small reads in mem before flushing to temp file
master
Glenn Strauss 10 months ago
parent
commit
39a577985f
  1. 63
      src/http-header-glue.c
  2. 7
      src/response.h

63
src/http-header-glue.c

@ -702,10 +702,17 @@ void http_response_upgrade_read_body_unknown(request_st * const r) {
}
static int http_response_append_buffer(request_st * const r, buffer * const mem) {
__attribute_pure__
static int http_response_append_buffer_simple_accum(const request_st * const r, const off_t len) {
/*(check to accumulate small reads in buffer before flushing to temp file)*/
return
len < 32768 && r->write_queue.last && r->write_queue.last->file.is_temp;
}
static int http_response_append_buffer(request_st * const r, buffer * const mem, const int simple_accum) {
/* Note: this routine is separate from http_response_append_mem() to
* potentially avoid copying in http_chunk_append_buffer(). Otherwise this
* would be: return http_response_append_mem(r, BUF_PTR_LEN(mem)); */
* potentially avoid copying buffer by using http_chunk_append_buffer(). */
if (r->resp_decode_chunked)
return http_chunk_decode_append_buffer(r, mem);
@ -713,7 +720,14 @@ static int http_response_append_buffer(request_st * const r, buffer * const mem)
if (r->resp_body_scratchpad > 0) {
off_t len = (off_t)buffer_clen(mem);
r->resp_body_scratchpad -= len;
if (r->resp_body_scratchpad <= 0) {
if (r->resp_body_scratchpad > 0) {
if (simple_accum
&& http_response_append_buffer_simple_accum(r, len)) {
r->resp_body_scratchpad += len;
return 0; /*(accumulate small reads in buffer)*/
}
}
else { /* (r->resp_body_scratchpad <= 0) */
r->resp_body_finished = 1;
if (r->resp_body_scratchpad < 0) {
/*(silently truncate if data exceeds Content-Length)*/
@ -727,6 +741,10 @@ static int http_response_append_buffer(request_st * const r, buffer * const mem)
/*(silently truncate if data exceeds Content-Length)*/
return 0;
}
else if (simple_accum
&& http_response_append_buffer_simple_accum(r, buffer_clen(mem))) {
return 0; /*(accumulate small reads in buffer)*/
}
return http_chunk_append_buffer(r, mem);
}
@ -1212,6 +1230,15 @@ handler_t http_response_read(request_st * const r, http_response_opts * const op
handler_t rc = opts->parse(r, opts, b, (size_t)n);
if (rc != HANDLER_GO_ON) return rc;
} else if (0 == n) {
if (!buffer_is_blank(b) && opts->simple_accum) {
/*(flush small reads previously accumulated in b)*/
int rc = http_response_append_buffer(r, b, 0); /*(0 to flush)*/
if (__builtin_expect( (0 != rc), 0)) {
/* error writing to tempfile;
* truncate response or send 500 if nothing sent yet */
return HANDLER_ERROR;
}
}
/* note: no further data is sent to backend after read EOF on socket
* (not checking for half-closed TCP socket)
* (backend should read all data desired prior to closing socket,
@ -1221,16 +1248,38 @@ handler_t http_response_read(request_st * const r, http_response_opts * const op
/* split header from body */
handler_t rc = http_response_parse_headers(r, opts, b);
if (rc != HANDLER_GO_ON) return rc;
/* accumulate response in b until headers completed (or error) */
if (r->resp_body_started) buffer_clear(b);
/* accumulate response in b until headers completed (or error)*/
if (r->resp_body_started) {
buffer_clear(b);
/* enable simple accumulation of small reads in some situations
* no Content-Length (will read to EOF)
* Content-Length (will read until r->resp_body_scratchpad == 0)
* not chunked-encoding
* not bufmin streaming
* (no custom parse routine set for opts->parse()) */
if (!r->resp_decode_chunked /* && NULL == opts->parse */
&& !(r->conf.stream_response_body
& FDEVENT_STREAM_RESPONSE_BUFMIN))
opts->simple_accum = 1;
}
} else {
int rc = http_response_append_buffer(r, b);
/* flush b (do not accumulate small reads) if streaming and might
* write to client since there is a chance that r->write_queue is
* fully written to client (no more temp files) and then we do not
* want to hold onto buffered data in b for an indeterminate time
* until next read of data from backend */
int simple_accum = opts->simple_accum
&& (!(r->conf.stream_response_body
& FDEVENT_STREAM_RESPONSE)
|| !r->con->is_writable);
int rc = http_response_append_buffer(r, b, simple_accum);
if (__builtin_expect( (0 != rc), 0)) {
/* error writing to tempfile;
* truncate response or send 500 if nothing sent yet */
return HANDLER_ERROR;
}
/*buffer_clear(b);*//*http_response_append_buffer() clears*/
/* small reads might accumulate in b; not necessarily cleared */
}
if (r->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN) {

7
src/response.h

@ -23,9 +23,10 @@ enum {
typedef struct http_response_opts_t {
int fdfmt;
int backend;
int authorizer;
unsigned short local_redir;
unsigned short xsendfile_allow;
int authorizer; /* bool */
uint8_t simple_accum; /* bool */
uint8_t local_redir; /* 0,1,2 */
uint8_t xsendfile_allow; /* bool */
const array *xsendfile_docroot;
void *pdata;
handler_t(*parse)(request_st *, struct http_response_opts_t *, buffer *, size_t);

Loading…
Cancel
Save