summaryrefslogtreecommitdiffstats
path: root/modules/http2
diff options
context:
space:
mode:
authorStefan Eissing <icing@apache.org>2016-04-15 16:56:11 +0200
committerStefan Eissing <icing@apache.org>2016-04-15 16:56:11 +0200
commit90005fa61a3522a625f9a6b243e5797296132597 (patch)
tree82404a4e4af33576383c31227039b88c7c95c283 /modules/http2
parentmod_http2: new bucket beams for tranporting buckets across threads without bu... (diff)
downloadapache2-90005fa61a3522a625f9a6b243e5797296132597.tar.xz
apache2-90005fa61a3522a625f9a6b243e5797296132597.zip
mod_http2: delaying response start until flush or data accumulation
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1739312 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/http2')
-rw-r--r--modules/http2/h2_bucket_beam.c24
-rw-r--r--modules/http2/h2_bucket_beam.h5
-rw-r--r--modules/http2/h2_proxy_session.c8
-rw-r--r--modules/http2/h2_task.c48
4 files changed, 68 insertions, 17 deletions
diff --git a/modules/http2/h2_bucket_beam.c b/modules/http2/h2_bucket_beam.c
index 5406176fad..fee6c7bc87 100644
--- a/modules/http2/h2_bucket_beam.c
+++ b/modules/http2/h2_bucket_beam.c
@@ -803,6 +803,30 @@ apr_off_t h2_beam_get_buffered(h2_bucket_beam *beam)
return l;
}
+apr_off_t h2_beam_get_mem_used(h2_bucket_beam *beam)
+{
+ apr_thread_mutex_t *lock;
+ apr_bucket *b;
+ apr_off_t l = 0;
+ int acquired;
+
+ if (enter_yellow(beam, &lock, &acquired) == APR_SUCCESS) {
+ for (b = H2_BLIST_FIRST(&beam->red);
+ b != H2_BLIST_SENTINEL(&beam->red);
+ b = APR_BUCKET_NEXT(b)) {
+ if (APR_BUCKET_IS_FILE(b)) {
+ /* do not count */
+ }
+ else {
+ /* should all have determinate length */
+ l += b->length;
+ }
+ }
+ leave_yellow(beam, lock, acquired);
+ }
+ return l;
+}
+
int h2_beam_empty(h2_bucket_beam *beam)
{
apr_thread_mutex_t *lock;
diff --git a/modules/http2/h2_bucket_beam.h b/modules/http2/h2_bucket_beam.h
index 45d98b29cc..0b40599022 100644
--- a/modules/http2/h2_bucket_beam.h
+++ b/modules/http2/h2_bucket_beam.h
@@ -284,6 +284,11 @@ void h2_beam_on_file_beam(h2_bucket_beam *beam,
*/
apr_off_t h2_beam_get_buffered(h2_bucket_beam *beam);
+/**
+ * Get the memory used by the buffered buckets, approximately.
+ */
+apr_off_t h2_beam_get_mem_used(h2_bucket_beam *beam);
+
int h2_beam_closed(h2_bucket_beam *beam);
int h2_beam_empty(h2_bucket_beam *beam);
diff --git a/modules/http2/h2_proxy_session.c b/modules/http2/h2_proxy_session.c
index 19aff5bf6f..51b68f2f4f 100644
--- a/modules/http2/h2_proxy_session.c
+++ b/modules/http2/h2_proxy_session.c
@@ -354,10 +354,10 @@ static int on_data_chunk_recv(nghttp2_session *ngh2, uint8_t flags,
b = apr_bucket_transient_create((const char*)data, len,
stream->r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(stream->output, b);
- if (flags & NGHTTP2_DATA_FLAG_EOF) {
- b = apr_bucket_flush_create(stream->r->connection->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(stream->output, b);
- }
+ /* always flush after a DATA frame, as we have no other indication
+ * of buffer use */
+ b = apr_bucket_flush_create(stream->r->connection->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(stream->output, b);
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, stream->r, APLOGNO(03359)
"h2_proxy_session(%s): pass response data for "
diff --git a/modules/http2/h2_task.c b/modules/http2/h2_task.c
index ba67b4198f..3eb25e8f7a 100644
--- a/modules/http2/h2_task.c
+++ b/modules/http2/h2_task.c
@@ -242,7 +242,7 @@ static apr_status_t input_read(h2_task *task, ap_filter_t* f,
}
/*******************************************************************************
- * task input handling
+ * task output handling
******************************************************************************/
static apr_status_t open_response(h2_task *task)
@@ -312,6 +312,7 @@ static apr_status_t output_write(h2_task *task, ap_filter_t* f,
{
apr_bucket *b;
apr_status_t status = APR_SUCCESS;
+ int flush = 0;
if (APR_BRIGADE_EMPTY(bb)) {
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, task->c,
@@ -349,7 +350,22 @@ static apr_status_t output_write(h2_task *task, ap_filter_t* f,
}
/* If there is nothing saved (anymore), try to write the brigade passed */
- if ((!task->output.bb || APR_BRIGADE_EMPTY(task->output.bb)) && !APR_BRIGADE_EMPTY(bb)) {
+ if ((!task->output.bb || APR_BRIGADE_EMPTY(task->output.bb))
+ && !APR_BRIGADE_EMPTY(bb)) {
+ /* check if we have a flush before the end-of-request */
+ if (!task->output.response_open) {
+ for (b = APR_BRIGADE_FIRST(bb);
+ b != APR_BRIGADE_SENTINEL(bb);
+ b = APR_BUCKET_NEXT(b)) {
+ if (AP_BUCKET_IS_EOR(b)) {
+ break;
+ }
+ else if (APR_BUCKET_IS_FLUSH(b)) {
+ flush = 1;
+ }
+ }
+ }
+
status = send_out(task, bb);
if (status != APR_SUCCESS) {
return status;
@@ -368,9 +384,10 @@ static apr_status_t output_write(h2_task *task, ap_filter_t* f,
return ap_save_brigade(f, &task->output.bb, &bb, task->pool);
}
- if (!task->output.response_open) {
- /* data is in the output beam, if we have not opened the response,
- * do so now. */
+ if (!task->output.response_open
+ && (flush || h2_beam_get_mem_used(task->output.beam) > (32*1024))) {
+ /* if we have enough buffered or we got a flush bucket, open
+ * the response now. */
status = open_response(task);
task->output.response_open = 1;
}
@@ -378,6 +395,17 @@ static apr_status_t output_write(h2_task *task, ap_filter_t* f,
return status;
}
+static apr_status_t output_finish(h2_task *task)
+{
+ apr_status_t status = APR_SUCCESS;
+
+ if (!task->output.response_open) {
+ status = open_response(task);
+ task->output.response_open = 1;
+ }
+ return status;
+}
+
/*******************************************************************************
* task slave connection filters
******************************************************************************/
@@ -461,7 +489,6 @@ h2_task *h2_task_create(conn_rec *c, const h2_request *req,
ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, c,
APLOGNO(02941) "h2_task(%ld-%d): create stream task",
c->id, req->id);
- h2_mplx_out_close(mplx, req->id);
return NULL;
}
@@ -505,8 +532,6 @@ void h2_task_set_io_blocking(h2_task *task, int blocking)
apr_status_t h2_task_do(h2_task *task)
{
- apr_status_t status;
-
AP_DEBUG_ASSERT(task);
task->input.block = APR_BLOCK_READ;
@@ -546,16 +571,13 @@ apr_status_t h2_task_do(h2_task *task)
"h2_task(%s): process_conn returned frozen task",
task->id);
/* cleanup delayed */
- status = APR_EAGAIN;
+ return APR_EAGAIN;
}
else {
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, task->c,
"h2_task(%s): processing done", task->id);
- h2_mplx_out_close(task->mplx, task->stream_id);
- status = APR_SUCCESS;
+ return output_finish(task);
}
-
- return status;
}
static apr_status_t h2_task_process_request(h2_task *task, conn_rec *c)