changeset 8476:f9fbeb4ee0de quic

QUIC: added limit of queued data. The ngx_quic_queue_frame() functions puts a frame into send queue and schedules a push timer to actually send data. The patch adds tracking for data amount in the queue and sends data immediately if amount of data exceeds limit.
author Vladimir Homutov <vl@nginx.com>
date Thu, 16 Jul 2020 15:02:38 +0300
parents b276833111cf
children 031918df51c0
files src/event/ngx_event_quic.c src/event/ngx_event_quic.h src/event/ngx_event_quic_transport.h
diffstat 3 files changed, 34 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/src/event/ngx_event_quic.c
+++ b/src/event/ngx_event_quic.c
@@ -73,6 +73,8 @@ typedef struct {
 
     ngx_queue_t                       frames;
     ngx_queue_t                       sent;
+
+    size_t                            frames_len;
 } ngx_quic_send_ctx_t;
 
 
@@ -3273,10 +3275,24 @@ ngx_quic_queue_frame(ngx_quic_connection
 
     ngx_queue_insert_tail(&ctx->frames, &frame->queue);
 
-    /* TODO: check PUSH flag on stream and call output */
-
-    if (!qc->push.timer_set && !qc->closing) {
-        ngx_add_timer(&qc->push, qc->tp.max_ack_delay);
+    frame->len = ngx_quic_create_frame(NULL, frame);
+    /* always succeeds */
+
+    ctx->frames_len += frame->len;
+
+    if (qc->closing) {
+        return;
+    }
+
+    /* TODO: TCP_NODELAY analogue ? TCP_CORK and others... */
+
+    if (ctx->frames_len < NGX_QUIC_MIN_DATA_NODELAY) {
+        if (!qc->push.timer_set) {
+            ngx_add_timer(&qc->push, qc->tp.max_ack_delay);
+        }
+
+    } else {
+        ngx_post_event(&qc->push, &ngx_posted_events);
     }
 }
 
@@ -3309,7 +3325,7 @@ ngx_quic_output(ngx_connection_t *c)
 static ngx_int_t
 ngx_quic_output_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx)
 {
-    size_t                  len, hlen, n;
+    size_t                  len, hlen;
     ngx_uint_t              need_ack;
     ngx_queue_t            *q, range;
     ngx_quic_frame_t       *f;
@@ -3340,9 +3356,7 @@ ngx_quic_output_frames(ngx_connection_t 
             /* process group of frames that fits into packet */
             f = ngx_queue_data(q, ngx_quic_frame_t, queue);
 
-            n = ngx_quic_create_frame(NULL, f);
-
-            if (len && hlen + len + n > qc->ctp.max_udp_payload_size) {
+            if (len && hlen + len + f->len > qc->ctp.max_udp_payload_size) {
                 break;
             }
 
@@ -3350,7 +3364,7 @@ ngx_quic_output_frames(ngx_connection_t 
                 need_ack = 1;
             }
 
-            if (need_ack && cg->in_flight + len + n > cg->window) {
+            if (need_ack && cg->in_flight + len + f->len > cg->window) {
                 break;
             }
 
@@ -3360,8 +3374,9 @@ ngx_quic_output_frames(ngx_connection_t 
 
             ngx_queue_remove(&f->queue);
             ngx_queue_insert_tail(&range, &f->queue);
-
-            len += n;
+            ctx->frames_len -= f->len;
+
+            len += f->len;
 
         } while (q != ngx_queue_sentinel(&ctx->frames));
 
@@ -4271,7 +4286,6 @@ ngx_quic_alloc_frame(ngx_connection_t *c
 static void
 ngx_quic_congestion_ack(ngx_connection_t *c, ngx_quic_frame_t *f)
 {
-    ssize_t                 n;
     ngx_msec_t              timer;
     ngx_quic_congestion_t  *cg;
     ngx_quic_connection_t  *qc;
@@ -4279,9 +4293,7 @@ ngx_quic_congestion_ack(ngx_connection_t
     qc = c->quic;
     cg = &qc->congestion;
 
-    n = ngx_quic_create_frame(NULL, f);
-
-    cg->in_flight -= n;
+    cg->in_flight -= f->len;
 
     timer = f->last - cg->recovery_start;
 
@@ -4290,14 +4302,14 @@ ngx_quic_congestion_ack(ngx_connection_t
     }
 
     if (cg->window < cg->ssthresh) {
-        cg->window += n;
+        cg->window += f->len;
 
         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
                        "quic congestion slow start win:%uz, ss:%uz, if:%uz",
                        cg->window, cg->ssthresh, cg->in_flight);
 
     } else {
-        cg->window += qc->tp.max_udp_payload_size * n / cg->window;
+        cg->window += qc->tp.max_udp_payload_size * f->len / cg->window;
 
         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
                        "quic congestion avoidance win:%uz, ss:%uz, if:%uz",
--- a/src/event/ngx_event_quic.h
+++ b/src/event/ngx_event_quic.h
@@ -54,6 +54,10 @@
 
 #define NGX_QUIC_MIN_INITIAL_SIZE            1200
 
+/* if we have so much data, send immediately */
+/* TODO: configurable ? */
+#define NGX_QUIC_MIN_DATA_NODELAY             512 /* bytes */
+
 #define NGX_QUIC_STREAM_SERVER_INITIATED     0x01
 #define NGX_QUIC_STREAM_UNIDIRECTIONAL       0x02
 
--- a/src/event/ngx_event_quic_transport.h
+++ b/src/event/ngx_event_quic_transport.h
@@ -250,6 +250,7 @@ struct ngx_quic_frame_s {
     uint64_t                                    pnum;
     ngx_msec_t                                  first;
     ngx_msec_t                                  last;
+    ssize_t                                     len;
     ngx_uint_t                                  need_ack;
                                                     /* unsigned need_ack:1; */