changeset 6059:c81d79a7befd

SPDY: always push pending data. This helps to avoid suboptimal behavior when a client waits for a control frame or more data to increase window size, but the frames have been delayed in the socket buffer. The delays can be caused by bad interaction between Nagle's algorithm on nginx side and delayed ACK on the client side or by TCP_CORK/TCP_NOPUSH if SPDY was working without SSL and sendfile() was used. The pushing code is now very similar to ngx_http_set_keepalive().
author Valentin Bartenev <vbart@nginx.com>
date Mon, 23 Mar 2015 21:04:13 +0300
parents 7ba52c995325
children 3d4730eada9c
files src/http/ngx_http_spdy.c
diffstat 1 files changed, 40 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/src/http/ngx_http_spdy.c
+++ b/src/http/ngx_http_spdy.c
@@ -662,6 +662,7 @@ ngx_http_spdy_write_handler(ngx_event_t 
 ngx_int_t
 ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc)
 {
+    int                         tcp_nodelay;
     ngx_chain_t                *cl;
     ngx_event_t                *wev;
     ngx_connection_t           *c;
@@ -710,6 +711,44 @@ ngx_http_spdy_send_output_queue(ngx_http
         goto error;
     }
 
+    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");
+            goto error;
+        }
+
+        c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
+        tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0;
+
+    } else {
+        tcp_nodelay = 1;
+    }
+
+    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;
+            goto error;
+        }
+
+        c->tcp_nodelay = NGX_TCP_NODELAY_SET;
+    }
+
     if (cl) {
         ngx_add_timer(wev, clcf->send_timeout);
 
@@ -3321,10 +3360,8 @@ 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             *c, *fc;
-    ngx_http_core_loc_conf_t     *clcf;
+    ngx_connection_t             *fc;
     ngx_http_spdy_stream_t      **index, *s;
     ngx_http_spdy_srv_conf_t     *sscf;
     ngx_http_spdy_connection_t   *sc;
@@ -3350,54 +3387,6 @@ 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) {