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 {
}
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,
......
......@@ -273,7 +273,9 @@ QuicConnection::QuicConnection(
goaway_received_(false),
write_error_occurred_(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
<< "Created connection with connection_id: " << connection_id;
framer_.set_visitor(this);
......@@ -2638,12 +2640,46 @@ const QuicTime::Delta QuicConnection::DelayedAckTime() {
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() {
if (queued_packets_.empty() &&
bool application_limited =
queued_packets_.empty() &&
!sent_packet_manager_.HasPendingRetransmissions() &&
!visitor_->WillingAndAbleToWrite()) {
sent_packet_manager_.OnApplicationLimited();
!visitor_->WillingAndAbleToWrite();
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) {
......
......@@ -718,6 +718,13 @@ class QUIC_EXPORT_PRIVATE QuicConnection
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:
// Calls cancel() on all the alarms owned by this connection.
void CancelAllAlarms();
......@@ -772,6 +779,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// If there are no packets to retransmit, does not do anything.
void SendProbingRetransmissions();
// Decides whether to send probing retransmissions, and does so if required.
void MaybeSendProbingRetransmissions();
private:
friend class test::QuicConnectionPeer;
friend class test::PacketSavingConnection;
......@@ -1143,6 +1153,18 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Consecutive number of sent packets which have 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);
};
......
......@@ -45,9 +45,11 @@ using testing::_;
using testing::AnyNumber;
using testing::AtLeast;
using testing::DoAll;
using testing::Ge;
using testing::InSequence;
using testing::Invoke;
using testing::InvokeWithoutArgs;
using testing::Lt;
using testing::Ref;
using testing::Return;
using testing::SaveArg;
......@@ -5489,6 +5491,48 @@ TEST_P(QuicConnectionTest, NotBecomeApplicationLimitedDueToWriteBlock) {
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) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Send an ack by simulating delayed ack alarm firing.
......
......@@ -601,7 +601,7 @@ bool QuicSentPacketManager::MaybeRetransmitOldestPacket(TransmissionType type) {
MarkForRetransmission(packet_number, type);
return true;
}
QUIC_DLOG(ERROR)
QUIC_DVLOG(1)
<< "No retransmittable packets, so RetransmitOldestPacket failed.";
return false;
}
......
......@@ -235,6 +235,8 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
return largest_packet_peer_knows_is_acked_;
}
bool handshake_confirmed() const { return handshake_confirmed_; }
private:
friend class test::QuicConnectionPeer;
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