Commit 574a4c17 authored by Victor Vasiliev's avatar Victor Vasiliev Committed by Commit Bot

Add a feature to QuicConnection in which it sends probing retransmissions...

Add a feature to QuicConnection in which it sends probing retransmissions whenever it becomes application limited.

This also corrects the BBR behavior for determining when to probe.

Merge internal change: 174041573

R=rch@chromium.org

Bug: 
Change-Id: I7bdc95af25d83da37ad10f167da33a92fa991f2a
Reviewed-on: https://chromium-review.googlesource.com/777589Reviewed-by: default avatarRyan Hamilton <rch@chromium.org>
Commit-Queue: Victor Vasiliev <vasilvv@chromium.org>
Cr-Commit-Position: refs/heads/master@{#517708}
parent dee5d806
...@@ -197,7 +197,7 @@ bool BbrSender::InRecovery() const { ...@@ -197,7 +197,7 @@ bool BbrSender::InRecovery() const {
} }
bool BbrSender::IsProbingForMoreBandwidth() const { bool BbrSender::IsProbingForMoreBandwidth() const {
return mode_ == PROBE_BW && pacing_gain_ > 1; return (mode_ == PROBE_BW && pacing_gain_ > 1) || mode_ == STARTUP;
} }
void BbrSender::SetFromConfig(const QuicConfig& config, void BbrSender::SetFromConfig(const QuicConfig& config,
......
...@@ -273,7 +273,9 @@ QuicConnection::QuicConnection( ...@@ -273,7 +273,9 @@ QuicConnection::QuicConnection(
goaway_received_(false), goaway_received_(false),
write_error_occurred_(false), write_error_occurred_(false),
no_stop_waiting_frames_(false), no_stop_waiting_frames_(false),
consecutive_num_packets_with_no_retransmittable_frames_(0) { consecutive_num_packets_with_no_retransmittable_frames_(0),
fill_up_link_during_probing_(false),
probing_retransmission_pending_(false) {
QUIC_DLOG(INFO) << ENDPOINT QUIC_DLOG(INFO) << ENDPOINT
<< "Created connection with connection_id: " << connection_id; << "Created connection with connection_id: " << connection_id;
framer_.set_visitor(this); framer_.set_visitor(this);
...@@ -2638,12 +2640,46 @@ const QuicTime::Delta QuicConnection::DelayedAckTime() { ...@@ -2638,12 +2640,46 @@ const QuicTime::Delta QuicConnection::DelayedAckTime() {
std::min(kMaxDelayedAckTimeMs, kMinRetransmissionTimeMs / 2)); std::min(kMaxDelayedAckTimeMs, kMinRetransmissionTimeMs / 2));
} }
void QuicConnection::MaybeSendProbingRetransmissions() {
DCHECK(fill_up_link_during_probing_);
if (!sent_packet_manager_.handshake_confirmed()) {
return;
}
if (!sent_packet_manager_.GetSendAlgorithm()->IsProbingForMoreBandwidth()) {
return;
}
if (probing_retransmission_pending_) {
QUIC_BUG << "MaybeSendProbingRetransmissions is called while another call "
"to it is already in progress";
return;
}
probing_retransmission_pending_ = true;
SendProbingRetransmissions();
probing_retransmission_pending_ = false;
}
void QuicConnection::CheckIfApplicationLimited() { void QuicConnection::CheckIfApplicationLimited() {
if (queued_packets_.empty() && bool application_limited =
queued_packets_.empty() &&
!sent_packet_manager_.HasPendingRetransmissions() && !sent_packet_manager_.HasPendingRetransmissions() &&
!visitor_->WillingAndAbleToWrite()) { !visitor_->WillingAndAbleToWrite();
sent_packet_manager_.OnApplicationLimited();
if (!application_limited) {
return;
} }
if (fill_up_link_during_probing_) {
MaybeSendProbingRetransmissions();
if (!CanWrite(HAS_RETRANSMITTABLE_DATA)) {
return;
}
}
sent_packet_manager_.OnApplicationLimited();
} }
void QuicConnection::UpdatePacketContent(PacketContent type) { void QuicConnection::UpdatePacketContent(PacketContent type) {
......
...@@ -718,6 +718,13 @@ class QUIC_EXPORT_PRIVATE QuicConnection ...@@ -718,6 +718,13 @@ class QUIC_EXPORT_PRIVATE QuicConnection
return last_packet_source_address_; return last_packet_source_address_;
} }
bool fill_up_link_during_probing() const {
return fill_up_link_during_probing_;
}
void set_fill_up_link_during_probing(bool new_value) {
fill_up_link_during_probing_ = new_value;
}
protected: protected:
// Calls cancel() on all the alarms owned by this connection. // Calls cancel() on all the alarms owned by this connection.
void CancelAllAlarms(); void CancelAllAlarms();
...@@ -772,6 +779,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection ...@@ -772,6 +779,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// If there are no packets to retransmit, does not do anything. // If there are no packets to retransmit, does not do anything.
void SendProbingRetransmissions(); void SendProbingRetransmissions();
// Decides whether to send probing retransmissions, and does so if required.
void MaybeSendProbingRetransmissions();
private: private:
friend class test::QuicConnectionPeer; friend class test::QuicConnectionPeer;
friend class test::PacketSavingConnection; friend class test::PacketSavingConnection;
...@@ -1143,6 +1153,18 @@ class QUIC_EXPORT_PRIVATE QuicConnection ...@@ -1143,6 +1153,18 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Consecutive number of sent packets which have no retransmittable frames. // Consecutive number of sent packets which have no retransmittable frames.
size_t consecutive_num_packets_with_no_retransmittable_frames_; size_t consecutive_num_packets_with_no_retransmittable_frames_;
// If true, the connection will fill up the pipe with extra data whenever the
// congestion controller needs it in order to make a bandwidth estimate. This
// is useful if the application pesistently underutilizes the link, but still
// relies on having a reasonable bandwidth estimate from the connection, e.g.
// for real time applications.
bool fill_up_link_during_probing_;
// If true, the probing retransmission will not be started again. This is
// used to safeguard against an accidental tail recursion in probing
// retransmission code.
bool probing_retransmission_pending_;
DISALLOW_COPY_AND_ASSIGN(QuicConnection); DISALLOW_COPY_AND_ASSIGN(QuicConnection);
}; };
......
...@@ -45,9 +45,11 @@ using testing::_; ...@@ -45,9 +45,11 @@ using testing::_;
using testing::AnyNumber; using testing::AnyNumber;
using testing::AtLeast; using testing::AtLeast;
using testing::DoAll; using testing::DoAll;
using testing::Ge;
using testing::InSequence; using testing::InSequence;
using testing::Invoke; using testing::Invoke;
using testing::InvokeWithoutArgs; using testing::InvokeWithoutArgs;
using testing::Lt;
using testing::Ref; using testing::Ref;
using testing::Return; using testing::Return;
using testing::SaveArg; using testing::SaveArg;
...@@ -5489,6 +5491,48 @@ TEST_P(QuicConnectionTest, NotBecomeApplicationLimitedDueToWriteBlock) { ...@@ -5489,6 +5491,48 @@ TEST_P(QuicConnectionTest, NotBecomeApplicationLimitedDueToWriteBlock) {
connection_.SendStreamData3(); connection_.SendStreamData3();
} }
// Test the mode in which the link is filled up with probing retransmissions if
// the connection becomes application-limited.
TEST_P(QuicConnectionTest, SendDataWhenApplicationLimited) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(*send_algorithm_, IsProbingForMoreBandwidth())
.WillRepeatedly(Return(true));
{
InSequence seq;
EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillRepeatedly(Return(true));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
EXPECT_CALL(visitor_, WillingAndAbleToWrite())
.WillRepeatedly(Return(false));
}
// Fix congestion window to be 2000 bytes.
EXPECT_CALL(*send_algorithm_, CanSend(Ge(2000u)))
.WillRepeatedly(Return(false));
EXPECT_CALL(*send_algorithm_, CanSend(Lt(2000u)))
.WillRepeatedly(Return(true));
EXPECT_CALL(*send_algorithm_, OnApplicationLimited(_)).Times(0);
ASSERT_EQ(0u, connection_.GetStats().packets_sent);
connection_.set_fill_up_link_during_probing(true);
connection_.OnHandshakeComplete();
connection_.SendStreamData3();
// Since the frame data we send is small, we expect a lot of packets from a
// 2000 byte window.
EXPECT_GT(connection_.GetStats().packets_sent, 10u);
// Acknowledge all packets sent, except for the last one.
QuicAckFrame ack = InitAckFrame(
connection_.sent_packet_manager().GetLargestSentPacket() - 1);
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
// Ensure that since we no longer have retransmittable bytes in flight, this
// will not cause any responses to be sent.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
EXPECT_CALL(*send_algorithm_, OnApplicationLimited(_)).Times(1);
ProcessAckPacket(&ack);
}
TEST_P(QuicConnectionTest, DonotForceSendingAckOnPacketTooLarge) { TEST_P(QuicConnectionTest, DonotForceSendingAckOnPacketTooLarge) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Send an ack by simulating delayed ack alarm firing. // Send an ack by simulating delayed ack alarm firing.
......
...@@ -601,7 +601,7 @@ bool QuicSentPacketManager::MaybeRetransmitOldestPacket(TransmissionType type) { ...@@ -601,7 +601,7 @@ bool QuicSentPacketManager::MaybeRetransmitOldestPacket(TransmissionType type) {
MarkForRetransmission(packet_number, type); MarkForRetransmission(packet_number, type);
return true; return true;
} }
QUIC_DLOG(ERROR) QUIC_DVLOG(1)
<< "No retransmittable packets, so RetransmitOldestPacket failed."; << "No retransmittable packets, so RetransmitOldestPacket failed.";
return false; return false;
} }
......
...@@ -235,6 +235,8 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { ...@@ -235,6 +235,8 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
return largest_packet_peer_knows_is_acked_; return largest_packet_peer_knows_is_acked_;
} }
bool handshake_confirmed() const { return handshake_confirmed_; }
private: private:
friend class test::QuicConnectionPeer; friend class test::QuicConnectionPeer;
friend class test::QuicSentPacketManagerPeer; friend class test::QuicSentPacketManagerPeer;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment