| 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 359f2d190b1c77a533eb87569b64f8d010469c3d..0640c29940c1a5d0d5415c39575b1fb450fd70a1 100644
|
| --- a/net/quic/quic_unacked_packet_map.cc
|
| +++ b/net/quic/quic_unacked_packet_map.cc
|
| @@ -16,17 +16,20 @@ namespace net {
|
| 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) {
|
| - delete it->second.retransmittable_frames;
|
| + it != unacked_packets_.end(); ++it, ++index) {
|
| + delete it->retransmittable_frames;
|
| // Only delete all_transmissions once, for the newest packet.
|
| - if (it->first == *it->second.all_transmissions->rbegin()) {
|
| - delete it->second.all_transmissions;
|
| + if (it->all_transmissions != NULL &&
|
| + index == *it->all_transmissions->rbegin()) {
|
| + delete it->all_transmissions;
|
| }
|
| }
|
| }
|
| @@ -35,19 +38,11 @@ QuicUnackedPacketMap::~QuicUnackedPacketMap() {
|
| // sent in order and the connection tracks RetransmittableFrames for longer.
|
| void QuicUnackedPacketMap::AddPacket(
|
| const SerializedPacket& serialized_packet) {
|
| - 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] =
|
| + DCHECK_EQ(least_unacked_ + unacked_packets_.size(),
|
| + serialized_packet.sequence_number);
|
| + unacked_packets_.push_back(
|
| TransmissionInfo(serialized_packet.retransmittable_frames,
|
| - serialized_packet.sequence_number,
|
| - serialized_packet.sequence_number_length);
|
| + serialized_packet.sequence_number_length));
|
| if (serialized_packet.retransmittable_frames != NULL &&
|
| serialized_packet.retransmittable_frames->HasCryptoHandshake()
|
| == IS_HANDSHAKE) {
|
| @@ -55,17 +50,28 @@ void QuicUnackedPacketMap::AddPacket(
|
| }
|
| }
|
|
|
| +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(ContainsKey(unacked_packets_, old_sequence_number));
|
| - DCHECK(unacked_packets_.empty() ||
|
| - unacked_packets_.rbegin()->first < new_sequence_number);
|
| + 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);
|
|
|
| // TODO(ianswett): Discard and lose the packet lazily instead of immediately.
|
| TransmissionInfo* transmission_info =
|
| - FindOrNull(unacked_packets_, old_sequence_number);
|
| + &unacked_packets_.at(old_sequence_number - least_unacked_);
|
| RetransmittableFrames* frames = transmission_info->retransmittable_frames;
|
| LOG_IF(DFATAL, frames == NULL) << "Attempt to retransmit packet with no "
|
| << "retransmittable frames: "
|
| @@ -76,97 +82,86 @@ void QuicUnackedPacketMap::OnRetransmittedPacket(
|
| 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->size() > 1 &&
|
| + if (transmission_info->all_transmissions != NULL &&
|
| *(++transmission_info->all_transmissions->begin()) < largest_observed_) {
|
| QuicPacketSequenceNumber old_transmission =
|
| *transmission_info->all_transmissions->begin();
|
| - TransmissionInfo* old_transmission_info =
|
| - FindOrNull(unacked_packets_, old_transmission);
|
| + TransmissionInfo* old_info =
|
| + &unacked_packets_[old_transmission - least_unacked_];
|
| // Don't remove old packets if they're still in flight.
|
| - if (old_transmission_info == NULL || !old_transmission_info->in_flight) {
|
| - transmission_info->all_transmissions->erase(old_transmission);
|
| - unacked_packets_.erase(old_transmission);
|
| + 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;
|
| }
|
| }
|
| - unacked_packets_[new_sequence_number] =
|
| + 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(
|
| 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) {
|
| - UnackedPacketMap::iterator it = unacked_packets_.begin();
|
| - while (it != unacked_packets_.end() && num_to_clear > 0) {
|
| - QuicPacketSequenceNumber sequence_number = it->first;
|
| + while (!unacked_packets_.empty() && num_to_clear > 0) {
|
| // 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.
|
| - if (it->second.in_flight || it->second.retransmittable_frames != NULL) {
|
| + TransmissionInfo* info = &unacked_packets_.front();
|
| + if (info->in_flight || info->retransmittable_frames != NULL) {
|
| break;
|
| }
|
|
|
| - it->second.all_transmissions->erase(sequence_number);
|
| - LOG_IF(DFATAL, it->second.all_transmissions->empty())
|
| + info->all_transmissions->pop_front();
|
| + LOG_IF(DFATAL, info->all_transmissions->empty())
|
| << "Previous retransmissions must have a newer transmission.";
|
| - ++it;
|
| - unacked_packets_.erase(sequence_number);
|
| + unacked_packets_.pop_front();
|
| + ++least_unacked_;
|
| --num_to_clear;
|
| }
|
| }
|
|
|
| bool QuicUnackedPacketMap::HasRetransmittableFrames(
|
| QuicPacketSequenceNumber sequence_number) const {
|
| - const TransmissionInfo* transmission_info =
|
| - FindOrNull(unacked_packets_, sequence_number);
|
| - if (transmission_info == NULL) {
|
| - return false;
|
| - }
|
| -
|
| - return transmission_info->retransmittable_frames != NULL;
|
| + 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;
|
| }
|
|
|
| void QuicUnackedPacketMap::NackPacket(QuicPacketSequenceNumber sequence_number,
|
| size_t min_nacks) {
|
| - 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);
|
| + 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);
|
| }
|
|
|
| void QuicUnackedPacketMap::RemoveRetransmittability(
|
| QuicPacketSequenceNumber sequence_number) {
|
| - UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number);
|
| - if (it == unacked_packets_.end()) {
|
| - DVLOG(1) << "packet is not in unacked_packets: " << 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;
|
| }
|
| - 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 (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;
|
| - }
|
| + for (SequenceNumberList::const_iterator it = all_transmissions->begin();
|
| + it != all_transmissions->end(); ++it) {
|
| + TransmissionInfo* transmission_info =
|
| + &unacked_packets_[*it - least_unacked_];
|
| MaybeRemoveRetransmittableFrames(transmission_info);
|
| - 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);
|
| - }
|
| + transmission_info->all_transmissions = NULL;
|
| }
|
| -
|
| delete all_transmissions;
|
| }
|
|
|
| @@ -186,48 +181,36 @@ void QuicUnackedPacketMap::IncreaseLargestObserved(
|
| 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(
|
| - 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;
|
| + QuicPacketSequenceNumber sequence_number,
|
| + const TransmissionInfo& info) const {
|
| + return sequence_number <= largest_observed_ &&
|
| + !info.in_flight &&
|
| + info.retransmittable_frames == NULL &&
|
| + info.all_transmissions == NULL;
|
| }
|
|
|
| bool QuicUnackedPacketMap::IsUnacked(
|
| QuicPacketSequenceNumber sequence_number) const {
|
| - return ContainsKey(unacked_packets_, sequence_number);
|
| + if (sequence_number < least_unacked_ ||
|
| + sequence_number >= least_unacked_ + unacked_packets_.size()) {
|
| + return false;
|
| + }
|
| + return !IsPacketUseless(sequence_number,
|
| + unacked_packets_[sequence_number - least_unacked_]);
|
| }
|
|
|
| void QuicUnackedPacketMap::RemoveFromInFlight(
|
| QuicPacketSequenceNumber sequence_number) {
|
| - 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);
|
| + 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;
|
| }
|
| }
|
|
|
| @@ -241,16 +224,16 @@ bool QuicUnackedPacketMap::HasInFlightPackets() const {
|
|
|
| const TransmissionInfo& QuicUnackedPacketMap::GetTransmissionInfo(
|
| QuicPacketSequenceNumber sequence_number) const {
|
| - return unacked_packets_.find(sequence_number)->second;
|
| + return unacked_packets_[sequence_number - least_unacked_];
|
| }
|
|
|
| QuicTime QuicUnackedPacketMap::GetLastPacketSentTime() const {
|
| UnackedPacketMap::const_reverse_iterator it = unacked_packets_.rbegin();
|
| while (it != unacked_packets_.rend()) {
|
| - if (it->second.in_flight) {
|
| - LOG_IF(DFATAL, it->second.sent_time == QuicTime::Zero())
|
| + if (it->in_flight) {
|
| + LOG_IF(DFATAL, it->sent_time == QuicTime::Zero())
|
| << "Sent time can never be zero for a packet in flight.";
|
| - return it->second.sent_time;
|
| + return it->sent_time;
|
| }
|
| ++it;
|
| }
|
| @@ -260,25 +243,33 @@ QuicTime QuicUnackedPacketMap::GetLastPacketSentTime() const {
|
|
|
| QuicTime QuicUnackedPacketMap::GetFirstInFlightPacketSentTime() const {
|
| UnackedPacketMap::const_iterator it = unacked_packets_.begin();
|
| - while (it != unacked_packets_.end() && !it->second.in_flight) {
|
| + while (it != unacked_packets_.end() && !it->in_flight) {
|
| ++it;
|
| }
|
| if (it == unacked_packets_.end()) {
|
| LOG(DFATAL) << "GetFirstInFlightPacketSentTime requires in flight packets.";
|
| return QuicTime::Zero();
|
| }
|
| - return it->second.sent_time;
|
| + return it->sent_time;
|
| }
|
|
|
| -size_t QuicUnackedPacketMap::GetNumUnackedPackets() const {
|
| - return unacked_packets_.size();
|
| +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;
|
| }
|
|
|
| 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->second.in_flight) {
|
| + if (it->in_flight) {
|
| ++num_in_flight;
|
| }
|
| if (num_in_flight > 1) {
|
| @@ -295,7 +286,7 @@ bool QuicUnackedPacketMap::HasPendingCryptoPackets() const {
|
| bool QuicUnackedPacketMap::HasUnackedRetransmittableFrames() const {
|
| for (UnackedPacketMap::const_reverse_iterator it =
|
| unacked_packets_.rbegin(); it != unacked_packets_.rend(); ++it) {
|
| - if (it->second.in_flight && it->second.retransmittable_frames) {
|
| + if (it->in_flight && it->retransmittable_frames) {
|
| return true;
|
| }
|
| }
|
| @@ -303,52 +294,44 @@ bool QuicUnackedPacketMap::HasUnackedRetransmittableFrames() const {
|
| }
|
|
|
| QuicPacketSequenceNumber
|
| -QuicUnackedPacketMap::GetLeastUnackedSentPacket() const {
|
| +QuicUnackedPacketMap::GetLeastUnacked() const {
|
| if (unacked_packets_.empty()) {
|
| // If there are no unacked packets, return 0.
|
| return 0;
|
| }
|
| -
|
| - return unacked_packets_.begin()->first;
|
| + return least_unacked_;
|
| }
|
|
|
| void QuicUnackedPacketMap::SetSent(QuicPacketSequenceNumber sequence_number,
|
| QuicTime sent_time,
|
| QuicByteCount bytes_sent,
|
| bool set_in_flight) {
|
| - 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_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);
|
| largest_sent_packet_ = max(sequence_number, largest_sent_packet_);
|
| - it->second.sent_time = sent_time;
|
| + info->sent_time = sent_time;
|
| if (set_in_flight) {
|
| bytes_in_flight_ += bytes_sent;
|
| - it->second.bytes_sent = bytes_sent;
|
| - it->second.in_flight = true;
|
| + info->bytes_sent = bytes_sent;
|
| + info->in_flight = true;
|
| }
|
| }
|
|
|
| void QuicUnackedPacketMap::RestoreInFlight(
|
| QuicPacketSequenceNumber 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);
|
| - 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;
|
| + 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;
|
| }
|
|
|
| } // namespace net
|
|
|