]> git.kaiwu.me - nginx.git/commitdiff
SPDY: always push pending data.
authorValentin Bartenev <vbart@nginx.com>
Mon, 23 Mar 2015 18:04:13 +0000 (21:04 +0300)
committerValentin Bartenev <vbart@nginx.com>
Mon, 23 Mar 2015 18:04:13 +0000 (21:04 +0300)
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().

src/http/ngx_http_spdy.c

index c35c31a183819dc4b5b7875b5af06eaa4c8d68a0..6bb79b88bab4f32177724f361575887924a2fa2f 100644 (file)
@@ -662,6 +662,7 @@ ngx_http_spdy_write_handler(ngx_event_t *wev)
 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_spdy_connection_t *sc)
         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_event_t *ev)
 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_stream_t *stream, ngx_int_t rc)
         {
             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) {