diff options
author | Yann Ylavic <ylavic@apache.org> | 2018-10-24 15:06:04 +0000 |
---|---|---|
committer | Yann Ylavic <ylavic@apache.org> | 2018-10-24 15:06:04 +0000 |
commit | cd5255cd29980e1efa74112c21e57c446f91f4e5 (patch) | |
tree | a2a4e2ca3cdcee70bd77ebd064507df886b6bb3b /server/request.c | |
parent | a84b6923e79a74cf843eb00f1e4852dd9c5f495c (diff) | |
download | httpd-cd5255cd29980e1efa74112c21e57c446f91f4e5.tar.gz |
request: forward as much buckets as possible in ap_request_core_filter().
This improves performances while still preventing morphing buckets bound to
r->pool from reaching connection filters.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1844780 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'server/request.c')
-rw-r--r-- | server/request.c | 61 |
1 files changed, 49 insertions, 12 deletions
diff --git a/server/request.c b/server/request.c index b3c9ba8e25..70812fed59 100644 --- a/server/request.c +++ b/server/request.c @@ -2066,9 +2066,13 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_sub_req_output_filter(ap_filter_t *f, AP_CORE_DECLARE_NONSTD(apr_status_t) ap_request_core_filter(ap_filter_t *f, apr_bucket_brigade *bb) { - apr_bucket *flush_upto = NULL; apr_status_t status = APR_SUCCESS; + apr_read_type_e block = APR_NONBLOCK_READ; + conn_rec *c = f->r->connection; + apr_bucket *flush_upto = NULL; apr_bucket_brigade *tmp_bb; + apr_size_t tmp_bb_len = 0; + core_server_config *conf; int seen_eor = 0; /* @@ -2080,6 +2084,8 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_request_core_filter(ap_filter_t *f, return ap_pass_brigade(f->next, bb); } + conf = ap_get_core_module_config(f->r->server->module_config); + /* Reinstate any buffered content */ ap_filter_reinstate_brigade(f, bb, &flush_upto); @@ -2092,6 +2098,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_request_core_filter(ap_filter_t *f, /* Don't touch *bb after seen_eor */ while (status == APR_SUCCESS && !seen_eor && !APR_BRIGADE_EMPTY(bb)) { apr_bucket *bucket = APR_BRIGADE_FIRST(bb); + int do_pass = 0; if (AP_BUCKET_IS_EOR(bucket)) { /* pass out everything and never come back again, @@ -2116,31 +2123,61 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_request_core_filter(ap_filter_t *f, * something safe to pass down to the connection filters without * needing to be set aside. */ - if (!APR_BUCKET_IS_METADATA(bucket) - && bucket->length == (apr_size_t)-1) { + if (bucket->length == (apr_size_t)-1) { const char *data; apr_size_t size; - status = apr_bucket_read(bucket, &data, &size, APR_BLOCK_READ); + + status = apr_bucket_read(bucket, &data, &size, block); if (status != APR_SUCCESS) { - break; + if (!APR_STATUS_IS_EAGAIN(status) + || block != APR_NONBLOCK_READ) { + break; + } + /* Flush everything so far and retry in blocking mode */ + bucket = apr_bucket_flush_create(c->bucket_alloc); + block = APR_BLOCK_READ; + } + else { + tmp_bb_len += size; + block = APR_NONBLOCK_READ; } } + else { + tmp_bb_len += bucket->length; + } - /* pass each bucket down the chain */ + /* move the bucket to tmp_bb and check whether it exhausts bb or + * brings tmp_bb above the limit; in both cases it's time to pass + * everything down the chain. + */ APR_BUCKET_REMOVE(bucket); APR_BRIGADE_INSERT_TAIL(tmp_bb, bucket); + if (APR_BRIGADE_EMPTY(bb) + || APR_BUCKET_IS_FLUSH(bucket) + || tmp_bb_len >= conf->flush_max_threshold) { + do_pass = 1; + } } - status = ap_pass_brigade(f->next, tmp_bb); - apr_brigade_cleanup(tmp_bb); + if (do_pass || seen_eor) { + status = ap_pass_brigade(f->next, tmp_bb); + apr_brigade_cleanup(tmp_bb); + tmp_bb_len = 0; + } } - ap_release_brigade(f->c, tmp_bb); - /* Don't touch *bb after seen_eor */ - if (status == APR_SUCCESS && !seen_eor) { - status = ap_filter_setaside_brigade(f, bb); + if (!seen_eor) { + apr_status_t rv; + APR_BRIGADE_PREPEND(bb, tmp_bb); + rv = ap_filter_setaside_brigade(f, bb); + if (status == APR_SUCCESS) { + status = rv; + } } + + ap_release_brigade(f->c, tmp_bb); + return status; } |