[PATCH 2 of 2] HTTP/3: delayed Insert Count Increment instruction

Roman Arutyunyan arut at nginx.com
Thu Nov 18 09:52:15 UTC 2021


# HG changeset patch
# User Roman Arutyunyan <arut at nginx.com>
# Date 1637160353 -10800
#      Wed Nov 17 17:45:53 2021 +0300
# Branch quic
# Node ID 77e14add92c2e3a9c83eae5d4a8e260bb3e39daf
# Parent  b844c77ff22218a4863d1d926bcaaa0b043c8af5
HTTP/3: delayed Insert Count Increment instruction.

Sending the instruction is delayed until the end of the current event cycle.
Delaying the instruction is allowed by quic-qpack-21, section 2.2.2.3.
The goal is to reduce the amount of data sent back to client by accumulating
several inserts in one instruction and sometimes not sending the instruction at
all, if Section Acknowledgement was sent just before it.

diff --git a/src/http/v3/ngx_http_v3.c b/src/http/v3/ngx_http_v3.c
--- a/src/http/v3/ngx_http_v3.c
+++ b/src/http/v3/ngx_http_v3.c
@@ -45,6 +45,10 @@ ngx_http_v3_init_session(ngx_connection_
     h3c->keepalive.handler = ngx_http_v3_keepalive_handler;
     h3c->keepalive.cancelable = 1;
 
+    h3c->table.send_insert_count.log = c->log;
+    h3c->table.send_insert_count.data = c;
+    h3c->table.send_insert_count.handler = ngx_http_v3_inc_insert_count_handler;
+
     cln = ngx_pool_cleanup_add(c->pool, 0);
     if (cln == NULL) {
         goto failed;
@@ -91,6 +95,10 @@ ngx_http_v3_cleanup_session(void *data)
     if (h3c->keepalive.timer_set) {
         ngx_del_timer(&h3c->keepalive);
     }
+
+    if (h3c->table.send_insert_count.posted) {
+        ngx_delete_posted_event(&h3c->table.send_insert_count);
+    }
 }
 
 
diff --git a/src/http/v3/ngx_http_v3_parse.c b/src/http/v3/ngx_http_v3_parse.c
--- a/src/http/v3/ngx_http_v3_parse.c
+++ b/src/http/v3/ngx_http_v3_parse.c
@@ -398,6 +398,8 @@ done:
         {
             return NGX_ERROR;
         }
+
+        ngx_http_v3_ack_insert_count(c, st->prefix.insert_count);
     }
 
     st->state = sw_start;
diff --git a/src/http/v3/ngx_http_v3_tables.c b/src/http/v3/ngx_http_v3_tables.c
--- a/src/http/v3/ngx_http_v3_tables.c
+++ b/src/http/v3/ngx_http_v3_tables.c
@@ -232,11 +232,9 @@ ngx_http_v3_insert(ngx_connection_t *c, 
     dt->elts[dt->nelts++] = field;
     dt->size += size;
 
-    /* TODO increment can be sent less often */
+    dt->insert_count++;
 
-    if (ngx_http_v3_send_inc_insert_count(c, 1) != NGX_OK) {
-        return NGX_ERROR;
-    }
+    ngx_post_event(&dt->send_insert_count, &ngx_posted_events);
 
     if (ngx_http_v3_new_entry(c) != NGX_OK) {
         return NGX_ERROR;
@@ -246,6 +244,34 @@ ngx_http_v3_insert(ngx_connection_t *c, 
 }
 
 
+void
+ngx_http_v3_inc_insert_count_handler(ngx_event_t *ev)
+{
+    ngx_connection_t             *c;
+    ngx_http_v3_session_t        *h3c;
+    ngx_http_v3_dynamic_table_t  *dt;
+
+    c = ev->data;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http3 inc insert count handler");
+
+    h3c = ngx_http_v3_get_session(c);
+    dt = &h3c->table;
+
+    if (dt->insert_count > dt->ack_insert_count) {
+        if (ngx_http_v3_send_inc_insert_count(c,
+                                       dt->insert_count - dt->ack_insert_count)
+            != NGX_OK)
+        {
+            return;
+        }
+
+        dt->ack_insert_count = dt->insert_count;
+    }
+}
+
+
 ngx_int_t
 ngx_http_v3_set_capacity(ngx_connection_t *c, ngx_uint_t capacity)
 {
@@ -607,6 +633,21 @@ ngx_http_v3_check_insert_count(ngx_conne
 }
 
 
+void
+ngx_http_v3_ack_insert_count(ngx_connection_t *c, uint64_t insert_count)
+{
+    ngx_http_v3_session_t        *h3c;
+    ngx_http_v3_dynamic_table_t  *dt;
+
+    h3c = ngx_http_v3_get_session(c);
+    dt = &h3c->table;
+
+    if (dt->ack_insert_count < insert_count) {
+        dt->ack_insert_count = insert_count;
+    }
+}
+
+
 static void
 ngx_http_v3_unblock(void *data)
 {
diff --git a/src/http/v3/ngx_http_v3_tables.h b/src/http/v3/ngx_http_v3_tables.h
--- a/src/http/v3/ngx_http_v3_tables.h
+++ b/src/http/v3/ngx_http_v3_tables.h
@@ -26,9 +26,13 @@ typedef struct {
     ngx_uint_t                    base;
     size_t                        size;
     size_t                        capacity;
+    uint64_t                      insert_count;
+    uint64_t                      ack_insert_count;
+    ngx_event_t                   send_insert_count;
 } ngx_http_v3_dynamic_table_t;
 
 
+void ngx_http_v3_inc_insert_count_handler(ngx_event_t *ev);
 void ngx_http_v3_cleanup_table(ngx_http_v3_session_t *h3c);
 ngx_int_t ngx_http_v3_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic,
     ngx_uint_t index, ngx_str_t *value);
@@ -46,6 +50,7 @@ ngx_int_t ngx_http_v3_decode_insert_coun
     ngx_uint_t *insert_count);
 ngx_int_t ngx_http_v3_check_insert_count(ngx_connection_t *c,
     ngx_uint_t insert_count);
+void ngx_http_v3_ack_insert_count(ngx_connection_t *c, uint64_t insert_count);
 ngx_int_t ngx_http_v3_set_param(ngx_connection_t *c, uint64_t id,
     uint64_t value);
 


More information about the nginx-devel mailing list