aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorVictor Boivie <boivie@webrtc.org>2021-05-22 22:56:07 +0200
committerWebRTC LUCI CQ <webrtc-scoped@luci-project-accounts.iam.gserviceaccount.com>2021-05-31 21:07:17 +0000
commit7b4fd5ca5977af78e44cc4ee5e255df6e8efa036 (patch)
treeb7807e71a3fbc30028ba702dfdd4d90712c5ecb8 /net
parent82aa094a970a2c37634378910116bbe1d5abc633 (diff)
downloadwebrtc-7b4fd5ca5977af78e44cc4ee5e255df6e8efa036.tar.gz
dcsctp: Determine chunks to be retransmitted fast
Before this CL, before sending out any chunk, all inflight data chunks were inspected to find out if they were supposed to be retransmitted. When the congestion window is large, this is a lot of data chunks to inspect, which takes time. By having a separate collection for chunks to be retransmitted, this becomes a much faster operation. In most cases, constant in time. Bug: webrtc:12799 Change-Id: I0d43ba7a88656eead26d5e0b9c4735622a8d080e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219626 Reviewed-by: Florent Castelli <orphis@webrtc.org> Commit-Queue: Victor Boivie <boivie@webrtc.org> Cr-Commit-Position: refs/heads/master@{#34178}
Diffstat (limited to 'net')
-rw-r--r--net/dcsctp/tx/retransmission_queue.cc59
-rw-r--r--net/dcsctp/tx/retransmission_queue.h3
2 files changed, 44 insertions, 18 deletions
diff --git a/net/dcsctp/tx/retransmission_queue.cc b/net/dcsctp/tx/retransmission_queue.cc
index 3ed8ea94f0..ef2f0e3172 100644
--- a/net/dcsctp/tx/retransmission_queue.cc
+++ b/net/dcsctp/tx/retransmission_queue.cc
@@ -14,6 +14,7 @@
#include <functional>
#include <iterator>
#include <map>
+#include <set>
#include <string>
#include <unordered_map>
#include <utility>
@@ -83,17 +84,21 @@ RetransmissionQueue::RetransmissionQueue(
send_queue_(send_queue) {}
bool RetransmissionQueue::IsConsistent() const {
- size_t actual_outstanding_bytes = absl::c_accumulate(
- outstanding_data_, 0,
- [&](size_t r, const std::pair<const UnwrappedTSN, TxData>& d) {
- // Packets that have been ACKED or NACKED are not outstanding, as they
- // are received. And packets that are marked for retransmission or
- // abandoned are lost, and not outstanding.
- return r + (d.second.is_outstanding()
- ? GetSerializedChunkSize(d.second.data())
- : 0);
- });
- return actual_outstanding_bytes == outstanding_bytes_;
+ size_t actual_outstanding_bytes = 0;
+
+ std::set<UnwrappedTSN> actual_to_be_retransmitted;
+ for (const auto& elem : outstanding_data_) {
+ if (elem.second.is_outstanding()) {
+ actual_outstanding_bytes += GetSerializedChunkSize(elem.second.data());
+ }
+
+ if (elem.second.should_be_retransmitted()) {
+ actual_to_be_retransmitted.insert(elem.first);
+ }
+ }
+
+ return actual_outstanding_bytes == outstanding_bytes_ &&
+ actual_to_be_retransmitted == to_be_retransmitted_;
}
// Returns how large a chunk will be, serialized, carrying the data
@@ -110,6 +115,8 @@ void RetransmissionQueue::RemoveAcked(UnwrappedTSN cumulative_tsn_ack,
ack_info.acked_tsns.push_back(it->first.Wrap());
if (it->second.is_outstanding()) {
outstanding_bytes_ -= GetSerializedChunkSize(it->second.data());
+ } else if (it->second.should_be_retransmitted()) {
+ to_be_retransmitted_.erase(it->first);
}
}
@@ -137,6 +144,9 @@ void RetransmissionQueue::AckGapBlocks(
if (iter->second.is_outstanding()) {
outstanding_bytes_ -= GetSerializedChunkSize(iter->second.data());
}
+ if (iter->second.should_be_retransmitted()) {
+ to_be_retransmitted_.erase(iter->first);
+ }
iter->second.Ack();
ack_info.highest_tsn_acked =
std::max(ack_info.highest_tsn_acked, iter->first);
@@ -184,6 +194,7 @@ void RetransmissionQueue::NackBetweenAckBlocks(
if (iter->second.Nack()) {
ack_info.has_packet_loss = true;
+ to_be_retransmitted_.insert(iter->first);
RTC_DLOG(LS_VERBOSE) << log_prefix_ << *iter->first.Wrap()
<< " marked for retransmission";
}
@@ -497,6 +508,7 @@ void RetransmissionQueue::HandleT3RtxTimerExpiry() {
outstanding_bytes_ -= GetSerializedChunkSize(item.data());
}
if (item.Nack(/*retransmit_now=*/true)) {
+ to_be_retransmitted_.insert(tsn);
RTC_DLOG(LS_VERBOSE) << log_prefix_ << "Chunk " << *tsn.Wrap()
<< " will be retransmitted due to T3-RTX";
++count;
@@ -521,19 +533,27 @@ void RetransmissionQueue::HandleT3RtxTimerExpiry() {
std::vector<std::pair<TSN, Data>>
RetransmissionQueue::GetChunksToBeRetransmitted(size_t max_size) {
std::vector<std::pair<TSN, Data>> result;
- for (auto& elem : outstanding_data_) {
- UnwrappedTSN tsn = elem.first;
- TxData& item = elem.second;
+
+ for (auto it = to_be_retransmitted_.begin();
+ it != to_be_retransmitted_.end();) {
+ UnwrappedTSN tsn = *it;
+ auto elem = outstanding_data_.find(tsn);
+ RTC_DCHECK(elem != outstanding_data_.end());
+ TxData& item = elem->second;
+ RTC_DCHECK(item.should_be_retransmitted());
+ RTC_DCHECK(!item.is_outstanding());
+ RTC_DCHECK(!item.is_abandoned());
+ RTC_DCHECK(!item.is_acked());
size_t serialized_size = GetSerializedChunkSize(item.data());
- if (item.should_be_retransmitted() && serialized_size <= max_size) {
- RTC_DCHECK(!item.is_outstanding());
- RTC_DCHECK(!item.is_abandoned());
- RTC_DCHECK(!item.is_acked());
+ if (serialized_size <= max_size) {
item.Retransmit();
result.emplace_back(tsn.Wrap(), item.data().Clone());
max_size -= serialized_size;
outstanding_bytes_ += serialized_size;
+ it = to_be_retransmitted_.erase(it);
+ } else {
+ ++it;
}
// No point in continuing if the packet is full.
if (max_size <= data_chunk_header_size_) {
@@ -780,6 +800,9 @@ void RetransmissionQueue::ExpireAllFor(
other.data().message_id == item.data().message_id) {
RTC_DLOG(LS_VERBOSE) << log_prefix_ << "Marking chunk " << *tsn.Wrap()
<< " as abandoned";
+ if (other.should_be_retransmitted()) {
+ to_be_retransmitted_.erase(tsn);
+ }
other.Abandon();
}
}
diff --git a/net/dcsctp/tx/retransmission_queue.h b/net/dcsctp/tx/retransmission_queue.h
index ddffa85a61..7f5baf9fff 100644
--- a/net/dcsctp/tx/retransmission_queue.h
+++ b/net/dcsctp/tx/retransmission_queue.h
@@ -13,6 +13,7 @@
#include <cstdint>
#include <functional>
#include <map>
+#include <set>
#include <string>
#include <utility>
#include <vector>
@@ -360,6 +361,8 @@ class RetransmissionQueue {
// cumulative acked. Note that it also contains chunks that have been acked in
// gap ack blocks.
std::map<UnwrappedTSN, TxData> outstanding_data_;
+ // Data chunks that are to be retransmitted.
+ std::set<UnwrappedTSN> to_be_retransmitted_;
// The number of bytes that are in-flight (sent but not yet acked or nacked).
size_t outstanding_bytes_ = 0;
};