]> git.kaiwu.me - nginx.git/commitdiff
HTTP/2: optimized queuing of DATA frames
authorSergey Kandaurov <pluknet@nginx.com>
Fri, 25 Sep 2026 14:16:36 +0000 (14:16 +0000)
committerSergey Kandaurov <pluknet@nginx.com>
Wed, 4 Nov 2026 18:09:10 +0000 (22:09 +0400)
With priorities from RFC 9218, streams of the same urgency are ordered
by their identifiers, so queuing a frame of an older stream traverses
the frames of all newer ones.

Frames queued in ngx_http_v2_send_chain() belong to a single stream, and
hence to a single position in the output queue, which does not change
while they are queued.  Now the position is searched once per call.

src/http/v2/ngx_http_v2.h
src/http/v2/ngx_http_v2_filter_module.c

index 797e3e8b19392b66db6aa8e6238f38b6589f31e6..eb3cd008e980d7c468b5543ee68bb399eab92fb1 100644 (file)
@@ -261,9 +261,11 @@ ngx_http_v2_stream_precedes(ngx_http_v2_stream_t *s,
 }
 
 
-static ngx_inline void
-ngx_http_v2_queue_frame(ngx_http_v2_connection_t *h2c,
-    ngx_http_v2_out_frame_t *frame)
+/* all frames of a stream are queued at the same position */
+
+static ngx_inline ngx_http_v2_out_frame_t **
+ngx_http_v2_queue_position(ngx_http_v2_connection_t *h2c,
+    ngx_http_v2_stream_t *stream)
 {
     ngx_http_v2_out_frame_t  **out;
 
@@ -273,11 +275,19 @@ ngx_http_v2_queue_frame(ngx_http_v2_connection_t *h2c,
             break;
         }
 
-        if (ngx_http_v2_stream_precedes((*out)->stream, frame->stream)) {
+        if (ngx_http_v2_stream_precedes((*out)->stream, stream)) {
             break;
         }
     }
 
+    return out;
+}
+
+
+static ngx_inline void
+ngx_http_v2_queue_frame(ngx_http_v2_out_frame_t **out,
+    ngx_http_v2_out_frame_t *frame)
+{
     frame->next = *out;
     *out = frame;
 }
index 4165c1c06147cfe2d86f0618d86b6511fcd1d799..c82cbbddf9864ae004cf29cf4ea46745cf889b47 100644 (file)
@@ -1068,7 +1068,7 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit)
     ngx_http_request_t        *r;
     ngx_http_v2_stream_t      *stream;
     ngx_http_v2_loc_conf_t    *h2lcf;
-    ngx_http_v2_out_frame_t   *frame, *trailers;
+    ngx_http_v2_out_frame_t   *frame, *trailers, **fn;
     ngx_http_v2_connection_t  *h2c;
 
     r = fc->data;
@@ -1156,6 +1156,8 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit)
 
     trailers = NGX_HTTP_V2_NO_TRAILERS;
 
+    fn = ngx_http_v2_queue_position(h2c, stream);
+
 #if (NGX_SUPPRESS_WARN)
     cl = NULL;
 #endif
@@ -1236,7 +1238,7 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit)
                 return NGX_CHAIN_ERROR;
             }
 
-            ngx_http_v2_queue_frame(h2c, frame);
+            ngx_http_v2_queue_frame(fn, frame);
 
             h2c->send_window -= frame_size;
 
@@ -1247,7 +1249,7 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit)
         if (in == NULL) {
 
             if (trailers != NGX_HTTP_V2_NO_TRAILERS) {
-                ngx_http_v2_queue_frame(h2c, trailers);
+                ngx_http_v2_queue_frame(fn, trailers);
                 stream->queued++;
             }