Mercurial > hg > nginx
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; |