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) {