Author: rhuijben
Date: Wed Nov 25 12:27:42 2015
New Revision: 1716371
URL: http://svn.apache.org/viewvc?rev=1716371&view=rev
Log:
Remove a lot of bucket reading from the http2 processing by trying to read
a headers bucket before reading the separate lines to fill it.
Before this patch we usually created a header bucket and then read it into
another header bucket.
* buckets/barrier_buckets.c
(serf_barrier_read_bucket): New function.
(serf_bucket_type_barrier): Resolve TODO.
* buckets/hpack_buckets.c
(serf_hpack_decode_read,
serf_hpack_decode_peek): Remove unneeded check.
(serf_hpack_decode_read_bucket): New function.
* buckets/response_buckets.c
(response_context_t): Introduce new substates, to allow skipping
some parts of processing.
(serf_bucket_response_create,
serf_bucket_response_get_headers): Initialize headers on demand.
(run_machine): Handle the first and last headers read operations
as specific states to allow reading the headers as a bucket.
Modified:
serf/trunk/buckets/barrier_buckets.c
serf/trunk/buckets/hpack_buckets.c
serf/trunk/buckets/response_buckets.c
Modified: serf/trunk/buckets/barrier_buckets.c
URL:
http://svn.apache.org/viewvc/serf/trunk/buckets/barrier_buckets.c?rev=1716371&r1=1716370&r2=1716371&view=diff
==============================================================================
--- serf/trunk/buckets/barrier_buckets.c (original)
+++ serf/trunk/buckets/barrier_buckets.c Wed Nov 25 12:27:42 2015
@@ -72,6 +72,20 @@ static apr_status_t serf_barrier_readlin
return serf_bucket_readline(stream, acceptable, found, data, len);
}
+static serf_bucket_t *serf_barrier_read_bucket(serf_bucket_t *bucket,
+ const serf_bucket_type_t *type)
+{
+ serf_bucket_t *stream = bucket->data;
+
+ /* If a not-NULL bucket is returned then the ownership of that bucket may
+ now have been transferred. (See aggregate bucket read support).
+
+ This may affect something in our bucket, like any read does, but
+ we still perform our 'barrier job' of keeping the stream alive. */
+
+ return serf_bucket_read_bucket(stream, type);
+}
+
static apr_status_t serf_barrier_peek(serf_bucket_t *bucket,
const char **data,
apr_size_t *len)
@@ -118,7 +132,7 @@ const serf_bucket_type_t serf_bucket_typ
serf_buckets_are_v2,
serf_barrier_peek,
serf_barrier_destroy,
- serf_default_read_bucket, /* ### TODO? */
+ serf_barrier_read_bucket,
serf_barrier_get_remaining,
serf_barrier_set_config,
};
Modified: serf/trunk/buckets/hpack_buckets.c
URL:
http://svn.apache.org/viewvc/serf/trunk/buckets/hpack_buckets.c?rev=1716371&r1=1716370&r2=1716371&view=diff
==============================================================================
--- serf/trunk/buckets/hpack_buckets.c (original)
+++ serf/trunk/buckets/hpack_buckets.c Wed Nov 25 12:27:42 2015
@@ -1877,7 +1877,7 @@ serf_hpack_decode_read(serf_bucket_t *bu
apr_status_t status;
status = hpack_process(bucket);
- if (status || !ctx->agg)
+ if (status)
{
*len = 0;
return (status == SERF_ERROR_EMPTY_READ) ? APR_SUCCESS : status;
@@ -1895,7 +1895,7 @@ serf_hpack_decode_peek(serf_bucket_t *bu
apr_status_t status;
status = hpack_process(bucket);
- if (status || !ctx->agg)
+ if (status)
{
*len = 0;
return (status == SERF_ERROR_EMPTY_READ) ? APR_SUCCESS : status;
@@ -1904,6 +1904,18 @@ serf_hpack_decode_peek(serf_bucket_t *bu
return serf_bucket_peek(ctx->agg, data, len);
}
+static serf_bucket_t *
+serf_hpack_decode_read_bucket(serf_bucket_t *bucket,
+ const serf_bucket_type_t *type)
+{
+ serf_hpack_decode_ctx_t *ctx = bucket->data;
+
+ if (!ctx->hit_eof)
+ return serf_default_read_bucket(bucket, type);
+ else
+ return serf_bucket_read_bucket(ctx->agg, type);
+}
+
static apr_status_t
serf_hpack_decode_set_config(serf_bucket_t *bucket,
serf_config_t *config)
@@ -1930,10 +1942,9 @@ static void
serf_hpack_decode_destroy(serf_bucket_t *bucket)
{
serf_hpack_decode_ctx_t *ctx = bucket->data;
- serf_bucket_destroy(ctx->stream);
- if (ctx->agg)
- serf_bucket_destroy(ctx->agg);
+ serf_bucket_destroy(ctx->stream);
+ serf_bucket_destroy(ctx->agg);
if (ctx->method)
serf_bucket_mem_free(bucket->allocator, (void*)ctx->method);
@@ -1960,7 +1971,7 @@ const serf_bucket_type_t serf_bucket_typ
serf_buckets_are_v2,
serf_hpack_decode_peek,
serf_hpack_decode_destroy,
- serf_default_read_bucket,
+ serf_hpack_decode_read_bucket,
serf_default_get_remaining,
serf_hpack_decode_set_config
};
Modified: serf/trunk/buckets/response_buckets.c
URL:
http://svn.apache.org/viewvc/serf/trunk/buckets/response_buckets.c?rev=1716371&r1=1716370&r2=1716371&view=diff
==============================================================================
--- serf/trunk/buckets/response_buckets.c (original)
+++ serf/trunk/buckets/response_buckets.c Wed Nov 25 12:27:42 2015
@@ -35,7 +35,9 @@ typedef struct response_context_t {
enum {
STATE_STATUS_LINE, /* reading status line */
STATE_NEXT_STATUS_LINE,
+ STATE_PRE_HEADERS,
STATE_HEADERS, /* reading headers */
+ STATE_PRE_BODY,
STATE_BODY, /* reading body */
STATE_TRAILERS, /* reading trailers */
STATE_DONE /* we've sent EOF */
@@ -87,8 +89,8 @@ serf_bucket_t *serf_bucket_response_crea
ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
ctx->stream = stream;
ctx->body = NULL;
- ctx->incoming_headers = serf_bucket_headers_create(allocator);
- ctx->fetch_headers = ctx->incoming_headers;
+ ctx->incoming_headers = NULL;
+ ctx->fetch_headers = NULL;
ctx->state = STATE_STATUS_LINE;
ctx->chunked = 0;
ctx->head_req = 0;
@@ -118,10 +120,21 @@ void serf_bucket_response_decode_content
ctx->decode_content = decode;
}
-serf_bucket_t *serf_bucket_response_get_headers(
- serf_bucket_t *bucket)
+serf_bucket_t *serf_bucket_response_get_headers(serf_bucket_t *bucket)
{
- return ((response_context_t *)bucket->data)->fetch_headers;
+ response_context_t *ctx = bucket->data;
+
+ if (!ctx->fetch_headers) {
+
+ if (!ctx->incoming_headers) {
+ ctx->incoming_headers = serf_bucket_headers_create(
+ bucket->allocator);
+ }
+
+ ctx->fetch_headers = ctx->incoming_headers;
+ }
+
+ return ctx->fetch_headers;
}
@@ -281,7 +294,7 @@ static apr_status_t run_machine(serf_buc
}
/* Okay... move on to reading the headers. */
- ctx->state = STATE_HEADERS;
+ ctx->state = STATE_PRE_HEADERS;
}
else {
/* The connection closed before we could get the next
@@ -293,6 +306,34 @@ static apr_status_t run_machine(serf_buc
}
}
break;
+ case STATE_PRE_HEADERS:
+ {
+ serf_bucket_t *read_hdrs;
+
+ ctx->state = STATE_HEADERS;
+
+ /* Perhaps we can just read a headers bucket? */
+ read_hdrs = serf_bucket_read_bucket(ctx->stream,
+ &serf_bucket_type_headers);
+
+ if (read_hdrs) {
+ if (ctx->incoming_headers)
+ serf_bucket_destroy(ctx->incoming_headers);
+
+ ctx->incoming_headers = read_hdrs;
+
+ ctx->state = STATE_PRE_BODY;
+ }
+ else if (!ctx->incoming_headers) {
+ ctx->incoming_headers =
+ serf_bucket_headers_create(bkt->allocator);
+ }
+
+ if (!ctx->fetch_headers)
+ ctx->fetch_headers = ctx->incoming_headers;
+ }
+ break;
+
case STATE_HEADERS:
status = fetch_headers(bkt, ctx);
if (SERF_BUCKET_READ_ERROR(status))
@@ -301,7 +342,15 @@ static apr_status_t run_machine(serf_buc
/* If an empty line was read, then we hit the end of the headers.
* Move on to the body.
*/
- if (ctx->linebuf.state == SERF_LINEBUF_READY && !ctx->linebuf.used) {
+ if (ctx->linebuf.state != SERF_LINEBUF_READY || ctx->linebuf.used)
+ break;
+
+ /* Advance the state. */
+ ctx->state = STATE_PRE_BODY;
+ /* fall through */
+
+ case STATE_PRE_BODY:
+ {
const char *v;
int chunked = 0;
int gzip = 0;
@@ -523,7 +572,7 @@ apr_status_t serf_bucket_response_status
* it is quite possible to advance *and* to return APR_EAGAIN.
*/
status = run_machine(bkt, ctx);
- if (ctx->state == STATE_HEADERS) {
+ if (ctx->state != STATE_STATUS_LINE) {
*sline = ctx->sl;
}
else {