Index: net/quic/quic_sent_packet_manager.cc |
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc |
index f2c514b4bcc0b09891ab4413d256e9ac9279be26..20256cfcaecaffd6812bbc36cdfc34f94eddc0c5 100644 |
--- a/net/quic/quic_sent_packet_manager.cc |
+++ b/net/quic/quic_sent_packet_manager.cc |
@@ -32,7 +32,10 @@ static const int64 kDefaultRetransmissionTimeMs = 500; |
// support a higher or lower value. |
static const int64 kMinRetransmissionTimeMs = 200; |
static const int64 kMaxRetransmissionTimeMs = 60000; |
+// Maximum number of exponential backoffs used for RTO timeouts. |
static const size_t kMaxRetransmissions = 10; |
+// Maximum number of packets retransmitted upon an RTO. |
+static const size_t kMaxRetransmissionsOnTimeout = 2; |
// Ensure the handshake timer isnt't faster than 10ms. |
// This limits the tenth retransmitted packet to 10s after the initial CHLO. |
@@ -232,6 +235,17 @@ void QuicSentPacketManager::OnIncomingAck(const QuicAckFrame& ack_frame, |
// Anytime we are making forward progress and have a new RTT estimate, reset |
// the backoff counters. |
if (rtt_updated) { |
+ if (FLAGS_quic_use_new_rto && consecutive_rto_count_ > 0) { |
+ // If the ack acknowledges data sent prior to the RTO, |
+ // the RTO was spurious. |
+ if (ack_frame.largest_observed < first_rto_transmission_) { |
+ // Replace SRTT with latest_rtt and increase the variance to prevent |
+ // a spurious RTO from happening again. |
+ rtt_stats_.ExpireSmoothedMetrics(); |
+ } else { |
+ send_algorithm_->OnRetransmissionTimeout(true); |
+ } |
+ } |
// Reset all retransmit counters any time a new packet is acked. |
consecutive_rto_count_ = 0; |
consecutive_tlp_count_ = 0; |
@@ -365,7 +379,10 @@ void QuicSentPacketManager::MarkForRetransmission( |
const TransmissionInfo& transmission_info = |
unacked_packets_.GetTransmissionInfo(sequence_number); |
LOG_IF(DFATAL, transmission_info.retransmittable_frames == nullptr); |
- if (transmission_type != TLP_RETRANSMISSION) { |
+ // Both TLP and the new RTO leave the packets in flight and let the loss |
+ // detection decide if packets are lost. |
+ if (transmission_type != TLP_RETRANSMISSION && |
+ (!FLAGS_quic_use_new_rto || transmission_type != RTO_RETRANSMISSION)) { |
unacked_packets_.RemoveFromInFlight(sequence_number); |
} |
// TODO(ianswett): Currently the RTO can fire while there are pending NACK |
@@ -380,7 +397,8 @@ void QuicSentPacketManager::MarkForRetransmission( |
void QuicSentPacketManager::RecordSpuriousRetransmissions( |
const SequenceNumberList& all_transmissions, |
QuicPacketSequenceNumber acked_sequence_number) { |
- if (acked_sequence_number < first_rto_transmission_) { |
+ if (!FLAGS_quic_use_new_rto && |
+ acked_sequence_number < first_rto_transmission_) { |
// Cancel all pending RTO transmissions and restore their in flight status. |
// Replace SRTT with latest_rtt and increase the variance to prevent |
// a spurious RTO from happening again. |
@@ -405,9 +423,8 @@ void QuicSentPacketManager::RecordSpuriousRetransmissions( |
stats_->bytes_spuriously_retransmitted += retransmit_info.bytes_sent; |
++stats_->packets_spuriously_retransmitted; |
if (debug_delegate_ != nullptr) { |
- debug_delegate_->OnSpuriousPacketRetransmition( |
- retransmit_info.transmission_type, |
- retransmit_info.bytes_sent); |
+ debug_delegate_->OnSpuriousPacketRetransmission( |
+ retransmit_info.transmission_type, retransmit_info.bytes_sent); |
} |
} |
} |
@@ -535,7 +552,8 @@ bool QuicSentPacketManager::OnPacketSent( |
LOG_IF(DFATAL, bytes == 0) << "Cannot send empty packets."; |
if (original_sequence_number == 0) { |
- if (serialized_packet->retransmittable_frames) { |
+ if (!FLAGS_quic_ack_notifier_informed_on_serialized && |
+ serialized_packet->retransmittable_frames) { |
ack_notifier_manager_.OnSerializedPacket(*serialized_packet); |
} |
} else { |
@@ -623,7 +641,11 @@ void QuicSentPacketManager::OnRetransmissionTimeout() { |
return; |
case RTO_MODE: |
++stats_->rto_count; |
- RetransmitAllPackets(); |
+ if (FLAGS_quic_use_new_rto) { |
+ RetransmitRtoPackets(); |
+ } else { |
+ RetransmitAllPackets(); |
+ } |
return; |
} |
} |
@@ -669,6 +691,33 @@ bool QuicSentPacketManager::MaybeRetransmitTailLossProbe() { |
return false; |
} |
+void QuicSentPacketManager::RetransmitRtoPackets() { |
+ LOG_IF(DFATAL, pending_timer_transmission_count_ > 0) |
+ << "Retransmissions already queued:" << pending_timer_transmission_count_; |
+ // Mark two packets for retransmission. |
+ QuicPacketSequenceNumber sequence_number = unacked_packets_.GetLeastUnacked(); |
+ for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin(); |
+ it != unacked_packets_.end(); ++it, ++sequence_number) { |
+ if (it->retransmittable_frames != nullptr && |
+ pending_timer_transmission_count_ < kMaxRetransmissionsOnTimeout) { |
+ MarkForRetransmission(sequence_number, RTO_RETRANSMISSION); |
+ ++pending_timer_transmission_count_; |
+ } |
+ // Abandon non-retransmittable data that's in flight to ensure it doesn't |
+ // fill up the congestion window. |
+ if (it->retransmittable_frames == nullptr && it->in_flight && |
+ it->all_transmissions == nullptr) { |
+ unacked_packets_.RemoveFromInFlight(sequence_number); |
+ } |
+ } |
+ if (pending_timer_transmission_count_ > 0) { |
+ if (consecutive_rto_count_ == 0) { |
+ first_rto_transmission_ = unacked_packets_.largest_sent_packet() + 1; |
+ } |
+ ++consecutive_rto_count_; |
+ } |
+} |
+ |
void QuicSentPacketManager::RetransmitAllPackets() { |
DVLOG(1) << "RetransmitAllPackets() called with " |
<< unacked_packets_.GetNumUnackedPacketsDebugOnly() |
@@ -946,6 +995,11 @@ QuicPacketCount QuicSentPacketManager::GetSlowStartThresholdInTcpMss() const { |
return send_algorithm_->GetSlowStartThreshold() / kDefaultTCPMSS; |
} |
+void QuicSentPacketManager::OnSerializedPacket( |
+ const SerializedPacket& serialized_packet) { |
+ ack_notifier_manager_.OnSerializedPacket(serialized_packet); |
+} |
+ |
void QuicSentPacketManager::EnablePacing() { |
if (using_pacing_) { |
return; |