blob: b2ac6bfc7c43d2a940cdecd8299b2df056ac963d [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <algorithm>
6
QUICHE team5be974e2020-12-29 18:35:24 -05007#include "quic/core/quic_data_writer.h"
8#include "quic/core/quic_interval.h"
9#include "quic/core/quic_stream_send_buffer.h"
10#include "quic/core/quic_utils.h"
11#include "quic/platform/api/quic_bug_tracker.h"
12#include "quic/platform/api/quic_flag_utils.h"
13#include "quic/platform/api/quic_flags.h"
14#include "quic/platform/api/quic_logging.h"
vasilvv53f59f62021-06-09 10:48:48 -070015#include "quic/platform/api/quic_mem_slice.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050016
17namespace quic {
18
19namespace {
20
21struct CompareOffset {
22 bool operator()(const BufferedSlice& slice, QuicStreamOffset offset) const {
23 return slice.offset + slice.slice.length() < offset;
24 }
25};
26
27} // namespace
28
29BufferedSlice::BufferedSlice(QuicMemSlice mem_slice, QuicStreamOffset offset)
30 : slice(std::move(mem_slice)), offset(offset) {}
31
32BufferedSlice::BufferedSlice(BufferedSlice&& other) = default;
33
34BufferedSlice& BufferedSlice::operator=(BufferedSlice&& other) = default;
35
36BufferedSlice::~BufferedSlice() {}
37
QUICHE team03c62942019-12-19 15:09:40 -080038QuicInterval<std::size_t> BufferedSlice::interval() const {
39 const std::size_t length = slice.length();
40 return QuicInterval<std::size_t>(offset, offset + length);
41}
42
QUICHE teama6ef0a62019-03-07 20:34:33 -050043bool StreamPendingRetransmission::operator==(
44 const StreamPendingRetransmission& other) const {
45 return offset == other.offset && length == other.length;
46}
47
48QuicStreamSendBuffer::QuicStreamSendBuffer(QuicBufferAllocator* allocator)
renjietang96f8c6d2020-02-18 15:52:53 -080049 : current_end_offset_(0),
QUICHE team03c62942019-12-19 15:09:40 -080050 stream_offset_(0),
QUICHE teama6ef0a62019-03-07 20:34:33 -050051 allocator_(allocator),
52 stream_bytes_written_(0),
53 stream_bytes_outstanding_(0),
54 write_index_(-1) {}
55
56QuicStreamSendBuffer::~QuicStreamSendBuffer() {}
57
58void QuicStreamSendBuffer::SaveStreamData(const struct iovec* iov,
59 int iov_count,
60 size_t iov_offset,
61 QuicByteCount data_length) {
vasilvvf8035162021-02-01 14:49:14 -080062 QUICHE_DCHECK_LT(0u, data_length);
QUICHE teama6ef0a62019-03-07 20:34:33 -050063 // Latch the maximum data slice size.
64 const QuicByteCount max_data_slice_size =
65 GetQuicFlag(FLAGS_quic_send_buffer_max_data_slice_size);
66 while (data_length > 0) {
67 size_t slice_len = std::min(data_length, max_data_slice_size);
vasilvvff082a02019-12-24 22:07:51 -080068 QuicUniqueBufferPtr buffer = MakeUniqueBuffer(allocator_, slice_len);
QUICHE teama6ef0a62019-03-07 20:34:33 -050069 QuicUtils::CopyToBuffer(iov, iov_count, iov_offset, slice_len,
vasilvvff082a02019-12-24 22:07:51 -080070 buffer.get());
71 SaveMemSlice(QuicMemSlice(std::move(buffer), slice_len));
QUICHE teama6ef0a62019-03-07 20:34:33 -050072 data_length -= slice_len;
73 iov_offset += slice_len;
74 }
75}
76
77void QuicStreamSendBuffer::SaveMemSlice(QuicMemSlice slice) {
78 QUIC_DVLOG(2) << "Save slice offset " << stream_offset_ << " length "
79 << slice.length();
80 if (slice.empty()) {
QUICHE team6b68e542021-03-16 15:13:52 -070081 QUIC_BUG(quic_bug_10853_1) << "Try to save empty MemSlice to send buffer.";
QUICHE teama6ef0a62019-03-07 20:34:33 -050082 return;
83 }
84 size_t length = slice.length();
renjietang96f8c6d2020-02-18 15:52:53 -080085 // Need to start the offsets at the right interval.
86 if (interval_deque_.Empty()) {
87 const QuicStreamOffset end = stream_offset_ + length;
88 current_end_offset_ = std::max(current_end_offset_, end);
QUICHE teama6ef0a62019-03-07 20:34:33 -050089 }
renjietang96f8c6d2020-02-18 15:52:53 -080090 BufferedSlice bs = BufferedSlice(std::move(slice), stream_offset_);
91 interval_deque_.PushBack(std::move(bs));
QUICHE teama6ef0a62019-03-07 20:34:33 -050092 stream_offset_ += length;
93}
94
vasilvv53f59f62021-06-09 10:48:48 -070095QuicByteCount QuicStreamSendBuffer::SaveMemSliceSpan(
96 absl::Span<QuicMemSlice> span) {
97 QuicByteCount total = 0;
98 for (QuicMemSlice& slice : span) {
99 if (slice.length() == 0) {
100 // Skip empty slices.
101 continue;
102 }
103 total += slice.length();
104 SaveMemSlice(std::move(slice));
105 }
106 return total;
107}
108
QUICHE teama6ef0a62019-03-07 20:34:33 -0500109void QuicStreamSendBuffer::OnStreamDataConsumed(size_t bytes_consumed) {
110 stream_bytes_written_ += bytes_consumed;
111 stream_bytes_outstanding_ += bytes_consumed;
112}
113
114bool QuicStreamSendBuffer::WriteStreamData(QuicStreamOffset offset,
115 QuicByteCount data_length,
116 QuicDataWriter* writer) {
QUICHE team6b68e542021-03-16 15:13:52 -0700117 QUIC_BUG_IF(quic_bug_12823_1, current_end_offset_ < offset)
renjietang96f8c6d2020-02-18 15:52:53 -0800118 << "Tried to write data out of sequence. last_offset_end:"
119 << current_end_offset_ << ", offset:" << offset;
120 // The iterator returned from |interval_deque_| will automatically advance
121 // the internal write index for the QuicIntervalDeque. The incrementing is
122 // done in operator++.
123 for (auto slice_it = interval_deque_.DataAt(offset);
124 slice_it != interval_deque_.DataEnd(); ++slice_it) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500125 if (data_length == 0 || offset < slice_it->offset) {
126 break;
127 }
renjietang96f8c6d2020-02-18 15:52:53 -0800128
QUICHE teama6ef0a62019-03-07 20:34:33 -0500129 QuicByteCount slice_offset = offset - slice_it->offset;
130 QuicByteCount available_bytes_in_slice =
131 slice_it->slice.length() - slice_offset;
132 QuicByteCount copy_length = std::min(data_length, available_bytes_in_slice);
133 if (!writer->WriteBytes(slice_it->slice.data() + slice_offset,
134 copy_length)) {
QUICHE team6b68e542021-03-16 15:13:52 -0700135 QUIC_BUG(quic_bug_10853_2) << "Writer fails to write.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500136 return false;
137 }
138 offset += copy_length;
139 data_length -= copy_length;
renjietang96f8c6d2020-02-18 15:52:53 -0800140 const QuicStreamOffset new_end =
141 slice_it->offset + slice_it->slice.length();
142 current_end_offset_ = std::max(current_end_offset_, new_end);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500143 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500144 return data_length == 0;
145}
146
147bool QuicStreamSendBuffer::OnStreamDataAcked(
148 QuicStreamOffset offset,
149 QuicByteCount data_length,
150 QuicByteCount* newly_acked_length) {
151 *newly_acked_length = 0;
152 if (data_length == 0) {
153 return true;
154 }
155 if (bytes_acked_.Empty() || offset >= bytes_acked_.rbegin()->max() ||
156 bytes_acked_.IsDisjoint(
157 QuicInterval<QuicStreamOffset>(offset, offset + data_length))) {
158 // Optimization for the typical case, when all data is newly acked.
159 if (stream_bytes_outstanding_ < data_length) {
160 return false;
161 }
wub0be7fce2020-03-19 15:09:11 -0700162 bytes_acked_.AddOptimizedForAppend(offset, offset + data_length);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500163 *newly_acked_length = data_length;
164 stream_bytes_outstanding_ -= data_length;
165 pending_retransmissions_.Difference(offset, offset + data_length);
166 if (!FreeMemSlices(offset, offset + data_length)) {
167 return false;
168 }
169 CleanUpBufferedSlices();
170 return true;
171 }
172 // Exit if no new data gets acked.
173 if (bytes_acked_.Contains(offset, offset + data_length)) {
174 return true;
175 }
176 // Execute the slow path if newly acked data fill in existing holes.
177 QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length);
178 newly_acked.Difference(bytes_acked_);
179 for (const auto& interval : newly_acked) {
180 *newly_acked_length += (interval.max() - interval.min());
181 }
182 if (stream_bytes_outstanding_ < *newly_acked_length) {
183 return false;
184 }
185 stream_bytes_outstanding_ -= *newly_acked_length;
186 bytes_acked_.Add(offset, offset + data_length);
187 pending_retransmissions_.Difference(offset, offset + data_length);
188 if (newly_acked.Empty()) {
189 return true;
190 }
191 if (!FreeMemSlices(newly_acked.begin()->min(), newly_acked.rbegin()->max())) {
192 return false;
193 }
194 CleanUpBufferedSlices();
195 return true;
196}
197
198void QuicStreamSendBuffer::OnStreamDataLost(QuicStreamOffset offset,
199 QuicByteCount data_length) {
200 if (data_length == 0) {
201 return;
202 }
203 QuicIntervalSet<QuicStreamOffset> bytes_lost(offset, offset + data_length);
204 bytes_lost.Difference(bytes_acked_);
205 if (bytes_lost.Empty()) {
206 return;
207 }
208 for (const auto& lost : bytes_lost) {
209 pending_retransmissions_.Add(lost.min(), lost.max());
210 }
211}
212
213void QuicStreamSendBuffer::OnStreamDataRetransmitted(
214 QuicStreamOffset offset,
215 QuicByteCount data_length) {
216 if (data_length == 0) {
217 return;
218 }
219 pending_retransmissions_.Difference(offset, offset + data_length);
220}
221
222bool QuicStreamSendBuffer::HasPendingRetransmission() const {
223 return !pending_retransmissions_.Empty();
224}
225
226StreamPendingRetransmission QuicStreamSendBuffer::NextPendingRetransmission()
227 const {
228 if (HasPendingRetransmission()) {
229 const auto pending = pending_retransmissions_.begin();
230 return {pending->min(), pending->max() - pending->min()};
231 }
QUICHE team6b68e542021-03-16 15:13:52 -0700232 QUIC_BUG(quic_bug_10853_3)
QUICHE team8e6da712021-03-08 10:59:32 -0800233 << "NextPendingRetransmission is called unexpected with no "
234 "pending retransmissions.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500235 return {0, 0};
236}
237
238bool QuicStreamSendBuffer::FreeMemSlices(QuicStreamOffset start,
239 QuicStreamOffset end) {
renjietang96f8c6d2020-02-18 15:52:53 -0800240 auto it = interval_deque_.DataBegin();
241 if (it == interval_deque_.DataEnd() || it->slice.empty()) {
QUICHE team6b68e542021-03-16 15:13:52 -0700242 QUIC_BUG(quic_bug_10853_4)
QUICHE team8e6da712021-03-08 10:59:32 -0800243 << "Trying to ack stream data [" << start << ", " << end << "), "
244 << (it == interval_deque_.DataEnd()
245 ? "and there is no outstanding data."
246 : "and the first slice is empty.");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500247 return false;
248 }
renjietang96f8c6d2020-02-18 15:52:53 -0800249 if (!it->interval().Contains(start)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500250 // Slow path that not the earliest outstanding data gets acked.
renjietang96f8c6d2020-02-18 15:52:53 -0800251 it = std::lower_bound(interval_deque_.DataBegin(),
252 interval_deque_.DataEnd(), start, CompareOffset());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500253 }
renjietang96f8c6d2020-02-18 15:52:53 -0800254 if (it == interval_deque_.DataEnd() || it->slice.empty()) {
QUICHE team6b68e542021-03-16 15:13:52 -0700255 QUIC_BUG(quic_bug_10853_5)
QUICHE team8e6da712021-03-08 10:59:32 -0800256 << "Offset " << start << " with iterator offset: " << it->offset
257 << (it == interval_deque_.DataEnd() ? " does not exist."
258 : " has already been acked.");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500259 return false;
260 }
renjietang96f8c6d2020-02-18 15:52:53 -0800261 for (; it != interval_deque_.DataEnd(); ++it) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500262 if (it->offset >= end) {
263 break;
264 }
265 if (!it->slice.empty() &&
266 bytes_acked_.Contains(it->offset, it->offset + it->slice.length())) {
267 it->slice.Reset();
268 }
269 }
270 return true;
271}
272
273void QuicStreamSendBuffer::CleanUpBufferedSlices() {
renjietang96f8c6d2020-02-18 15:52:53 -0800274 while (!interval_deque_.Empty() &&
275 interval_deque_.DataBegin()->slice.empty()) {
QUICHE team6b68e542021-03-16 15:13:52 -0700276 QUIC_BUG_IF(quic_bug_12823_2,
277 interval_deque_.DataBegin()->offset > current_end_offset_)
renjietang96f8c6d2020-02-18 15:52:53 -0800278 << "Fail to pop front from interval_deque_. Front element contained "
279 "a slice whose data has not all be written. Front offset "
280 << interval_deque_.DataBegin()->offset << " length "
281 << interval_deque_.DataBegin()->slice.length();
282 interval_deque_.PopFront();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500283 }
284}
285
286bool QuicStreamSendBuffer::IsStreamDataOutstanding(
287 QuicStreamOffset offset,
288 QuicByteCount data_length) const {
289 return data_length > 0 &&
290 !bytes_acked_.Contains(offset, offset + data_length);
291}
292
293size_t QuicStreamSendBuffer::size() const {
renjietang96f8c6d2020-02-18 15:52:53 -0800294 return interval_deque_.Size();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500295}
296
297} // namespace quic