gfe-relnote: In QUIC, enable round robin scheduling. Protected by gfe2_reloadable_flag_quic_enable_rr_write_schduler. PiperOrigin-RevId: 269414968 Change-Id: Id2e97b3eea61cbd0f8c140f970715f21af90c156
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h index 8adf0ae..5f98345 100644 --- a/quic/core/crypto/crypto_protocol.h +++ b/quic/core/crypto/crypto_protocol.h
@@ -226,6 +226,7 @@ // has the highest priority. const QuicTag kLIFO = TAG('L', 'I', 'F', 'O'); // Stream with the largest ID // has the highest priority. +const QuicTag kRRWS = TAG('R', 'R', 'W', 'S'); // Round robin write scheduling. // Proof types (i.e. certificate types) // NOTE: although it would be silly to do so, specifying both kX509 and kX59R
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc index 9b812de..9ede3f8 100644 --- a/quic/core/quic_session.cc +++ b/quic/core/quic_session.cc
@@ -93,7 +93,8 @@ use_http2_priority_write_scheduler_(false), is_configured_(false), num_expected_unidirectional_static_streams_( - num_expected_unidirectional_static_streams) { + num_expected_unidirectional_static_streams), + enable_round_robin_scheduling_(false) { closed_streams_clean_up_alarm_ = QuicWrapUnique<QuicAlarm>(connection_->alarm_factory()->CreateAlarm( new ClosedStreamsCleanUpDelegate(this))); @@ -1000,6 +1001,12 @@ spdy::WriteSchedulerType::LIFO, transport_version())) { QUIC_RELOADABLE_FLAG_COUNT(quic_enable_lifo_write_scheduler); } + } else if (GetQuicReloadableFlag(quic_enable_rr_write_scheduler) && + ContainsQuicTag(config_.ReceivedConnectionOptions(), kRRWS) && + write_blocked_streams_.scheduler_type() == + spdy::WriteSchedulerType::SPDY) { + QUIC_RELOADABLE_FLAG_COUNT(quic_enable_rr_write_scheduler); + enable_round_robin_scheduling_ = true; } } @@ -1157,6 +1164,13 @@ QuicStreamId id, bool is_static, const spdy::SpdyStreamPrecedence& precedence) { + if (enable_round_robin_scheduling_) { + // Ignore provided precedence, instead, put all streams at the same priority + // bucket. + write_blocked_streams()->RegisterStream( + id, is_static, spdy::SpdyStreamPrecedence(spdy::kV3LowestPriority)); + return; + } write_blocked_streams()->RegisterStream(id, is_static, precedence); } @@ -1167,6 +1181,10 @@ void QuicSession::UpdateStreamPriority( QuicStreamId id, const spdy::SpdyStreamPrecedence& new_precedence) { + if (enable_round_robin_scheduling_) { + // Ignore updated precedence. + return; + } write_blocked_streams()->UpdateStreamPriority(id, new_precedence); }
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h index 5250f9b..6fb4c8d 100644 --- a/quic/core/quic_session.h +++ b/quic/core/quic_session.h
@@ -756,6 +756,9 @@ // The number of expected static streams. QuicStreamCount num_expected_unidirectional_static_streams_; + + // If true, enables round robin scheduling. + bool enable_round_robin_scheduling_; }; } // namespace quic
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc index f7ab416..004af59 100644 --- a/quic/core/quic_session_test.cc +++ b/quic/core/quic_session_test.cc
@@ -1000,6 +1000,50 @@ session_.OnCanWrite(); } +TEST_P(QuicSessionTestServer, RoundRobinScheduling) { + if (VersionHasIetfQuicFrames(GetParam().transport_version)) { + return; + } + SetQuicReloadableFlag(quic_enable_rr_write_scheduler, true); + QuicTagVector copt; + copt.push_back(kRRWS); + QuicConfigPeer::SetReceivedConnectionOptions(session_.config(), copt); + session_.OnConfigNegotiated(); + + session_.set_writev_consumes_all_data(true); + TestStream* stream2 = session_.CreateOutgoingBidirectionalStream(); + TestStream* stream4 = session_.CreateOutgoingBidirectionalStream(); + TestStream* stream6 = session_.CreateOutgoingBidirectionalStream(); + + session_.set_writev_consumes_all_data(true); + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + session_.MarkConnectionLevelWriteBlocked(stream4->id()); + session_.MarkConnectionLevelWriteBlocked(stream6->id()); + + // Verify streams are scheduled round robin. + InSequence s; + EXPECT_CALL(*stream2, OnCanWrite()); + EXPECT_CALL(*stream4, OnCanWrite()); + EXPECT_CALL(*stream6, OnCanWrite()); + session_.OnCanWrite(); + + /* 2, 4, 6, 8 */ + TestStream* stream8 = session_.CreateOutgoingBidirectionalStream(); + + // Verify updated priority is ignored. + stream4->SetPriority(spdy::SpdyStreamPrecedence(spdy::kV3HighestPriority)); + session_.MarkConnectionLevelWriteBlocked(stream8->id()); + session_.MarkConnectionLevelWriteBlocked(stream4->id()); + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + session_.MarkConnectionLevelWriteBlocked(stream6->id()); + + EXPECT_CALL(*stream8, OnCanWrite()); + EXPECT_CALL(*stream4, OnCanWrite()); + EXPECT_CALL(*stream2, OnCanWrite()); + EXPECT_CALL(*stream6, OnCanWrite()); + session_.OnCanWrite(); +} + TEST_P(QuicSessionTestServer, OnCanWriteBundlesStreams) { // Encryption needs to be established before data can be sent. CryptoHandshakeMessage msg;
diff --git a/quic/core/quic_write_blocked_list.h b/quic/core/quic_write_blocked_list.h index 72ebc05..f77a2cd 100644 --- a/quic/core/quic_write_blocked_list.h +++ b/quic/core/quic_write_blocked_list.h
@@ -210,6 +210,8 @@ return priority_write_scheduler_->IsStreamReady(stream_id); } + spdy::WriteSchedulerType scheduler_type() const { return scheduler_type_; } + private: bool PrecedenceMatchesSchedulerType( const spdy::SpdyStreamPrecedence& precedence) {