comparison src/http/ngx_http_spdy.c @ 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 a420cb1c170b
comparison
equal deleted inserted replaced
6058:7ba52c995325 6059:c81d79a7befd
660 660
661 661
662 ngx_int_t 662 ngx_int_t
663 ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc) 663 ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc)
664 { 664 {
665 int tcp_nodelay;
665 ngx_chain_t *cl; 666 ngx_chain_t *cl;
666 ngx_event_t *wev; 667 ngx_event_t *wev;
667 ngx_connection_t *c; 668 ngx_connection_t *c;
668 ngx_http_core_loc_conf_t *clcf; 669 ngx_http_core_loc_conf_t *clcf;
669 ngx_http_spdy_out_frame_t *out, *frame, *fn; 670 ngx_http_spdy_out_frame_t *out, *frame, *fn;
706 clcf = ngx_http_get_module_loc_conf(sc->http_connection->conf_ctx, 707 clcf = ngx_http_get_module_loc_conf(sc->http_connection->conf_ctx,
707 ngx_http_core_module); 708 ngx_http_core_module);
708 709
709 if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { 710 if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
710 goto error; 711 goto error;
712 }
713
714 if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
715 if (ngx_tcp_push(c->fd) == -1) {
716 ngx_connection_error(c, ngx_socket_errno, ngx_tcp_push_n " failed");
717 goto error;
718 }
719
720 c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
721 tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0;
722
723 } else {
724 tcp_nodelay = 1;
725 }
726
727 if (tcp_nodelay
728 && clcf->tcp_nodelay
729 && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET)
730 {
731 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
732
733 if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
734 (const void *) &tcp_nodelay, sizeof(int))
735 == -1)
736 {
737 #if (NGX_SOLARIS)
738 /* Solaris returns EINVAL if a socket has been shut down */
739 c->log_error = NGX_ERROR_IGNORE_EINVAL;
740 #endif
741
742 ngx_connection_error(c, ngx_socket_errno,
743 "setsockopt(TCP_NODELAY) failed");
744
745 c->log_error = NGX_ERROR_INFO;
746 goto error;
747 }
748
749 c->tcp_nodelay = NGX_TCP_NODELAY_SET;
711 } 750 }
712 751
713 if (cl) { 752 if (cl) {
714 ngx_add_timer(wev, clcf->send_timeout); 753 ngx_add_timer(wev, clcf->send_timeout);
715 754
3319 3358
3320 3359
3321 void 3360 void
3322 ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc) 3361 ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
3323 { 3362 {
3324 int tcp_nodelay;
3325 ngx_event_t *ev; 3363 ngx_event_t *ev;
3326 ngx_connection_t *c, *fc; 3364 ngx_connection_t *fc;
3327 ngx_http_core_loc_conf_t *clcf;
3328 ngx_http_spdy_stream_t **index, *s; 3365 ngx_http_spdy_stream_t **index, *s;
3329 ngx_http_spdy_srv_conf_t *sscf; 3366 ngx_http_spdy_srv_conf_t *sscf;
3330 ngx_http_spdy_connection_t *sc; 3367 ngx_http_spdy_connection_t *sc;
3331 3368
3332 sc = stream->connection; 3369 sc = stream->connection;
3347 NGX_SPDY_INTERNAL_ERROR, 3384 NGX_SPDY_INTERNAL_ERROR,
3348 stream->priority) 3385 stream->priority)
3349 != NGX_OK) 3386 != NGX_OK)
3350 { 3387 {
3351 sc->connection->error = 1; 3388 sc->connection->error = 1;
3352 }
3353
3354 } else {
3355 c = sc->connection;
3356
3357 if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
3358 if (ngx_tcp_push(c->fd) == -1) {
3359 ngx_connection_error(c, ngx_socket_errno,
3360 ngx_tcp_push_n " failed");
3361 c->error = 1;
3362 tcp_nodelay = 0;
3363
3364 } else {
3365 c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
3366 tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0;
3367 }
3368
3369 } else {
3370 tcp_nodelay = 1;
3371 }
3372
3373 clcf = ngx_http_get_module_loc_conf(stream->request,
3374 ngx_http_core_module);
3375
3376 if (tcp_nodelay
3377 && clcf->tcp_nodelay
3378 && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET)
3379 {
3380 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
3381
3382 if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
3383 (const void *) &tcp_nodelay, sizeof(int))
3384 == -1)
3385 {
3386 #if (NGX_SOLARIS)
3387 /* Solaris returns EINVAL if a socket has been shut down */
3388 c->log_error = NGX_ERROR_IGNORE_EINVAL;
3389 #endif
3390
3391 ngx_connection_error(c, ngx_socket_errno,
3392 "setsockopt(TCP_NODELAY) failed");
3393
3394 c->log_error = NGX_ERROR_INFO;
3395 c->error = 1;
3396
3397 } else {
3398 c->tcp_nodelay = NGX_TCP_NODELAY_SET;
3399 }
3400 } 3389 }
3401 } 3390 }
3402 3391
3403 if (sc->stream == stream) { 3392 if (sc->stream == stream) {
3404 sc->stream = NULL; 3393 sc->stream = NULL;