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