[nginx] SPDY: push pending data while closing a stream as with k...

Maxim Dounin mdounin at mdounin.ru
Tue Apr 7 13:04:21 UTC 2015


details:   http://hg.nginx.org/nginx/rev/7ea6f5140ed9
branches:  stable-1.6
changeset: 6078:7ea6f5140ed9
user:      Valentin Bartenev <vbart at nginx.com>
date:      Fri Nov 21 22:51:49 2014 +0300
description:
SPDY: push pending data while closing a stream as with keepalive.

This helps to avoid delays in sending the last chunk of data because
of bad interaction between Nagle's algorithm on nginx side and
delayed ACK on the client side.

Delays could also be caused by TCP_CORK/TCP_NOPUSH if SPDY was
working without SSL and sendfile() was used.

diffstat:

 src/http/ngx_http_spdy.c |  52 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 51 insertions(+), 1 deletions(-)

diffs (70 lines):

diff --git a/src/http/ngx_http_spdy.c b/src/http/ngx_http_spdy.c
--- a/src/http/ngx_http_spdy.c
+++ b/src/http/ngx_http_spdy.c
@@ -3156,8 +3156,10 @@ ngx_http_spdy_close_stream_handler(ngx_e
 void
 ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
 {
+    int                           tcp_nodelay;
     ngx_event_t                  *ev;
-    ngx_connection_t             *fc;
+    ngx_connection_t             *c, *fc;
+    ngx_http_core_loc_conf_t     *clcf;
     ngx_http_spdy_stream_t      **index, *s;
     ngx_http_spdy_srv_conf_t     *sscf;
     ngx_http_spdy_connection_t   *sc;
@@ -3183,6 +3185,54 @@ ngx_http_spdy_close_stream(ngx_http_spdy
         {
             sc->connection->error = 1;
         }
+
+    } else {
+        c = sc->connection;
+
+        if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
+            if (ngx_tcp_push(c->fd) == -1) {
+                ngx_connection_error(c, ngx_socket_errno,
+                                     ngx_tcp_push_n " failed");
+                c->error = 1;
+                tcp_nodelay = 0;
+
+            } else {
+                c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
+                tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0;
+            }
+
+        } else {
+            tcp_nodelay = 1;
+        }
+
+        clcf = ngx_http_get_module_loc_conf(stream->request,
+                                            ngx_http_core_module);
+
+        if (tcp_nodelay
+            && clcf->tcp_nodelay
+            && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET)
+        {
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
+
+            if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
+                           (const void *) &tcp_nodelay, sizeof(int))
+                == -1)
+            {
+#if (NGX_SOLARIS)
+                /* Solaris returns EINVAL if a socket has been shut down */
+                c->log_error = NGX_ERROR_IGNORE_EINVAL;
+#endif
+
+                ngx_connection_error(c, ngx_socket_errno,
+                                     "setsockopt(TCP_NODELAY) failed");
+
+                c->log_error = NGX_ERROR_INFO;
+                c->error = 1;
+
+            } else {
+                c->tcp_nodelay = NGX_TCP_NODELAY_SET;
+            }
+        }
     }
 
     if (sc->stream == stream) {



More information about the nginx-devel mailing list