From: Brian Pane Date: Tue, 27 Nov 2001 08:39:02 +0000 (+0000) Subject: Another performance-related change to core_output_filter(): if we X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=98505996b562be6aeed48b78dfe7b567cec0ef61;p=apache Another performance-related change to core_output_filter(): if we get a long stream of small buckets, so that multiple concatenation steps are required in a single pass through the brigade, re-use the buckets from the previous temp brigade when creating the next one. This allows us to avoid making yet another copy of the previously concatenated data. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@92197 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/server/core.c b/server/core.c index af47d7e0c0..ff27728b9f 100644 --- a/server/core.c +++ b/server/core.c @@ -3042,6 +3042,11 @@ static apr_status_t core_output_filter(ap_filter_t *f, apr_bucket_brigade *b) apr_size_t flen = 0; apr_off_t foffset = 0; + /* keep track of buckets that we've concatenated + * to avoid small writes + */ + apr_bucket *last_merged_bucket = NULL; + /* Iterate over the brigade: collect iovecs and/or a file */ APR_BRIGADE_FOREACH(e, b) { /* keep track of the last bucket processed */ @@ -3088,36 +3093,78 @@ static apr_status_t core_output_filter(ap_filter_t *f, apr_bucket_brigade *b) more = apr_brigade_split(b, e); break; } - temp_brig = apr_brigade_create(f->c->pool); + + /* Create a temporary brigade as a means + * of concatenating a bunch of buckets together + */ + if (last_merged_bucket) { + /* If we've concatenated together small + * buckets already in a previous pass, + * the initial buckets in this brigade + * are heap buckets that may have extra + * space left in them (because they + * were created by apr_brigade_write()). + * We can take advantage of this by + * building the new temp brigade out of + * these buckets, so that the content + * in them doesn't have to be copied again. + */ + apr_bucket_brigade *bb; + bb = apr_brigade_split(b, + APR_BUCKET_NEXT(last_merged_bucket)); + temp_brig = b; + b = bb; + } + else { + temp_brig = apr_brigade_create(f->c->pool); + } temp = APR_BRIGADE_FIRST(b); while (temp != e) { apr_bucket *d; rv = apr_bucket_read(temp, &str, &n, APR_BLOCK_READ); - nbytes -= n; apr_brigade_write(temp_brig, NULL, NULL, str, n); d = temp; temp = APR_BUCKET_NEXT(temp); apr_bucket_delete(d); } + nvec = 0; + nbytes = 0; temp = APR_BRIGADE_FIRST(temp_brig); APR_BUCKET_REMOVE(temp); APR_BRIGADE_INSERT_HEAD(b, temp); - e = temp; - last_e = e; + apr_bucket_read(temp, &str, &n, APR_BLOCK_READ); + vec[nvec].iov_base = (char*) str; + vec[nvec].iov_len = n; + nvec++; + + /* Just in case the temporary brigade has + * multiple buckets, recover the rest of + * them and put them in the brigade that + * we're sending. + */ for (next = APR_BRIGADE_FIRST(temp_brig); next != APR_BRIGADE_SENTINEL(temp_brig); next = APR_BRIGADE_FIRST(temp_brig)) { APR_BUCKET_REMOVE(next); APR_BUCKET_INSERT_AFTER(temp, next); temp = next; + apr_bucket_read(next, &str, &n, + APR_BLOCK_READ); + vec[nvec].iov_base = (char*) str; + vec[nvec].iov_len = n; + nvec++; } apr_brigade_destroy(temp_brig); - nvec = 0; - apr_bucket_read(e, &str, &n, APR_BLOCK_READ); + + last_merged_bucket = temp; + e = temp; + last_e = e; + } + else { + vec[nvec].iov_base = (char*) str; + vec[nvec].iov_len = n; + nvec++; } - vec[nvec].iov_base = (char*) str; - vec[nvec].iov_len = n; - nvec++; } else { /* The bucket is a trailer to a file bucket */