blob: ead192dd6fe7d6fde2ae45631efcaf88c94fd691 [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
37bool StreamPendingRetransmission::operator==(
38 const StreamPendingRetransmission& other) const {
39 return offset == other.offset && length == other.length;
40}
41
42QuicStreamSendBuffer::QuicStreamSendBuffer(QuicBufferAllocator* allocator)
43 : stream_offset_(0),
44 allocator_(allocator),
45 stream_bytes_written_(0),
46 stream_bytes_outstanding_(0),
47 write_index_(-1) {}
48
49QuicStreamSendBuffer::~QuicStreamSendBuffer() {}
50
51void QuicStreamSendBuffer::SaveStreamData(const struct iovec* iov,
52 int iov_count,
53 size_t iov_offset,
54 QuicByteCount data_length) {
55 DCHECK_LT(0u, data_length);
56 // Latch the maximum data slice size.
57 const QuicByteCount max_data_slice_size =
58 GetQuicFlag(FLAGS_quic_send_buffer_max_data_slice_size);
59 while (data_length > 0) {
60 size_t slice_len = std::min(data_length, max_data_slice_size);
61 QuicMemSlice slice(allocator_, slice_len);
62 QuicUtils::CopyToBuffer(iov, iov_count, iov_offset, slice_len,
63 const_cast<char*>(slice.data()));
64 SaveMemSlice(std::move(slice));
65 data_length -= slice_len;
66 iov_offset += slice_len;
67 }
68}
69
70void QuicStreamSendBuffer::SaveMemSlice(QuicMemSlice slice) {
71 QUIC_DVLOG(2) << "Save slice offset " << stream_offset_ << " length "
72 << slice.length();
73 if (slice.empty()) {
74 QUIC_BUG << "Try to save empty MemSlice to send buffer.";
75 return;
76 }
77 size_t length = slice.length();
78 buffered_slices_.emplace_back(std::move(slice), stream_offset_);
79 if (write_index_ == -1) {
80 write_index_ = buffered_slices_.size() - 1;
81 }
82 stream_offset_ += length;
83}
84
wub553a9662019-03-28 20:13:23 -070085QuicByteCount QuicStreamSendBuffer::SaveMemSliceSpan(QuicMemSliceSpan span) {
86 return span.ConsumeAll(
87 [&](QuicMemSlice slice) { SaveMemSlice(std::move(slice)); });
88}
89
QUICHE teama6ef0a62019-03-07 20:34:33 -050090void QuicStreamSendBuffer::OnStreamDataConsumed(size_t bytes_consumed) {
91 stream_bytes_written_ += bytes_consumed;
92 stream_bytes_outstanding_ += bytes_consumed;
93}
94
95bool QuicStreamSendBuffer::WriteStreamData(QuicStreamOffset offset,
96 QuicByteCount data_length,
97 QuicDataWriter* writer) {
98 bool write_index_hit = false;
99 QuicDeque<BufferedSlice>::iterator slice_it =
100 write_index_ == -1
101 ? buffered_slices_.begin()
102 // Assume with write_index, write mostly starts from indexed slice.
103 : buffered_slices_.begin() + write_index_;
104 if (write_index_ != -1) {
105 if (offset >= slice_it->offset + slice_it->slice.length()) {
106 QUIC_BUG << "Tried to write data out of sequence.";
107 return false;
108 }
109 // Determine if write actually happens at indexed slice.
110 if (offset >= slice_it->offset) {
111 write_index_hit = true;
112 } else {
113 // Write index missed, move iterator to the beginning.
114 slice_it = buffered_slices_.begin();
115 }
116 }
117
118 for (; slice_it != buffered_slices_.end(); ++slice_it) {
119 if (data_length == 0 || offset < slice_it->offset) {
120 break;
121 }
122 if (offset >= slice_it->offset + slice_it->slice.length()) {
123 continue;
124 }
125 QuicByteCount slice_offset = offset - slice_it->offset;
126 QuicByteCount available_bytes_in_slice =
127 slice_it->slice.length() - slice_offset;
128 QuicByteCount copy_length = std::min(data_length, available_bytes_in_slice);
129 if (!writer->WriteBytes(slice_it->slice.data() + slice_offset,
130 copy_length)) {
131 QUIC_BUG << "Writer fails to write.";
132 return false;
133 }
134 offset += copy_length;
135 data_length -= copy_length;
136
137 if (write_index_hit && copy_length == available_bytes_in_slice) {
138 // Finished writing all data in current slice, advance write index for
139 // next write.
140 ++write_index_;
141 }
142 }
143
144 if (write_index_hit &&
145 static_cast<size_t>(write_index_) == buffered_slices_.size()) {
146 // Already write to the end off buffer.
danzh3c98a732019-03-26 11:20:52 -0700147 QUIC_DVLOG(2) << "Finish writing out all buffered data.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500148 write_index_ = -1;
149 }
150
151 return data_length == 0;
152}
153
154bool QuicStreamSendBuffer::OnStreamDataAcked(
155 QuicStreamOffset offset,
156 QuicByteCount data_length,
157 QuicByteCount* newly_acked_length) {
158 *newly_acked_length = 0;
159 if (data_length == 0) {
160 return true;
161 }
162 if (bytes_acked_.Empty() || offset >= bytes_acked_.rbegin()->max() ||
163 bytes_acked_.IsDisjoint(
164 QuicInterval<QuicStreamOffset>(offset, offset + data_length))) {
165 // Optimization for the typical case, when all data is newly acked.
166 if (stream_bytes_outstanding_ < data_length) {
167 return false;
168 }
169 bytes_acked_.Add(offset, offset + data_length);
170 *newly_acked_length = data_length;
171 stream_bytes_outstanding_ -= data_length;
172 pending_retransmissions_.Difference(offset, offset + data_length);
173 if (!FreeMemSlices(offset, offset + data_length)) {
174 return false;
175 }
176 CleanUpBufferedSlices();
177 return true;
178 }
179 // Exit if no new data gets acked.
180 if (bytes_acked_.Contains(offset, offset + data_length)) {
181 return true;
182 }
183 // Execute the slow path if newly acked data fill in existing holes.
184 QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length);
185 newly_acked.Difference(bytes_acked_);
186 for (const auto& interval : newly_acked) {
187 *newly_acked_length += (interval.max() - interval.min());
188 }
189 if (stream_bytes_outstanding_ < *newly_acked_length) {
190 return false;
191 }
192 stream_bytes_outstanding_ -= *newly_acked_length;
193 bytes_acked_.Add(offset, offset + data_length);
194 pending_retransmissions_.Difference(offset, offset + data_length);
195 if (newly_acked.Empty()) {
196 return true;
197 }
198 if (!FreeMemSlices(newly_acked.begin()->min(), newly_acked.rbegin()->max())) {
199 return false;
200 }
201 CleanUpBufferedSlices();
202 return true;
203}
204
205void QuicStreamSendBuffer::OnStreamDataLost(QuicStreamOffset offset,
206 QuicByteCount data_length) {
207 if (data_length == 0) {
208 return;
209 }
210 QuicIntervalSet<QuicStreamOffset> bytes_lost(offset, offset + data_length);
211 bytes_lost.Difference(bytes_acked_);
212 if (bytes_lost.Empty()) {
213 return;
214 }
215 for (const auto& lost : bytes_lost) {
216 pending_retransmissions_.Add(lost.min(), lost.max());
217 }
218}
219
220void QuicStreamSendBuffer::OnStreamDataRetransmitted(
221 QuicStreamOffset offset,
222 QuicByteCount data_length) {
223 if (data_length == 0) {
224 return;
225 }
226 pending_retransmissions_.Difference(offset, offset + data_length);
227}
228
229bool QuicStreamSendBuffer::HasPendingRetransmission() const {
230 return !pending_retransmissions_.Empty();
231}
232
233StreamPendingRetransmission QuicStreamSendBuffer::NextPendingRetransmission()
234 const {
235 if (HasPendingRetransmission()) {
236 const auto pending = pending_retransmissions_.begin();
237 return {pending->min(), pending->max() - pending->min()};
238 }
239 QUIC_BUG << "NextPendingRetransmission is called unexpected with no "
240 "pending retransmissions.";
241 return {0, 0};
242}
243
244bool QuicStreamSendBuffer::FreeMemSlices(QuicStreamOffset start,
245 QuicStreamOffset end) {
246 auto it = buffered_slices_.begin();
247 // Find it, such that buffered_slices_[it - 1].end < start <=
248 // buffered_slices_[it].end.
249 if (it == buffered_slices_.end() || it->slice.empty()) {
250 QUIC_BUG << "Trying to ack stream data [" << start << ", " << end << "), "
251 << (it == buffered_slices_.end()
252 ? "and there is no outstanding data."
253 : "and the first slice is empty.");
254 return false;
255 }
256 if (start >= it->offset + it->slice.length() || start < it->offset) {
257 // Slow path that not the earliest outstanding data gets acked.
258 it = std::lower_bound(buffered_slices_.begin(), buffered_slices_.end(),
259 start, CompareOffset());
260 }
261 if (it == buffered_slices_.end() || it->slice.empty()) {
262 QUIC_BUG << "Offset " << start
263 << " does not exist or it has already been acked.";
264 return false;
265 }
266 for (; it != buffered_slices_.end(); ++it) {
267 if (it->offset >= end) {
268 break;
269 }
270 if (!it->slice.empty() &&
271 bytes_acked_.Contains(it->offset, it->offset + it->slice.length())) {
272 it->slice.Reset();
273 }
274 }
275 return true;
276}
277
278void QuicStreamSendBuffer::CleanUpBufferedSlices() {
279 while (!buffered_slices_.empty() && buffered_slices_.front().slice.empty()) {
280 // Remove data which stops waiting for acks. Please note, mem slices can
281 // be released out of order, but send buffer is cleaned up in order.
282 QUIC_BUG_IF(write_index_ == 0)
283 << "Fail to advance current_write_slice_. It points to the slice "
284 "whose data has all be written and ACK'ed or ignored. "
285 "current_write_slice_ offset "
286 << buffered_slices_[write_index_].offset << " length "
287 << buffered_slices_[write_index_].slice.length();
288 if (write_index_ > 0) {
289 // If write index is pointing to any slice, reduce the index as the
290 // slices are all shifted to the left by one.
291 --write_index_;
292 }
293 buffered_slices_.pop_front();
294 }
295}
296
297bool QuicStreamSendBuffer::IsStreamDataOutstanding(
298 QuicStreamOffset offset,
299 QuicByteCount data_length) const {
300 return data_length > 0 &&
301 !bytes_acked_.Contains(offset, offset + data_length);
302}
303
304size_t QuicStreamSendBuffer::size() const {
305 return buffered_slices_.size();
306}
307
308} // namespace quic