Do not instantiate QpackSendStream if qpack_maximum_dynamic_table_capacity_ is 0 in QuicSpdySession. This change saves up to 4K memory per QUIC connection (from 2 QpackSendStream and 2 QpackReceiveStream) when QPACK dynamic table is disabled. Protected by FLAGS_quic_reloadable_flag_quic_not_instantiate_unused_qpack_send_stream. PiperOrigin-RevId: 852984965
diff --git a/quiche/common/quiche_feature_flags_list.h b/quiche/common/quiche_feature_flags_list.h index aa47aa2..7b26e5d 100755 --- a/quiche/common/quiche_feature_flags_list.h +++ b/quiche/common/quiche_feature_flags_list.h
@@ -49,6 +49,7 @@ QUICHE_FLAG(bool, quiche_reloadable_flag_quic_no_path_degrading_before_handshake_confirmed, true, true, "If true, an endpoint does not detect path degrading or blackholing until handshake gets confirmed.") QUICHE_FLAG(bool, quiche_reloadable_flag_quic_no_write_control_frame_upon_connection_close, false, true, "If trrue, early return before write control frame in OnCanWrite() if the connection is already closed.") QUICHE_FLAG(bool, quiche_reloadable_flag_quic_no_write_control_frame_upon_connection_close2, false, true, "If true, QuicSession will block outgoing control frames when the connection is closed.") +QUICHE_FLAG(bool, quiche_reloadable_flag_quic_not_instantiate_unused_qpack_send_stream, false, false, "When qpack_maximum_dynamic_table_capacity is zero, don't bother to instantiate the unused QpackSendStream.") QUICHE_FLAG(bool, quiche_reloadable_flag_quic_notify_ack_listener_earlier, true, true, "If true, call QuicAckListenerInterface::OnPacketAcked() before moving the stream to closed stream list.") QUICHE_FLAG(bool, quiche_reloadable_flag_quic_notify_stream_soon_to_destroy, true, true, "If true, notify each QUIC stream before it gets destroyed and update ACK listener before that.") QUICHE_FLAG(bool, quiche_reloadable_flag_quic_on_packet_header_return_connected, false, true, "If true, QuicConnection::OnPacketHeader will return connected_ at the end of the function.")
diff --git a/quiche/quic/core/http/quic_spdy_session.cc b/quiche/quic/core/http/quic_spdy_session.cc index 479abfa..227294c 100644 --- a/quiche/quic/core/http/quic_spdy_session.cc +++ b/quiche/quic/core/http/quic_spdy_session.cc
@@ -1633,6 +1633,16 @@ } } + // When qpack_maximum_dynamic_table_capacity_ is zero, decoder's dynamic table + // capacity is always zero and encoder's dynamic table capacity is MIN(0, + // SETTINGS_QPACK_MAX_TABLE_CAPACITY from peer) = 0. Hence, we don't need to + // instantiate qpack send streams for both decoder and encoder. + if (GetQuicheReloadableFlag(quic_not_instantiate_unused_qpack_send_stream) && + qpack_maximum_dynamic_table_capacity_ == 0) { + QUICHE_RELOADABLE_FLAG_COUNT(quic_not_instantiate_unused_qpack_send_stream); + return; + } + if (!qpack_decoder_send_stream_ && CanOpenNextOutgoingUnidirectionalStream()) { auto decoder_send = std::make_unique<QpackSendStream>(
diff --git a/quiche/quic/core/http/quic_spdy_session_test.cc b/quiche/quic/core/http/quic_spdy_session_test.cc index e99c3df..6a39fe3 100644 --- a/quiche/quic/core/http/quic_spdy_session_test.cc +++ b/quiche/quic/core/http/quic_spdy_session_test.cc
@@ -2105,6 +2105,14 @@ QpackEncoderPeer::header_table(qpack_encoder); EXPECT_EQ(0, encoder_header_table->dynamic_table_capacity()); EXPECT_EQ(capacity, encoder_header_table->maximum_dynamic_table_capacity()); + if (GetQuicReloadableFlag(quic_not_instantiate_unused_qpack_send_stream)) { + EXPECT_EQ(nullptr, QuicSpdySessionPeer::GetQpackDecoderSendStream( + &session_.value())); + + } else { + EXPECT_NE(nullptr, QuicSpdySessionPeer::GetQpackDecoderSendStream( + &session_.value())); + } // Verify that the advertised capacity is 0. SettingsFrame outgoing_settings = session_->settings(); @@ -2659,6 +2667,13 @@ QpackEncoderPeer::header_table(qpack_encoder); EXPECT_EQ(capacity, encoder_header_table->maximum_dynamic_table_capacity()); EXPECT_EQ(0, encoder_header_table->dynamic_table_capacity()); + if (GetQuicheReloadableFlag(quic_not_instantiate_unused_qpack_send_stream)) { + EXPECT_EQ(nullptr, QuicSpdySessionPeer::GetQpackDecoderSendStream( + &session_.value())); + } else { + EXPECT_NE(nullptr, QuicSpdySessionPeer::GetQpackDecoderSendStream( + &session_.value())); + } // Verify that the advertised capacity is 0. SettingsFrame outgoing_settings = session_->settings();