| Index: net/quic/quic_unacked_packet_map.cc
|
| diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc
|
| index 0640c29940c1a5d0d5415c39575b1fb450fd70a1..359f2d190b1c77a533eb87569b64f8d010469c3d 100644
|
| --- a/net/quic/quic_unacked_packet_map.cc
|
| +++ b/net/quic/quic_unacked_packet_map.cc
|
| @@ -16,20 +16,17 @@
|
| QuicUnackedPacketMap::QuicUnackedPacketMap()
|
| : largest_sent_packet_(0),
|
| largest_observed_(0),
|
| - least_unacked_(1),
|
| bytes_in_flight_(0),
|
| pending_crypto_packet_count_(0) {
|
| }
|
|
|
| QuicUnackedPacketMap::~QuicUnackedPacketMap() {
|
| - QuicPacketSequenceNumber index = least_unacked_;
|
| for (UnackedPacketMap::iterator it = unacked_packets_.begin();
|
| - it != unacked_packets_.end(); ++it, ++index) {
|
| - delete it->retransmittable_frames;
|
| + it != unacked_packets_.end(); ++it) {
|
| + delete it->second.retransmittable_frames;
|
| // Only delete all_transmissions once, for the newest packet.
|
| - if (it->all_transmissions != NULL &&
|
| - index == *it->all_transmissions->rbegin()) {
|
| - delete it->all_transmissions;
|
| + if (it->first == *it->second.all_transmissions->rbegin()) {
|
| + delete it->second.all_transmissions;
|
| }
|
| }
|
| }
|
| @@ -38,11 +35,19 @@
|
| // sent in order and the connection tracks RetransmittableFrames for longer.
|
| void QuicUnackedPacketMap::AddPacket(
|
| const SerializedPacket& serialized_packet) {
|
| - DCHECK_EQ(least_unacked_ + unacked_packets_.size(),
|
| - serialized_packet.sequence_number);
|
| - unacked_packets_.push_back(
|
| + if (!unacked_packets_.empty()) {
|
| + bool is_old_packet = unacked_packets_.rbegin()->first >=
|
| + serialized_packet.sequence_number;
|
| + LOG_IF(DFATAL, is_old_packet) << "Old packet serialized: "
|
| + << serialized_packet.sequence_number
|
| + << " vs: "
|
| + << unacked_packets_.rbegin()->first;
|
| + }
|
| +
|
| + unacked_packets_[serialized_packet.sequence_number] =
|
| TransmissionInfo(serialized_packet.retransmittable_frames,
|
| - serialized_packet.sequence_number_length));
|
| + serialized_packet.sequence_number,
|
| + serialized_packet.sequence_number_length);
|
| if (serialized_packet.retransmittable_frames != NULL &&
|
| serialized_packet.retransmittable_frames->HasCryptoHandshake()
|
| == IS_HANDSHAKE) {
|
| @@ -50,28 +55,17 @@
|
| }
|
| }
|
|
|
| -void QuicUnackedPacketMap::RemoveObsoletePackets() {
|
| - while (!unacked_packets_.empty()) {
|
| - if (!IsPacketUseless(least_unacked_, unacked_packets_.front())) {
|
| - break;
|
| - }
|
| - delete unacked_packets_.front().all_transmissions;
|
| - unacked_packets_.pop_front();
|
| - ++least_unacked_;
|
| - }
|
| -}
|
| -
|
| void QuicUnackedPacketMap::OnRetransmittedPacket(
|
| QuicPacketSequenceNumber old_sequence_number,
|
| QuicPacketSequenceNumber new_sequence_number,
|
| TransmissionType transmission_type) {
|
| - DCHECK_GE(old_sequence_number, least_unacked_);
|
| - DCHECK_LT(old_sequence_number, least_unacked_ + unacked_packets_.size());
|
| - DCHECK_EQ(least_unacked_ + unacked_packets_.size(), new_sequence_number);
|
| + DCHECK(ContainsKey(unacked_packets_, old_sequence_number));
|
| + DCHECK(unacked_packets_.empty() ||
|
| + unacked_packets_.rbegin()->first < new_sequence_number);
|
|
|
| // TODO(ianswett): Discard and lose the packet lazily instead of immediately.
|
| TransmissionInfo* transmission_info =
|
| - &unacked_packets_.at(old_sequence_number - least_unacked_);
|
| + FindOrNull(unacked_packets_, old_sequence_number);
|
| RetransmittableFrames* frames = transmission_info->retransmittable_frames;
|
| LOG_IF(DFATAL, frames == NULL) << "Attempt to retransmit packet with no "
|
| << "retransmittable frames: "
|
| @@ -82,86 +76,97 @@
|
| transmission_info->retransmittable_frames = NULL;
|
| // Only keep one transmission older than largest observed, because only the
|
| // most recent is expected to possibly be a spurious retransmission.
|
| - if (transmission_info->all_transmissions != NULL &&
|
| + if (transmission_info->all_transmissions->size() > 1 &&
|
| *(++transmission_info->all_transmissions->begin()) < largest_observed_) {
|
| QuicPacketSequenceNumber old_transmission =
|
| *transmission_info->all_transmissions->begin();
|
| - TransmissionInfo* old_info =
|
| - &unacked_packets_[old_transmission - least_unacked_];
|
| + TransmissionInfo* old_transmission_info =
|
| + FindOrNull(unacked_packets_, old_transmission);
|
| // Don't remove old packets if they're still in flight.
|
| - if (!old_info->in_flight) {
|
| - old_info->all_transmissions->pop_front();
|
| - // This will cause the packet be removed in RemoveObsoletePackets.
|
| - old_info->all_transmissions = NULL;
|
| - }
|
| - }
|
| - if (transmission_info->all_transmissions == NULL) {
|
| - transmission_info->all_transmissions = new SequenceNumberList();
|
| - transmission_info->all_transmissions->push_back(old_sequence_number);
|
| - }
|
| - transmission_info->all_transmissions->push_back(new_sequence_number);
|
| - unacked_packets_.push_back(
|
| + if (old_transmission_info == NULL || !old_transmission_info->in_flight) {
|
| + transmission_info->all_transmissions->erase(old_transmission);
|
| + unacked_packets_.erase(old_transmission);
|
| + }
|
| + }
|
| + unacked_packets_[new_sequence_number] =
|
| TransmissionInfo(frames,
|
| + new_sequence_number,
|
| transmission_info->sequence_number_length,
|
| transmission_type,
|
| - transmission_info->all_transmissions));
|
| + transmission_info->all_transmissions);
|
| }
|
|
|
| void QuicUnackedPacketMap::ClearPreviousRetransmissions(size_t num_to_clear) {
|
| - while (!unacked_packets_.empty() && num_to_clear > 0) {
|
| + UnackedPacketMap::iterator it = unacked_packets_.begin();
|
| + while (it != unacked_packets_.end() && num_to_clear > 0) {
|
| + QuicPacketSequenceNumber sequence_number = it->first;
|
| // If this packet is in flight, or has retransmittable data, then there is
|
| // no point in clearing out any further packets, because they would not
|
| // affect the high water mark.
|
| - TransmissionInfo* info = &unacked_packets_.front();
|
| - if (info->in_flight || info->retransmittable_frames != NULL) {
|
| + if (it->second.in_flight || it->second.retransmittable_frames != NULL) {
|
| break;
|
| }
|
|
|
| - info->all_transmissions->pop_front();
|
| - LOG_IF(DFATAL, info->all_transmissions->empty())
|
| + it->second.all_transmissions->erase(sequence_number);
|
| + LOG_IF(DFATAL, it->second.all_transmissions->empty())
|
| << "Previous retransmissions must have a newer transmission.";
|
| - unacked_packets_.pop_front();
|
| - ++least_unacked_;
|
| + ++it;
|
| + unacked_packets_.erase(sequence_number);
|
| --num_to_clear;
|
| }
|
| }
|
|
|
| bool QuicUnackedPacketMap::HasRetransmittableFrames(
|
| QuicPacketSequenceNumber sequence_number) const {
|
| - DCHECK_GE(sequence_number, least_unacked_);
|
| - DCHECK_LT(sequence_number, least_unacked_ + unacked_packets_.size());
|
| - return unacked_packets_[
|
| - sequence_number - least_unacked_].retransmittable_frames != NULL;
|
| + const TransmissionInfo* transmission_info =
|
| + FindOrNull(unacked_packets_, sequence_number);
|
| + if (transmission_info == NULL) {
|
| + return false;
|
| + }
|
| +
|
| + return transmission_info->retransmittable_frames != NULL;
|
| }
|
|
|
| void QuicUnackedPacketMap::NackPacket(QuicPacketSequenceNumber sequence_number,
|
| size_t min_nacks) {
|
| - DCHECK_GE(sequence_number, least_unacked_);
|
| - DCHECK_LT(sequence_number, least_unacked_ + unacked_packets_.size());
|
| - unacked_packets_[sequence_number - least_unacked_].nack_count =
|
| - max(min_nacks,
|
| - unacked_packets_[sequence_number - least_unacked_].nack_count);
|
| + UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number);
|
| + if (it == unacked_packets_.end()) {
|
| + LOG(DFATAL) << "NackPacket called for packet that is not unacked: "
|
| + << sequence_number;
|
| + return;
|
| + }
|
| +
|
| + it->second.nack_count = max(min_nacks, it->second.nack_count);
|
| }
|
|
|
| void QuicUnackedPacketMap::RemoveRetransmittability(
|
| QuicPacketSequenceNumber sequence_number) {
|
| - DCHECK_GE(sequence_number, least_unacked_);
|
| - DCHECK_LT(sequence_number, least_unacked_ + unacked_packets_.size());
|
| - TransmissionInfo* info = &unacked_packets_[sequence_number - least_unacked_];
|
| - SequenceNumberList* all_transmissions = info->all_transmissions;
|
| - if (all_transmissions == NULL) {
|
| - MaybeRemoveRetransmittableFrames(info);
|
| - return;
|
| - }
|
| + UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number);
|
| + if (it == unacked_packets_.end()) {
|
| + DVLOG(1) << "packet is not in unacked_packets: " << sequence_number;
|
| + return;
|
| + }
|
| + SequenceNumberSet* all_transmissions = it->second.all_transmissions;
|
| + // TODO(ianswett): Consider optimizing this for lone packets.
|
| // TODO(ianswett): Consider adding a check to ensure there are retransmittable
|
| // frames associated with this packet.
|
| - for (SequenceNumberList::const_iterator it = all_transmissions->begin();
|
| - it != all_transmissions->end(); ++it) {
|
| - TransmissionInfo* transmission_info =
|
| - &unacked_packets_[*it - least_unacked_];
|
| + for (SequenceNumberSet::reverse_iterator it = all_transmissions->rbegin();
|
| + it != all_transmissions->rend(); ++it) {
|
| + TransmissionInfo* transmission_info = FindOrNull(unacked_packets_, *it);
|
| + if (transmission_info == NULL) {
|
| + LOG(DFATAL) << "All transmissions in all_transmissions must be present "
|
| + << "in the unacked packet map.";
|
| + continue;
|
| + }
|
| MaybeRemoveRetransmittableFrames(transmission_info);
|
| - transmission_info->all_transmissions = NULL;
|
| - }
|
| + if (*it <= largest_observed_ && !transmission_info->in_flight) {
|
| + unacked_packets_.erase(*it);
|
| + } else {
|
| + transmission_info->all_transmissions = new SequenceNumberSet();
|
| + transmission_info->all_transmissions->insert(*it);
|
| + }
|
| + }
|
| +
|
| delete all_transmissions;
|
| }
|
|
|
| @@ -181,36 +186,48 @@
|
| QuicPacketSequenceNumber largest_observed) {
|
| DCHECK_LE(largest_observed_, largest_observed);
|
| largest_observed_ = largest_observed;
|
| + UnackedPacketMap::iterator it = unacked_packets_.begin();
|
| + while (it != unacked_packets_.end() && it->first <= largest_observed_) {
|
| + if (!IsPacketUseless(it)) {
|
| + ++it;
|
| + continue;
|
| + }
|
| + delete it->second.all_transmissions;
|
| + QuicPacketSequenceNumber sequence_number = it->first;
|
| + ++it;
|
| + unacked_packets_.erase(sequence_number);
|
| + }
|
| }
|
|
|
| bool QuicUnackedPacketMap::IsPacketUseless(
|
| - QuicPacketSequenceNumber sequence_number,
|
| - const TransmissionInfo& info) const {
|
| - return sequence_number <= largest_observed_ &&
|
| - !info.in_flight &&
|
| - info.retransmittable_frames == NULL &&
|
| - info.all_transmissions == NULL;
|
| + UnackedPacketMap::const_iterator it) const {
|
| + return it->first <= largest_observed_ &&
|
| + !it->second.in_flight &&
|
| + it->second.retransmittable_frames == NULL &&
|
| + it->second.all_transmissions->size() == 1;
|
| }
|
|
|
| bool QuicUnackedPacketMap::IsUnacked(
|
| QuicPacketSequenceNumber sequence_number) const {
|
| - if (sequence_number < least_unacked_ ||
|
| - sequence_number >= least_unacked_ + unacked_packets_.size()) {
|
| - return false;
|
| - }
|
| - return !IsPacketUseless(sequence_number,
|
| - unacked_packets_[sequence_number - least_unacked_]);
|
| + return ContainsKey(unacked_packets_, sequence_number);
|
| }
|
|
|
| void QuicUnackedPacketMap::RemoveFromInFlight(
|
| QuicPacketSequenceNumber sequence_number) {
|
| - DCHECK_GE(sequence_number, least_unacked_);
|
| - DCHECK_LT(sequence_number, least_unacked_ + unacked_packets_.size());
|
| - TransmissionInfo* info = &unacked_packets_[sequence_number - least_unacked_];
|
| - if (info->in_flight) {
|
| - LOG_IF(DFATAL, bytes_in_flight_ < info->bytes_sent);
|
| - bytes_in_flight_ -= info->bytes_sent;
|
| - info->in_flight = false;
|
| + UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number);
|
| + if (it == unacked_packets_.end()) {
|
| + LOG(DFATAL) << "RemoveFromFlight called for packet that is not unacked: "
|
| + << sequence_number;
|
| + return;
|
| + }
|
| + if (it->second.in_flight) {
|
| + LOG_IF(DFATAL, bytes_in_flight_ < it->second.bytes_sent);
|
| + bytes_in_flight_ -= it->second.bytes_sent;
|
| + it->second.in_flight = false;
|
| + }
|
| + if (IsPacketUseless(it)) {
|
| + delete it->second.all_transmissions;
|
| + unacked_packets_.erase(it);
|
| }
|
| }
|
|
|
| @@ -224,16 +241,16 @@
|
|
|
| const TransmissionInfo& QuicUnackedPacketMap::GetTransmissionInfo(
|
| QuicPacketSequenceNumber sequence_number) const {
|
| - return unacked_packets_[sequence_number - least_unacked_];
|
| + return unacked_packets_.find(sequence_number)->second;
|
| }
|
|
|
| QuicTime QuicUnackedPacketMap::GetLastPacketSentTime() const {
|
| UnackedPacketMap::const_reverse_iterator it = unacked_packets_.rbegin();
|
| while (it != unacked_packets_.rend()) {
|
| - if (it->in_flight) {
|
| - LOG_IF(DFATAL, it->sent_time == QuicTime::Zero())
|
| + if (it->second.in_flight) {
|
| + LOG_IF(DFATAL, it->second.sent_time == QuicTime::Zero())
|
| << "Sent time can never be zero for a packet in flight.";
|
| - return it->sent_time;
|
| + return it->second.sent_time;
|
| }
|
| ++it;
|
| }
|
| @@ -243,33 +260,25 @@
|
|
|
| QuicTime QuicUnackedPacketMap::GetFirstInFlightPacketSentTime() const {
|
| UnackedPacketMap::const_iterator it = unacked_packets_.begin();
|
| - while (it != unacked_packets_.end() && !it->in_flight) {
|
| + while (it != unacked_packets_.end() && !it->second.in_flight) {
|
| ++it;
|
| }
|
| if (it == unacked_packets_.end()) {
|
| LOG(DFATAL) << "GetFirstInFlightPacketSentTime requires in flight packets.";
|
| return QuicTime::Zero();
|
| }
|
| - return it->sent_time;
|
| -}
|
| -
|
| -size_t QuicUnackedPacketMap::GetNumUnackedPacketsDebugOnly() const {
|
| - size_t unacked_packet_count = 0;
|
| - QuicPacketSequenceNumber sequence_number = least_unacked_;
|
| - for (UnackedPacketMap::const_iterator it = unacked_packets_.begin();
|
| - it != unacked_packets_.end(); ++it, ++sequence_number) {
|
| - if (!IsPacketUseless(sequence_number, *it)) {
|
| - ++unacked_packet_count;
|
| - }
|
| - }
|
| - return unacked_packet_count;
|
| + return it->second.sent_time;
|
| +}
|
| +
|
| +size_t QuicUnackedPacketMap::GetNumUnackedPackets() const {
|
| + return unacked_packets_.size();
|
| }
|
|
|
| bool QuicUnackedPacketMap::HasMultipleInFlightPackets() const {
|
| size_t num_in_flight = 0;
|
| for (UnackedPacketMap::const_reverse_iterator it = unacked_packets_.rbegin();
|
| it != unacked_packets_.rend(); ++it) {
|
| - if (it->in_flight) {
|
| + if (it->second.in_flight) {
|
| ++num_in_flight;
|
| }
|
| if (num_in_flight > 1) {
|
| @@ -286,7 +295,7 @@
|
| bool QuicUnackedPacketMap::HasUnackedRetransmittableFrames() const {
|
| for (UnackedPacketMap::const_reverse_iterator it =
|
| unacked_packets_.rbegin(); it != unacked_packets_.rend(); ++it) {
|
| - if (it->in_flight && it->retransmittable_frames) {
|
| + if (it->second.in_flight && it->second.retransmittable_frames) {
|
| return true;
|
| }
|
| }
|
| @@ -294,44 +303,52 @@
|
| }
|
|
|
| QuicPacketSequenceNumber
|
| -QuicUnackedPacketMap::GetLeastUnacked() const {
|
| +QuicUnackedPacketMap::GetLeastUnackedSentPacket() const {
|
| if (unacked_packets_.empty()) {
|
| // If there are no unacked packets, return 0.
|
| return 0;
|
| }
|
| - return least_unacked_;
|
| +
|
| + return unacked_packets_.begin()->first;
|
| }
|
|
|
| void QuicUnackedPacketMap::SetSent(QuicPacketSequenceNumber sequence_number,
|
| QuicTime sent_time,
|
| QuicByteCount bytes_sent,
|
| bool set_in_flight) {
|
| - DCHECK_GE(sequence_number, least_unacked_);
|
| - DCHECK_LT(sequence_number, least_unacked_ + unacked_packets_.size());
|
| - TransmissionInfo* info = &unacked_packets_[sequence_number - least_unacked_];
|
| - DCHECK(!info->in_flight);
|
| -
|
| - DCHECK_LT(largest_sent_packet_, sequence_number);
|
| + DCHECK_LT(0u, sequence_number);
|
| + UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number);
|
| + if (it == unacked_packets_.end()) {
|
| + LOG(DFATAL) << "OnPacketSent called for packet that is not unacked: "
|
| + << sequence_number;
|
| + return;
|
| + }
|
| + DCHECK(!it->second.in_flight);
|
| +
|
| largest_sent_packet_ = max(sequence_number, largest_sent_packet_);
|
| - info->sent_time = sent_time;
|
| + it->second.sent_time = sent_time;
|
| if (set_in_flight) {
|
| bytes_in_flight_ += bytes_sent;
|
| - info->bytes_sent = bytes_sent;
|
| - info->in_flight = true;
|
| + it->second.bytes_sent = bytes_sent;
|
| + it->second.in_flight = true;
|
| }
|
| }
|
|
|
| void QuicUnackedPacketMap::RestoreInFlight(
|
| QuicPacketSequenceNumber sequence_number) {
|
| - DCHECK_GE(sequence_number, least_unacked_);
|
| - DCHECK_LT(sequence_number, least_unacked_ + unacked_packets_.size());
|
| - TransmissionInfo* info = &unacked_packets_[sequence_number - least_unacked_];
|
| - DCHECK(!info->in_flight);
|
| - DCHECK_NE(0u, info->bytes_sent);
|
| - DCHECK(info->sent_time.IsInitialized());
|
| -
|
| - bytes_in_flight_ += info->bytes_sent;
|
| - info->in_flight = true;
|
| + DCHECK_LT(0u, sequence_number);
|
| + UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number);
|
| + if (it == unacked_packets_.end()) {
|
| + LOG(DFATAL) << "OnPacketSent called for packet that is not unacked: "
|
| + << sequence_number;
|
| + return;
|
| + }
|
| + DCHECK(!it->second.in_flight);
|
| + DCHECK_NE(0u, it->second.bytes_sent);
|
| + DCHECK(it->second.sent_time.IsInitialized());
|
| +
|
| + bytes_in_flight_ += it->second.bytes_sent;
|
| + it->second.in_flight = true;
|
| }
|
|
|
| } // namespace net
|
|
|