Hi, It is limitation of current nginx spdy implementation that whole data chain is sent by single spdy data frame. Below are changes where I tried to change this behavior and use 32kb data frames at most in order to send outgoing spdy data. Any comments are welcome.
# HG changeset patch # User ykirpic...@gmail.com # Date 1372085474 -14400 # Branch spdy_split_big_frame_default # Node ID c8660bcdd8d3fb2ef12fa1edc1d0f39b771de51e # Parent 982678c5c270f93a0c21ab6eb23cb123c0dc3df0 SPDY: split big frames diff -r 982678c5c270 -r c8660bcdd8d3 src/core/ngx_buf.h --- a/src/core/ngx_buf.h Wed Jun 12 00:41:24 2013 +0900 +++ b/src/core/ngx_buf.h Mon Jun 24 18:51:14 2013 +0400 @@ -158,5 +158,8 @@ void ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy, ngx_chain_t **out, ngx_buf_tag_t tag); + ngx_int_t +ngx_split_buf_in_chain(ngx_pool_t *pool, ngx_chain_t **chain, + ngx_chain_t *in, off_t buf_size); #endif /* _NGX_BUF_H_INCLUDED_ */ diff -r 982678c5c270 -r c8660bcdd8d3 src/core/ngx_output_chain.c --- a/src/core/ngx_output_chain.c Wed Jun 12 00:41:24 2013 +0900 +++ b/src/core/ngx_output_chain.c Mon Jun 24 18:51:14 2013 +0400 @@ -672,3 +672,59 @@ return NGX_AGAIN; } + + + ngx_int_t +ngx_split_buf_in_chain(ngx_pool_t *pool, ngx_chain_t **chain, + ngx_chain_t *in, off_t buf_size) +{ + ngx_chain_t *cl, **il; + ngx_buf_t *b, *buf; + +#if 0 + if (!in->buf->in_file) { + return NGX_OK; + } +#endif + + il = chain; + + while (ngx_buf_size(in->buf) > buf_size) { + cl = ngx_alloc_chain_link(pool); + if (cl == NULL) { + return NGX_ERROR; + } + + buf = in->buf; + + /* split a file buf on bufs by the buf_size limit */ + + b = ngx_calloc_buf(pool); + if (b == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(b, buf, sizeof(ngx_buf_t)); + b->start = NULL; + b->end = NULL; + b->last_buf = 0; + b->last_in_chain = 0; + + if (ngx_buf_in_memory(buf)) { + buf->pos += buf_size; + b->last = buf->pos; + } + + buf->file_pos += buf_size; + b->file_last = buf->file_pos; + + cl->buf = b; + + cl->next = in; + *il = cl; + il = &cl->next; + } + + return NGX_OK; +} + diff -r 982678c5c270 -r c8660bcdd8d3 src/http/ngx_http_spdy_filter_module.c --- a/src/http/ngx_http_spdy_filter_module.c Wed Jun 12 00:41:24 2013 +0900 +++ b/src/http/ngx_http_spdy_filter_module.c Mon Jun 24 18:51:14 2013 +0400 @@ -15,6 +15,9 @@ #define NGX_SPDY_WRITE_BUFFERED NGX_HTTP_WRITE_BUFFERED +/* it is subject for change */ +/* consider to use NGX_SPDY_MAX_FRAME_SIZE instead ??? */ +#define NGX_SPDY_MAX_FRAME_LENGTH (1024 * 32) #define ngx_http_spdy_nv_nsize(h) (NGX_SPDY_NV_NLEN_SIZE + sizeof(h) - 1) #define ngx_http_spdy_nv_vsize(h) (NGX_SPDY_NV_VLEN_SIZE + sizeof(h) - 1) @@ -676,6 +679,10 @@ cl->buf = b; *ln = cl; + if (ngx_buf_size(b) > NGX_SPDY_MAX_FRAME_LENGTH) { + ngx_split_buf_in_chain(r->pool, ln, cl, NGX_SPDY_MAX_FRAME_LENGTH); + } + ln = &cl->next; if (ll->next == NULL) { @@ -685,24 +692,51 @@ ll = ll->next; } - if (size > NGX_SPDY_MAX_FRAME_SIZE) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "FIXME: chain too big in spdy filter: %O", size); - return NGX_ERROR; + cl->next = NULL; + ll = cl = out; + size = 0; + + for ( ;; ) { + if (size + ngx_buf_size(cl->buf) > NGX_SPDY_MAX_FRAME_LENGTH) { + ll->buf->last_in_chain = 1; + frame = ngx_http_spdy_filter_get_data_frame(stream, (size_t)size, + ll->buf->last_buf, out, ll); + + ngx_http_spdy_queue_frame(stream->connection, frame); + stream->waiting++; + r->main->blocked++; + + + size = ngx_buf_size(cl->buf); + out = cl; + ll->next = NULL; + ll = cl; + if (cl->next == NULL) { + break; + } + cl = cl->next; + } + else { + size += ngx_buf_size(cl->buf); + ll = cl; + if (cl->next == NULL) { + break; + } + cl = cl->next; + + } } - frame = ngx_http_spdy_filter_get_data_frame(stream, (size_t) size, - b->last_buf, out, cl); - if (frame == NULL) { - return NGX_ERROR; + if (size > 0) { + ll->buf->last_in_chain = 1; + + frame = ngx_http_spdy_filter_get_data_frame(stream, (size_t)size, + ll->buf->last_buf, out, ll); + ngx_http_spdy_queue_frame(stream->connection, frame); + stream->waiting++; + r->main->blocked++; } - ngx_http_spdy_queue_frame(stream->connection, frame); - - stream->waiting++; - - r->main->blocked++; - return ngx_http_spdy_filter_send(r->connection, stream); } BR/ Yury
_______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel