dcsctp: Rename outstanding bytes to unacked bytes

And the same for outstanding items, which become unacked items. The old
names were unfortunate - especially since they were managed by a class
called OutstandingData.

To make this less complicated, these variables have been renamed to
something that is easier to understand; "Unacked bytes/items". Simply
what has been sent but hasn't been acked or nacked yet. So likely what's
in-flight, but could possibly be lost and not found to be lost yet.

Bug: None
Change-Id: I877d7f2cac5d164bf2f9f66cb32ae1f6d850ad2c
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/329761
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#41313}
This commit is contained in:
Victor Boivie 2023-12-04 09:58:25 +01:00 committed by WebRTC LUCI CQ
parent c176175f01
commit 9a2e32b9f2
7 changed files with 79 additions and 81 deletions

View File

@ -606,7 +606,7 @@ absl::optional<Metrics> DcSctpSocket::GetMetrics() const {
size_t packet_payload_size = size_t packet_payload_size =
options_.mtu - SctpPacket::kHeaderSize - DataChunk::kHeaderSize; options_.mtu - SctpPacket::kHeaderSize - DataChunk::kHeaderSize;
metrics.unack_data_count = metrics.unack_data_count =
tcb_->retransmission_queue().outstanding_items() + tcb_->retransmission_queue().unacked_items() +
(send_queue_.total_buffered_amount() + packet_payload_size - 1) / (send_queue_.total_buffered_amount() + packet_payload_size - 1) /
packet_payload_size; packet_payload_size;
metrics.peer_rwnd_bytes = tcb_->retransmission_queue().rwnd(); metrics.peer_rwnd_bytes = tcb_->retransmission_queue().rwnd();
@ -1720,7 +1720,7 @@ void DcSctpSocket::HandleForwardTsnCommon(const AnyForwardTsnChunk& chunk) {
} }
void DcSctpSocket::MaybeSendShutdownOrAck() { void DcSctpSocket::MaybeSendShutdownOrAck() {
if (tcb_->retransmission_queue().outstanding_bytes() != 0) { if (tcb_->retransmission_queue().unacked_bytes() != 0) {
return; return;
} }

View File

@ -77,8 +77,8 @@ bool OutstandingData::Item::has_expired(Timestamp now) const {
} }
bool OutstandingData::IsConsistent() const { bool OutstandingData::IsConsistent() const {
size_t actual_outstanding_bytes = 0; size_t actual_unacked_bytes = 0;
size_t actual_outstanding_items = 0; size_t actual_unacked_items = 0;
std::set<UnwrappedTSN> combined_to_be_retransmitted; std::set<UnwrappedTSN> combined_to_be_retransmitted;
combined_to_be_retransmitted.insert(to_be_retransmitted_.begin(), combined_to_be_retransmitted.insert(to_be_retransmitted_.begin(),
@ -91,8 +91,8 @@ bool OutstandingData::IsConsistent() const {
for (const Item& item : outstanding_data_) { for (const Item& item : outstanding_data_) {
tsn.Increment(); tsn.Increment();
if (item.is_outstanding()) { if (item.is_outstanding()) {
actual_outstanding_bytes += GetSerializedChunkSize(item.data()); actual_unacked_bytes += GetSerializedChunkSize(item.data());
++actual_outstanding_items; ++actual_unacked_items;
} }
if (item.should_be_retransmitted()) { if (item.should_be_retransmitted()) {
@ -100,8 +100,8 @@ bool OutstandingData::IsConsistent() const {
} }
} }
return actual_outstanding_bytes == outstanding_bytes_ && return actual_unacked_bytes == unacked_bytes_ &&
actual_outstanding_items == outstanding_items_ && actual_unacked_items == unacked_items_ &&
actual_combined_to_be_retransmitted == combined_to_be_retransmitted; actual_combined_to_be_retransmitted == combined_to_be_retransmitted;
} }
@ -112,8 +112,8 @@ void OutstandingData::AckChunk(AckInfo& ack_info,
size_t serialized_size = GetSerializedChunkSize(item.data()); size_t serialized_size = GetSerializedChunkSize(item.data());
ack_info.bytes_acked += serialized_size; ack_info.bytes_acked += serialized_size;
if (item.is_outstanding()) { if (item.is_outstanding()) {
outstanding_bytes_ -= serialized_size; unacked_bytes_ -= serialized_size;
--outstanding_items_; --unacked_items_;
} }
if (item.should_be_retransmitted()) { if (item.should_be_retransmitted()) {
RTC_DCHECK(to_be_fast_retransmitted_.find(tsn) == RTC_DCHECK(to_be_fast_retransmitted_.find(tsn) ==
@ -259,8 +259,8 @@ bool OutstandingData::NackItem(UnwrappedTSN tsn,
bool retransmit_now, bool retransmit_now,
bool do_fast_retransmit) { bool do_fast_retransmit) {
if (item.is_outstanding()) { if (item.is_outstanding()) {
outstanding_bytes_ -= GetSerializedChunkSize(item.data()); unacked_bytes_ -= GetSerializedChunkSize(item.data());
--outstanding_items_; --unacked_items_;
} }
switch (item.Nack(retransmit_now)) { switch (item.Nack(retransmit_now)) {
@ -302,7 +302,7 @@ void OutstandingData::AbandonAllFor(const Item& item) {
item.message_id(), std::move(message_end), Timestamp::Zero(), item.message_id(), std::move(message_end), Timestamp::Zero(),
MaxRetransmits(0), Timestamp::PlusInfinity(), LifecycleId::NotSet()); MaxRetransmits(0), Timestamp::PlusInfinity(), LifecycleId::NotSet());
// The added chunk shouldn't be included in `outstanding_bytes`, so set it // The added chunk shouldn't be included in `unacked_bytes`, so set it
// as acked. // as acked.
added_item.Ack(); added_item.Ack();
RTC_DLOG(LS_VERBOSE) << "Adding unsent end placeholder for message at tsn=" RTC_DLOG(LS_VERBOSE) << "Adding unsent end placeholder for message at tsn="
@ -344,8 +344,8 @@ std::vector<std::pair<TSN, Data>> OutstandingData::ExtractChunksThatCanFit(
item.MarkAsRetransmitted(); item.MarkAsRetransmitted();
result.emplace_back(tsn.Wrap(), item.data().Clone()); result.emplace_back(tsn.Wrap(), item.data().Clone());
max_size -= serialized_size; max_size -= serialized_size;
outstanding_bytes_ += serialized_size; unacked_bytes_ += serialized_size;
++outstanding_items_; ++unacked_items_;
it = chunks.erase(it); it = chunks.erase(it);
} else { } else {
++it; ++it;
@ -422,8 +422,8 @@ absl::optional<UnwrappedTSN> OutstandingData::Insert(
LifecycleId lifecycle_id) { LifecycleId lifecycle_id) {
// All chunks are always padded to be even divisible by 4. // All chunks are always padded to be even divisible by 4.
size_t chunk_size = GetSerializedChunkSize(data); size_t chunk_size = GetSerializedChunkSize(data);
outstanding_bytes_ += chunk_size; unacked_bytes_ += chunk_size;
++outstanding_items_; ++unacked_items_;
UnwrappedTSN tsn = next_tsn(); UnwrappedTSN tsn = next_tsn();
Item& item = outstanding_data_.emplace_back(message_id, data.Clone(), Item& item = outstanding_data_.emplace_back(message_id, data.Clone(),
time_sent, max_retransmissions, time_sent, max_retransmissions,

View File

@ -31,6 +31,9 @@ namespace dcsctp {
// This class keeps track of outstanding data chunks (sent, not yet acked) and // This class keeps track of outstanding data chunks (sent, not yet acked) and
// handles acking, nacking, rescheduling and abandoning. // handles acking, nacking, rescheduling and abandoning.
//
// Items are added to this queue as they are sent and will be removed when the
// peer acks them using the cumulative TSN ack.
class OutstandingData { class OutstandingData {
public: public:
// State for DATA chunks (message fragments) in the queue - used in tests. // State for DATA chunks (message fragments) in the queue - used in tests.
@ -98,10 +101,10 @@ class OutstandingData {
// it? // it?
std::vector<std::pair<TSN, Data>> GetChunksToBeRetransmitted(size_t max_size); std::vector<std::pair<TSN, Data>> GetChunksToBeRetransmitted(size_t max_size);
size_t outstanding_bytes() const { return outstanding_bytes_; } size_t unacked_bytes() const { return unacked_bytes_; }
// Returns the number of DATA chunks that are in-flight. // Returns the number of DATA chunks that are in-flight (not acked or nacked).
size_t outstanding_items() const { return outstanding_items_; } size_t unacked_items() const { return unacked_items_; }
// Given the current time `now_ms`, expire and abandon outstanding (sent at // Given the current time `now_ms`, expire and abandon outstanding (sent at
// least once) chunks that have a limited lifetime. // least once) chunks that have a limited lifetime.
@ -355,10 +358,10 @@ class OutstandingData {
// increasing TSN order. The last item has `TSN=highest_outstanding_tsn()`. // increasing TSN order. The last item has `TSN=highest_outstanding_tsn()`.
std::deque<Item> outstanding_data_; std::deque<Item> outstanding_data_;
// The number of bytes that are in-flight (sent but not yet acked or nacked). // The number of bytes that are in-flight (sent but not yet acked or nacked).
size_t outstanding_bytes_ = 0; size_t unacked_bytes_ = 0;
// The number of DATA chunks that are in-flight (sent but not yet acked or // The number of DATA chunks that are in-flight (sent but not yet acked or
// nacked). // nacked).
size_t outstanding_items_ = 0; size_t unacked_items_ = 0;
// Data chunks that are eligible for fast retransmission. // Data chunks that are eligible for fast retransmission.
std::set<UnwrappedTSN> to_be_fast_retransmitted_; std::set<UnwrappedTSN> to_be_fast_retransmitted_;
// Data chunks that are to be retransmitted. // Data chunks that are to be retransmitted.

View File

@ -59,8 +59,8 @@ class OutstandingDataTest : public testing::Test {
TEST_F(OutstandingDataTest, HasInitialState) { TEST_F(OutstandingDataTest, HasInitialState) {
EXPECT_TRUE(buf_.empty()); EXPECT_TRUE(buf_.empty());
EXPECT_EQ(buf_.outstanding_bytes(), 0u); EXPECT_EQ(buf_.unacked_bytes(), 0u);
EXPECT_EQ(buf_.outstanding_items(), 0u); EXPECT_EQ(buf_.unacked_items(), 0u);
EXPECT_FALSE(buf_.has_data_to_be_retransmitted()); EXPECT_FALSE(buf_.has_data_to_be_retransmitted());
EXPECT_EQ(buf_.last_cumulative_tsn_ack().Wrap(), TSN(9)); EXPECT_EQ(buf_.last_cumulative_tsn_ack().Wrap(), TSN(9));
EXPECT_EQ(buf_.next_tsn().Wrap(), TSN(10)); EXPECT_EQ(buf_.next_tsn().Wrap(), TSN(10));
@ -76,8 +76,8 @@ TEST_F(OutstandingDataTest, InsertChunk) {
EXPECT_EQ(tsn.Wrap(), TSN(10)); EXPECT_EQ(tsn.Wrap(), TSN(10));
EXPECT_EQ(buf_.outstanding_bytes(), DataChunk::kHeaderSize + RoundUpTo4(1)); EXPECT_EQ(buf_.unacked_bytes(), DataChunk::kHeaderSize + RoundUpTo4(1));
EXPECT_EQ(buf_.outstanding_items(), 1u); EXPECT_EQ(buf_.unacked_items(), 1u);
EXPECT_FALSE(buf_.has_data_to_be_retransmitted()); EXPECT_FALSE(buf_.has_data_to_be_retransmitted());
EXPECT_EQ(buf_.last_cumulative_tsn_ack().Wrap(), TSN(9)); EXPECT_EQ(buf_.last_cumulative_tsn_ack().Wrap(), TSN(9));
EXPECT_EQ(buf_.next_tsn().Wrap(), TSN(11)); EXPECT_EQ(buf_.next_tsn().Wrap(), TSN(11));
@ -96,8 +96,8 @@ TEST_F(OutstandingDataTest, AcksSingleChunk) {
EXPECT_EQ(ack.highest_tsn_acked.Wrap(), TSN(10)); EXPECT_EQ(ack.highest_tsn_acked.Wrap(), TSN(10));
EXPECT_FALSE(ack.has_packet_loss); EXPECT_FALSE(ack.has_packet_loss);
EXPECT_EQ(buf_.outstanding_bytes(), 0u); EXPECT_EQ(buf_.unacked_bytes(), 0u);
EXPECT_EQ(buf_.outstanding_items(), 0u); EXPECT_EQ(buf_.unacked_items(), 0u);
EXPECT_FALSE(buf_.has_data_to_be_retransmitted()); EXPECT_FALSE(buf_.has_data_to_be_retransmitted());
EXPECT_EQ(buf_.last_cumulative_tsn_ack().Wrap(), TSN(10)); EXPECT_EQ(buf_.last_cumulative_tsn_ack().Wrap(), TSN(10));
EXPECT_EQ(buf_.next_tsn().Wrap(), TSN(11)); EXPECT_EQ(buf_.next_tsn().Wrap(), TSN(11));
@ -110,8 +110,8 @@ TEST_F(OutstandingDataTest, AcksPreviousChunkDoesntUpdate) {
buf_.Insert(kMessageId, gen_.Ordered({1}, "BE"), kNow); buf_.Insert(kMessageId, gen_.Ordered({1}, "BE"), kNow);
buf_.HandleSack(unwrapper_.Unwrap(TSN(9)), {}, false); buf_.HandleSack(unwrapper_.Unwrap(TSN(9)), {}, false);
EXPECT_EQ(buf_.outstanding_bytes(), DataChunk::kHeaderSize + RoundUpTo4(1)); EXPECT_EQ(buf_.unacked_bytes(), DataChunk::kHeaderSize + RoundUpTo4(1));
EXPECT_EQ(buf_.outstanding_items(), 1u); EXPECT_EQ(buf_.unacked_items(), 1u);
EXPECT_FALSE(buf_.has_data_to_be_retransmitted()); EXPECT_FALSE(buf_.has_data_to_be_retransmitted());
EXPECT_EQ(buf_.last_cumulative_tsn_ack().Wrap(), TSN(9)); EXPECT_EQ(buf_.last_cumulative_tsn_ack().Wrap(), TSN(9));
EXPECT_EQ(buf_.next_tsn().Wrap(), TSN(11)); EXPECT_EQ(buf_.next_tsn().Wrap(), TSN(11));
@ -132,8 +132,8 @@ TEST_F(OutstandingDataTest, AcksAndNacksWithGapAckBlocks) {
EXPECT_EQ(ack.highest_tsn_acked.Wrap(), TSN(11)); EXPECT_EQ(ack.highest_tsn_acked.Wrap(), TSN(11));
EXPECT_FALSE(ack.has_packet_loss); EXPECT_FALSE(ack.has_packet_loss);
EXPECT_EQ(buf_.outstanding_bytes(), 0u); EXPECT_EQ(buf_.unacked_bytes(), 0u);
EXPECT_EQ(buf_.outstanding_items(), 0u); EXPECT_EQ(buf_.unacked_items(), 0u);
EXPECT_FALSE(buf_.has_data_to_be_retransmitted()); EXPECT_FALSE(buf_.has_data_to_be_retransmitted());
EXPECT_EQ(buf_.last_cumulative_tsn_ack().Wrap(), TSN(9)); EXPECT_EQ(buf_.last_cumulative_tsn_ack().Wrap(), TSN(9));
EXPECT_EQ(buf_.next_tsn().Wrap(), TSN(12)); EXPECT_EQ(buf_.next_tsn().Wrap(), TSN(12));

View File

@ -115,12 +115,12 @@ void RetransmissionQueue::MaybeExitFastRecovery(
} }
void RetransmissionQueue::HandleIncreasedCumulativeTsnAck( void RetransmissionQueue::HandleIncreasedCumulativeTsnAck(
size_t outstanding_bytes, size_t unacked_bytes,
size_t total_bytes_acked) { size_t total_bytes_acked) {
// Allow some margin for classifying as fully utilized, due to e.g. that too // Allow some margin for classifying as fully utilized, due to e.g. that too
// small packets (less than kMinimumFragmentedPayload) are not sent + // small packets (less than kMinimumFragmentedPayload) are not sent +
// overhead. // overhead.
bool is_fully_utilized = outstanding_bytes + options_.mtu >= cwnd_; bool is_fully_utilized = unacked_bytes + options_.mtu >= cwnd_;
size_t old_cwnd = cwnd_; size_t old_cwnd = cwnd_;
if (phase() == CongestionAlgorithmPhase::kSlowStart) { if (phase() == CongestionAlgorithmPhase::kSlowStart) {
if (is_fully_utilized && !is_in_fast_recovery()) { if (is_fully_utilized && !is_in_fast_recovery()) {
@ -205,13 +205,13 @@ void RetransmissionQueue::HandlePacketLoss(UnwrappedTSN highest_tsn_acked) {
} }
void RetransmissionQueue::UpdateReceiverWindow(uint32_t a_rwnd) { void RetransmissionQueue::UpdateReceiverWindow(uint32_t a_rwnd) {
rwnd_ = outstanding_data_.outstanding_bytes() >= a_rwnd rwnd_ = outstanding_data_.unacked_bytes() >= a_rwnd
? 0 ? 0
: a_rwnd - outstanding_data_.outstanding_bytes(); : a_rwnd - outstanding_data_.unacked_bytes();
} }
void RetransmissionQueue::StartT3RtxTimerIfOutstandingData() { void RetransmissionQueue::StartT3RtxTimerIfOutstandingData() {
// Note: Can't use `outstanding_bytes()` as that one doesn't count chunks to // Note: Can't use `unacked_bytes()` as that one doesn't count chunks to
// be retransmitted. // be retransmitted.
if (outstanding_data_.empty()) { if (outstanding_data_.empty()) {
// https://tools.ietf.org/html/rfc4960#section-6.3.2 // https://tools.ietf.org/html/rfc4960#section-6.3.2
@ -265,7 +265,7 @@ bool RetransmissionQueue::HandleSack(Timestamp now, const SackChunk& sack) {
UnwrappedTSN old_last_cumulative_tsn_ack = UnwrappedTSN old_last_cumulative_tsn_ack =
outstanding_data_.last_cumulative_tsn_ack(); outstanding_data_.last_cumulative_tsn_ack();
size_t old_outstanding_bytes = outstanding_data_.outstanding_bytes(); size_t old_unacked_bytes = outstanding_data_.unacked_bytes();
size_t old_rwnd = rwnd_; size_t old_rwnd = rwnd_;
UnwrappedTSN cumulative_tsn_ack = UnwrappedTSN cumulative_tsn_ack =
tsn_unwrapper_.Unwrap(sack.cumulative_tsn_ack()); tsn_unwrapper_.Unwrap(sack.cumulative_tsn_ack());
@ -302,9 +302,9 @@ bool RetransmissionQueue::HandleSack(Timestamp now, const SackChunk& sack) {
RTC_DLOG(LS_VERBOSE) << log_prefix_ << "Received SACK, cum_tsn_ack=" RTC_DLOG(LS_VERBOSE) << log_prefix_ << "Received SACK, cum_tsn_ack="
<< *cumulative_tsn_ack.Wrap() << " (" << *cumulative_tsn_ack.Wrap() << " ("
<< *old_last_cumulative_tsn_ack.Wrap() << *old_last_cumulative_tsn_ack.Wrap()
<< "), outstanding_bytes=" << "), unacked_bytes="
<< outstanding_data_.outstanding_bytes() << " (" << outstanding_data_.unacked_bytes() << " ("
<< old_outstanding_bytes << "), rwnd=" << rwnd_ << " (" << old_unacked_bytes << "), rwnd=" << rwnd_ << " ("
<< old_rwnd << ")"; << old_rwnd << ")";
if (cumulative_tsn_ack > old_last_cumulative_tsn_ack) { if (cumulative_tsn_ack > old_last_cumulative_tsn_ack) {
@ -316,8 +316,7 @@ bool RetransmissionQueue::HandleSack(Timestamp now, const SackChunk& sack) {
// Note: It may be started again in a bit further down. // Note: It may be started again in a bit further down.
t3_rtx_.Stop(); t3_rtx_.Stop();
HandleIncreasedCumulativeTsnAck(old_outstanding_bytes, HandleIncreasedCumulativeTsnAck(old_unacked_bytes, ack_info.bytes_acked);
ack_info.bytes_acked);
} }
if (ack_info.has_packet_loss) { if (ack_info.has_packet_loss) {
@ -355,7 +354,7 @@ void RetransmissionQueue::UpdateRTT(Timestamp now,
void RetransmissionQueue::HandleT3RtxTimerExpiry() { void RetransmissionQueue::HandleT3RtxTimerExpiry() {
size_t old_cwnd = cwnd_; size_t old_cwnd = cwnd_;
size_t old_outstanding_bytes = outstanding_bytes(); size_t old_unacked_bytes = unacked_bytes();
// https://tools.ietf.org/html/rfc4960#section-6.3.3 // https://tools.ietf.org/html/rfc4960#section-6.3.3
// "For the destination address for which the timer expires, adjust // "For the destination address for which the timer expires, adjust
// its ssthresh with rules defined in Section 7.2.3 and set the cwnd <- MTU." // its ssthresh with rules defined in Section 7.2.3 and set the cwnd <- MTU."
@ -392,8 +391,8 @@ void RetransmissionQueue::HandleT3RtxTimerExpiry() {
RTC_DLOG(LS_INFO) << log_prefix_ << "t3-rtx expired. new cwnd=" << cwnd_ RTC_DLOG(LS_INFO) << log_prefix_ << "t3-rtx expired. new cwnd=" << cwnd_
<< " (" << old_cwnd << "), ssthresh=" << ssthresh_ << " (" << old_cwnd << "), ssthresh=" << ssthresh_
<< ", outstanding_bytes " << outstanding_bytes() << " (" << ", unacked_bytes " << unacked_bytes() << " ("
<< old_outstanding_bytes << ")"; << old_unacked_bytes << ")";
RTC_DCHECK(IsConsistent()); RTC_DCHECK(IsConsistent());
} }
@ -402,7 +401,7 @@ RetransmissionQueue::GetChunksForFastRetransmit(size_t bytes_in_packet) {
RTC_DCHECK(outstanding_data_.has_data_to_be_fast_retransmitted()); RTC_DCHECK(outstanding_data_.has_data_to_be_fast_retransmitted());
RTC_DCHECK(IsDivisibleBy4(bytes_in_packet)); RTC_DCHECK(IsDivisibleBy4(bytes_in_packet));
std::vector<std::pair<TSN, Data>> to_be_sent; std::vector<std::pair<TSN, Data>> to_be_sent;
size_t old_outstanding_bytes = outstanding_bytes(); size_t old_unacked_bytes = unacked_bytes();
to_be_sent = to_be_sent =
outstanding_data_.GetChunksToBeFastRetransmitted(bytes_in_packet); outstanding_data_.GetChunksToBeFastRetransmitted(bytes_in_packet);
@ -441,8 +440,8 @@ RetransmissionQueue::GetChunksForFastRetransmit(size_t bytes_in_packet) {
sb << *c.first; sb << *c.first;
}) })
<< " - " << bytes_retransmitted << " - " << bytes_retransmitted
<< " bytes. outstanding_bytes=" << outstanding_bytes() << " bytes. unacked_bytes=" << unacked_bytes() << " ("
<< " (" << old_outstanding_bytes << ")"; << old_unacked_bytes << ")";
RTC_DCHECK(IsConsistent()); RTC_DCHECK(IsConsistent());
return to_be_sent; return to_be_sent;
@ -455,7 +454,7 @@ std::vector<std::pair<TSN, Data>> RetransmissionQueue::GetChunksToSend(
RTC_DCHECK(IsDivisibleBy4(bytes_remaining_in_packet)); RTC_DCHECK(IsDivisibleBy4(bytes_remaining_in_packet));
std::vector<std::pair<TSN, Data>> to_be_sent; std::vector<std::pair<TSN, Data>> to_be_sent;
size_t old_outstanding_bytes = outstanding_bytes(); size_t old_unacked_bytes = unacked_bytes();
size_t old_rwnd = rwnd_; size_t old_rwnd = rwnd_;
// Calculate the bandwidth budget (how many bytes that is // Calculate the bandwidth budget (how many bytes that is
@ -527,8 +526,8 @@ std::vector<std::pair<TSN, Data>> RetransmissionQueue::GetChunksToSend(
[&](size_t r, const std::pair<TSN, Data>& d) { [&](size_t r, const std::pair<TSN, Data>& d) {
return r + GetSerializedChunkSize(d.second); return r + GetSerializedChunkSize(d.second);
}) })
<< " bytes. outstanding_bytes=" << outstanding_bytes() << " bytes. unacked_bytes=" << unacked_bytes() << " ("
<< " (" << old_outstanding_bytes << "), cwnd=" << cwnd_ << old_unacked_bytes << "), cwnd=" << cwnd_
<< ", rwnd=" << rwnd_ << " (" << old_rwnd << ")"; << ", rwnd=" << rwnd_ << " (" << old_rwnd << ")";
} }
RTC_DCHECK(IsConsistent()); RTC_DCHECK(IsConsistent());
@ -551,9 +550,9 @@ bool RetransmissionQueue::ShouldSendForwardTsn(Timestamp now) {
} }
size_t RetransmissionQueue::max_bytes_to_send() const { size_t RetransmissionQueue::max_bytes_to_send() const {
size_t left = outstanding_bytes() >= cwnd_ ? 0 : cwnd_ - outstanding_bytes(); size_t left = unacked_bytes() >= cwnd_ ? 0 : cwnd_ - unacked_bytes();
if (outstanding_bytes() == 0) { if (unacked_bytes() == 0) {
// https://datatracker.ietf.org/doc/html/rfc4960#section-6.1 // https://datatracker.ietf.org/doc/html/rfc4960#section-6.1
// ... However, regardless of the value of rwnd (including if it is 0), the // ... However, regardless of the value of rwnd (including if it is 0), the
// data sender can always have one DATA chunk in flight to the receiver if // data sender can always have one DATA chunk in flight to the receiver if

View File

@ -121,14 +121,10 @@ class RetransmissionQueue {
uint64_t rtx_bytes_count() const { return rtx_bytes_count_; } uint64_t rtx_bytes_count() const { return rtx_bytes_count_; }
// Returns the number of bytes of packets that are in-flight. // Returns the number of bytes of packets that are in-flight.
size_t outstanding_bytes() const { size_t unacked_bytes() const { return outstanding_data_.unacked_bytes(); }
return outstanding_data_.outstanding_bytes();
}
// Returns the number of DATA chunks that are in-flight. // Returns the number of DATA chunks that are in-flight.
size_t outstanding_items() const { size_t unacked_items() const { return outstanding_data_.unacked_items(); }
return outstanding_data_.outstanding_items();
}
// Indicates if the congestion control algorithm allows data to be sent. // Indicates if the congestion control algorithm allows data to be sent.
bool can_send_data() const; bool can_send_data() const;
@ -197,7 +193,7 @@ class RetransmissionQueue {
// Update the congestion control algorithm given as the cumulative ack TSN // Update the congestion control algorithm given as the cumulative ack TSN
// value has increased, as reported in an incoming SACK chunk. // value has increased, as reported in an incoming SACK chunk.
void HandleIncreasedCumulativeTsnAck(size_t outstanding_bytes, void HandleIncreasedCumulativeTsnAck(size_t unacked_bytes,
size_t total_bytes_acked); size_t total_bytes_acked);
// Update the congestion control algorithm, given as packet loss has been // Update the congestion control algorithm, given as packet loss has been
// detected, as reported in an incoming SACK chunk. // detected, as reported in an incoming SACK chunk.

View File

@ -579,8 +579,8 @@ TEST_F(RetransmissionQueueTest, RetransmitsWhenSendBufferIsFullT3Expiry) {
static constexpr size_t kCwnd = 1200; static constexpr size_t kCwnd = 1200;
queue.set_cwnd(kCwnd); queue.set_cwnd(kCwnd);
EXPECT_EQ(queue.cwnd(), kCwnd); EXPECT_EQ(queue.cwnd(), kCwnd);
EXPECT_EQ(queue.outstanding_bytes(), 0u); EXPECT_EQ(queue.unacked_bytes(), 0u);
EXPECT_EQ(queue.outstanding_items(), 0u); EXPECT_EQ(queue.unacked_items(), 0u);
std::vector<uint8_t> payload(1000); std::vector<uint8_t> payload(1000);
EXPECT_CALL(producer_, Produce) EXPECT_CALL(producer_, Produce)
@ -596,8 +596,8 @@ TEST_F(RetransmissionQueueTest, RetransmitsWhenSendBufferIsFullT3Expiry) {
EXPECT_THAT(queue.GetChunkStatesForTesting(), EXPECT_THAT(queue.GetChunkStatesForTesting(),
ElementsAre(Pair(TSN(9), State::kAcked), // ElementsAre(Pair(TSN(9), State::kAcked), //
Pair(TSN(10), State::kInFlight))); Pair(TSN(10), State::kInFlight)));
EXPECT_EQ(queue.outstanding_bytes(), payload.size() + DataChunk::kHeaderSize); EXPECT_EQ(queue.unacked_bytes(), payload.size() + DataChunk::kHeaderSize);
EXPECT_EQ(queue.outstanding_items(), 1u); EXPECT_EQ(queue.unacked_items(), 1u);
// Will force chunks to be retransmitted // Will force chunks to be retransmitted
queue.HandleT3RtxTimerExpiry(); queue.HandleT3RtxTimerExpiry();
@ -605,8 +605,8 @@ TEST_F(RetransmissionQueueTest, RetransmitsWhenSendBufferIsFullT3Expiry) {
EXPECT_THAT(queue.GetChunkStatesForTesting(), EXPECT_THAT(queue.GetChunkStatesForTesting(),
ElementsAre(Pair(TSN(9), State::kAcked), // ElementsAre(Pair(TSN(9), State::kAcked), //
Pair(TSN(10), State::kToBeRetransmitted))); Pair(TSN(10), State::kToBeRetransmitted)));
EXPECT_EQ(queue.outstanding_bytes(), 0u); EXPECT_EQ(queue.unacked_bytes(), 0u);
EXPECT_EQ(queue.outstanding_items(), 0u); EXPECT_EQ(queue.unacked_items(), 0u);
std::vector<std::pair<TSN, Data>> chunks_to_rtx = std::vector<std::pair<TSN, Data>> chunks_to_rtx =
queue.GetChunksToSend(now_, 1500); queue.GetChunksToSend(now_, 1500);
@ -614,8 +614,8 @@ TEST_F(RetransmissionQueueTest, RetransmitsWhenSendBufferIsFullT3Expiry) {
EXPECT_THAT(queue.GetChunkStatesForTesting(), EXPECT_THAT(queue.GetChunkStatesForTesting(),
ElementsAre(Pair(TSN(9), State::kAcked), // ElementsAre(Pair(TSN(9), State::kAcked), //
Pair(TSN(10), State::kInFlight))); Pair(TSN(10), State::kInFlight)));
EXPECT_EQ(queue.outstanding_bytes(), payload.size() + DataChunk::kHeaderSize); EXPECT_EQ(queue.unacked_bytes(), payload.size() + DataChunk::kHeaderSize);
EXPECT_EQ(queue.outstanding_items(), 1u); EXPECT_EQ(queue.unacked_items(), 1u);
} }
TEST_F(RetransmissionQueueTest, ProducesValidForwardTsn) { TEST_F(RetransmissionQueueTest, ProducesValidForwardTsn) {
@ -1048,8 +1048,8 @@ TEST_F(RetransmissionQueueTest, AccountsNackedAbandonedChunksAsNotOutstanding) {
Pair(TSN(10), State::kInFlight), // Pair(TSN(10), State::kInFlight), //
Pair(TSN(11), State::kInFlight), // Pair(TSN(11), State::kInFlight), //
Pair(TSN(12), State::kInFlight))); Pair(TSN(12), State::kInFlight)));
EXPECT_EQ(queue.outstanding_bytes(), (16 + 4) * 3u); EXPECT_EQ(queue.unacked_bytes(), (16 + 4) * 3u);
EXPECT_EQ(queue.outstanding_items(), 3u); EXPECT_EQ(queue.unacked_items(), 3u);
// Mark the message as lost. // Mark the message as lost.
EXPECT_CALL(producer_, Discard(StreamID(1), kMessageId)).Times(1); EXPECT_CALL(producer_, Discard(StreamID(1), kMessageId)).Times(1);
@ -1062,21 +1062,21 @@ TEST_F(RetransmissionQueueTest, AccountsNackedAbandonedChunksAsNotOutstanding) {
Pair(TSN(10), State::kAbandoned), // Pair(TSN(10), State::kAbandoned), //
Pair(TSN(11), State::kAbandoned), // Pair(TSN(11), State::kAbandoned), //
Pair(TSN(12), State::kAbandoned))); Pair(TSN(12), State::kAbandoned)));
EXPECT_EQ(queue.outstanding_bytes(), 0u); EXPECT_EQ(queue.unacked_bytes(), 0u);
EXPECT_EQ(queue.outstanding_items(), 0u); EXPECT_EQ(queue.unacked_items(), 0u);
// Now ACK those, one at a time. // Now ACK those, one at a time.
queue.HandleSack(now_, SackChunk(TSN(10), kArwnd, {}, {})); queue.HandleSack(now_, SackChunk(TSN(10), kArwnd, {}, {}));
EXPECT_EQ(queue.outstanding_bytes(), 0u); EXPECT_EQ(queue.unacked_bytes(), 0u);
EXPECT_EQ(queue.outstanding_items(), 0u); EXPECT_EQ(queue.unacked_items(), 0u);
queue.HandleSack(now_, SackChunk(TSN(11), kArwnd, {}, {})); queue.HandleSack(now_, SackChunk(TSN(11), kArwnd, {}, {}));
EXPECT_EQ(queue.outstanding_bytes(), 0u); EXPECT_EQ(queue.unacked_bytes(), 0u);
EXPECT_EQ(queue.outstanding_items(), 0u); EXPECT_EQ(queue.unacked_items(), 0u);
queue.HandleSack(now_, SackChunk(TSN(12), kArwnd, {}, {})); queue.HandleSack(now_, SackChunk(TSN(12), kArwnd, {}, {}));
EXPECT_EQ(queue.outstanding_bytes(), 0u); EXPECT_EQ(queue.unacked_bytes(), 0u);
EXPECT_EQ(queue.outstanding_items(), 0u); EXPECT_EQ(queue.unacked_items(), 0u);
} }
TEST_F(RetransmissionQueueTest, ExpireFromSendQueueWhenPartiallySent) { TEST_F(RetransmissionQueueTest, ExpireFromSendQueueWhenPartiallySent) {
@ -1398,7 +1398,7 @@ TEST_F(RetransmissionQueueTest, CwndRecoversWhenAcking) {
queue.GetChunksToSend(now_, 1500); queue.GetChunksToSend(now_, 1500);
EXPECT_THAT(chunks_to_send, ElementsAre(Pair(TSN(10), _))); EXPECT_THAT(chunks_to_send, ElementsAre(Pair(TSN(10), _)));
size_t serialized_size = payload.size() + DataChunk::kHeaderSize; size_t serialized_size = payload.size() + DataChunk::kHeaderSize;
EXPECT_EQ(queue.outstanding_bytes(), serialized_size); EXPECT_EQ(queue.unacked_bytes(), serialized_size);
queue.HandleSack(now_, SackChunk(TSN(10), kArwnd, {}, {})); queue.HandleSack(now_, SackChunk(TSN(10), kArwnd, {}, {}));
@ -1435,7 +1435,7 @@ TEST_F(RetransmissionQueueTest, OnlySendsLargePacketsOnLargeCongestionWindow) {
queue.HandleSack(now_, SackChunk(TSN(10), kArwnd, {}, {})); queue.HandleSack(now_, SackChunk(TSN(10), kArwnd, {}, {}));
EXPECT_TRUE(queue.can_send_data()); EXPECT_TRUE(queue.can_send_data());
EXPECT_EQ(queue.outstanding_bytes(), 0u); EXPECT_EQ(queue.unacked_bytes(), 0u);
EXPECT_EQ(queue.cwnd(), intial_cwnd + kMaxMtu); EXPECT_EQ(queue.cwnd(), intial_cwnd + kMaxMtu);
} }