blob: 7b8a23b86c4363749e2c9d9d31786f1c2a4cb53a [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 teama6ef0a62019-03-07 20:34:33 -05007#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
8#include "net/third_party/quiche/src/quic/core/quic_interval.h"
9#include "net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h"
10#include "net/third_party/quiche/src/quic/core/quic_utils.h"
11#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
12#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
13#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
14#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
15
16namespace quic {
17
18namespace {
19
20struct CompareOffset {
21 bool operator()(const BufferedSlice& slice, QuicStreamOffset offset) const {
22 return slice.offset + slice.slice.length() < offset;
23 }
24};
25
26} // namespace
27
28BufferedSlice::BufferedSlice(QuicMemSlice mem_slice, QuicStreamOffset offset)
29 : slice(std::move(mem_slice)), offset(offset) {}
30
31BufferedSlice::BufferedSlice(BufferedSlice&& other) = default;
32
33BufferedSlice& BufferedSlice::operator=(BufferedSlice&& other) = default;
34
35BufferedSlice::~BufferedSlice() {}
36
QUICHE team03c62942019-12-19 15:09:40 -080037QuicInterval<std::size_t> BufferedSlice::interval() const {
38 const std::size_t length = slice.length();
39 return QuicInterval<std::size_t>(offset, offset + length);
40}
41
QUICHE teama6ef0a62019-03-07 20:34:33 -050042bool StreamPendingRetransmission::operator==(
43 const StreamPendingRetransmission& other) const {
44 return offset == other.offset && length == other.length;
45}
46
47QuicStreamSendBuffer::QuicStreamSendBuffer(QuicBufferAllocator* allocator)
renjietang96f8c6d2020-02-18 15:52:53 -080048 : current_end_offset_(0),
QUICHE team03c62942019-12-19 15:09:40 -080049 stream_offset_(0),
QUICHE teama6ef0a62019-03-07 20:34:33 -050050 allocator_(allocator),
51 stream_bytes_written_(0),
52 stream_bytes_outstanding_(0),
53 write_index_(-1) {}
54
55QuicStreamSendBuffer::~QuicStreamSendBuffer() {}
56
57void QuicStreamSendBuffer::SaveStreamData(const struct iovec* iov,
58 int iov_count,
59 size_t iov_offset,
60 QuicByteCount data_length) {
61 DCHECK_LT(0u, data_length);
62 // Latch the maximum data slice size.
63 const QuicByteCount max_data_slice_size =
64 GetQuicFlag(FLAGS_quic_send_buffer_max_data_slice_size);
65 while (data_length > 0) {
66 size_t slice_len = std::min(data_length, max_data_slice_size);
vasilvvff082a02019-12-24 22:07:51 -080067 QuicUniqueBufferPtr buffer = MakeUniqueBuffer(allocator_, slice_len);
QUICHE teama6ef0a62019-03-07 20:34:33 -050068 QuicUtils::CopyToBuffer(iov, iov_count, iov_offset, slice_len,
vasilvvff082a02019-12-24 22:07:51 -080069 buffer.get());
70 SaveMemSlice(QuicMemSlice(std::move(buffer), slice_len));
QUICHE teama6ef0a62019-03-07 20:34:33 -050071 data_length -= slice_len;
72 iov_offset += slice_len;
73 }
74}
75
76void QuicStreamSendBuffer::SaveMemSlice(QuicMemSlice slice) {
77 QUIC_DVLOG(2) << "Save slice offset " << stream_offset_ << " length "
78 << slice.length();
79 if (slice.empty()) {
80 QUIC_BUG << "Try to save empty MemSlice to send buffer.";
81 return;
82 }
83 size_t length = slice.length();
renjietang96f8c6d2020-02-18 15:52:53 -080084 // Need to start the offsets at the right interval.
85 if (interval_deque_.Empty()) {
86 const QuicStreamOffset end = stream_offset_ + length;
87 current_end_offset_ = std::max(current_end_offset_, end);
QUICHE teama6ef0a62019-03-07 20:34:33 -050088 }
renjietang96f8c6d2020-02-18 15:52:53 -080089 BufferedSlice bs = BufferedSlice(std::move(slice), stream_offset_);
90 interval_deque_.PushBack(std::move(bs));
QUICHE teama6ef0a62019-03-07 20:34:33 -050091 stream_offset_ += length;
92}
93
wub553a9662019-03-28 20:13:23 -070094QuicByteCount QuicStreamSendBuffer::SaveMemSliceSpan(QuicMemSliceSpan span) {
95 return span.ConsumeAll(
96 [&](QuicMemSlice slice) { SaveMemSlice(std::move(slice)); });
97}
98
QUICHE teama6ef0a62019-03-07 20:34:33 -050099void QuicStreamSendBuffer::OnStreamDataConsumed(size_t bytes_consumed) {
100 stream_bytes_written_ += bytes_consumed;
101 stream_bytes_outstanding_ += bytes_consumed;
102}
103
104bool QuicStreamSendBuffer::WriteStreamData(QuicStreamOffset offset,
105 QuicByteCount data_length,
106 QuicDataWriter* writer) {
renjietang96f8c6d2020-02-18 15:52:53 -0800107 QUIC_BUG_IF(current_end_offset_ < offset)
108 << "Tried to write data out of sequence. last_offset_end:"
109 << current_end_offset_ << ", offset:" << offset;
110 // The iterator returned from |interval_deque_| will automatically advance
111 // the internal write index for the QuicIntervalDeque. The incrementing is
112 // done in operator++.
113 for (auto slice_it = interval_deque_.DataAt(offset);
114 slice_it != interval_deque_.DataEnd(); ++slice_it) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500115 if (data_length == 0 || offset < slice_it->offset) {
116 break;
117 }
renjietang96f8c6d2020-02-18 15:52:53 -0800118
QUICHE teama6ef0a62019-03-07 20:34:33 -0500119 QuicByteCount slice_offset = offset - slice_it->offset;
120 QuicByteCount available_bytes_in_slice =
121 slice_it->slice.length() - slice_offset;
122 QuicByteCount copy_length = std::min(data_length, available_bytes_in_slice);
123 if (!writer->WriteBytes(slice_it->slice.data() + slice_offset,
124 copy_length)) {
125 QUIC_BUG << "Writer fails to write.";
126 return false;
127 }
128 offset += copy_length;
129 data_length -= copy_length;
renjietang96f8c6d2020-02-18 15:52:53 -0800130 const QuicStreamOffset new_end =
131 slice_it->offset + slice_it->slice.length();
132 current_end_offset_ = std::max(current_end_offset_, new_end);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500133 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500134 return data_length == 0;
135}
136
137bool QuicStreamSendBuffer::OnStreamDataAcked(
138 QuicStreamOffset offset,
139 QuicByteCount data_length,
140 QuicByteCount* newly_acked_length) {
141 *newly_acked_length = 0;
142 if (data_length == 0) {
143 return true;
144 }
145 if (bytes_acked_.Empty() || offset >= bytes_acked_.rbegin()->max() ||
146 bytes_acked_.IsDisjoint(
147 QuicInterval<QuicStreamOffset>(offset, offset + data_length))) {
148 // Optimization for the typical case, when all data is newly acked.
149 if (stream_bytes_outstanding_ < data_length) {
150 return false;
151 }
wub0be7fce2020-03-19 15:09:11 -0700152 bytes_acked_.AddOptimizedForAppend(offset, offset + data_length);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500153 *newly_acked_length = data_length;
154 stream_bytes_outstanding_ -= data_length;
155 pending_retransmissions_.Difference(offset, offset + data_length);
156 if (!FreeMemSlices(offset, offset + data_length)) {
157 return false;
158 }
159 CleanUpBufferedSlices();
160 return true;
161 }
162 // Exit if no new data gets acked.
163 if (bytes_acked_.Contains(offset, offset + data_length)) {
164 return true;
165 }
166 // Execute the slow path if newly acked data fill in existing holes.
167 QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length);
168 newly_acked.Difference(bytes_acked_);
169 for (const auto& interval : newly_acked) {
170 *newly_acked_length += (interval.max() - interval.min());
171 }
172 if (stream_bytes_outstanding_ < *newly_acked_length) {
173 return false;
174 }
175 stream_bytes_outstanding_ -= *newly_acked_length;
176 bytes_acked_.Add(offset, offset + data_length);
177 pending_retransmissions_.Difference(offset, offset + data_length);
178 if (newly_acked.Empty()) {
179 return true;
180 }
181 if (!FreeMemSlices(newly_acked.begin()->min(), newly_acked.rbegin()->max())) {
182 return false;
183 }
184 CleanUpBufferedSlices();
185 return true;
186}
187
188void QuicStreamSendBuffer::OnStreamDataLost(QuicStreamOffset offset,
189 QuicByteCount data_length) {
190 if (data_length == 0) {
191 return;
192 }
193 QuicIntervalSet<QuicStreamOffset> bytes_lost(offset, offset + data_length);
194 bytes_lost.Difference(bytes_acked_);
195 if (bytes_lost.Empty()) {
196 return;
197 }
198 for (const auto& lost : bytes_lost) {
199 pending_retransmissions_.Add(lost.min(), lost.max());
200 }
201}
202
203void QuicStreamSendBuffer::OnStreamDataRetransmitted(
204 QuicStreamOffset offset,
205 QuicByteCount data_length) {
206 if (data_length == 0) {
207 return;
208 }
209 pending_retransmissions_.Difference(offset, offset + data_length);
210}
211
212bool QuicStreamSendBuffer::HasPendingRetransmission() const {
213 return !pending_retransmissions_.Empty();
214}
215
216StreamPendingRetransmission QuicStreamSendBuffer::NextPendingRetransmission()
217 const {
218 if (HasPendingRetransmission()) {
219 const auto pending = pending_retransmissions_.begin();
220 return {pending->min(), pending->max() - pending->min()};
221 }
222 QUIC_BUG << "NextPendingRetransmission is called unexpected with no "
223 "pending retransmissions.";
224 return {0, 0};
225}
226
227bool QuicStreamSendBuffer::FreeMemSlices(QuicStreamOffset start,
228 QuicStreamOffset end) {
renjietang96f8c6d2020-02-18 15:52:53 -0800229 auto it = interval_deque_.DataBegin();
230 if (it == interval_deque_.DataEnd() || it->slice.empty()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500231 QUIC_BUG << "Trying to ack stream data [" << start << ", " << end << "), "
renjietang96f8c6d2020-02-18 15:52:53 -0800232 << (it == interval_deque_.DataEnd()
QUICHE teama6ef0a62019-03-07 20:34:33 -0500233 ? "and there is no outstanding data."
234 : "and the first slice is empty.");
235 return false;
236 }
renjietang96f8c6d2020-02-18 15:52:53 -0800237 if (!it->interval().Contains(start)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500238 // Slow path that not the earliest outstanding data gets acked.
renjietang96f8c6d2020-02-18 15:52:53 -0800239 it = std::lower_bound(interval_deque_.DataBegin(),
240 interval_deque_.DataEnd(), start, CompareOffset());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500241 }
renjietang96f8c6d2020-02-18 15:52:53 -0800242 if (it == interval_deque_.DataEnd() || it->slice.empty()) {
243 QUIC_BUG << "Offset " << start << " with iterator offset: " << it->offset
244 << (it == interval_deque_.DataEnd() ? " does not exist."
245 : " has already been acked.");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500246 return false;
247 }
renjietang96f8c6d2020-02-18 15:52:53 -0800248 for (; it != interval_deque_.DataEnd(); ++it) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500249 if (it->offset >= end) {
250 break;
251 }
252 if (!it->slice.empty() &&
253 bytes_acked_.Contains(it->offset, it->offset + it->slice.length())) {
254 it->slice.Reset();
255 }
256 }
257 return true;
258}
259
260void QuicStreamSendBuffer::CleanUpBufferedSlices() {
renjietang96f8c6d2020-02-18 15:52:53 -0800261 while (!interval_deque_.Empty() &&
262 interval_deque_.DataBegin()->slice.empty()) {
263 QUIC_BUG_IF(interval_deque_.DataBegin()->offset > current_end_offset_)
264 << "Fail to pop front from interval_deque_. Front element contained "
265 "a slice whose data has not all be written. Front offset "
266 << interval_deque_.DataBegin()->offset << " length "
267 << interval_deque_.DataBegin()->slice.length();
268 interval_deque_.PopFront();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500269 }
270}
271
272bool QuicStreamSendBuffer::IsStreamDataOutstanding(
273 QuicStreamOffset offset,
274 QuicByteCount data_length) const {
275 return data_length > 0 &&
276 !bytes_acked_.Contains(offset, offset + data_length);
277}
278
279size_t QuicStreamSendBuffer::size() const {
renjietang96f8c6d2020-02-18 15:52:53 -0800280 return interval_deque_.Size();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500281}
282
283} // namespace quic