Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: net/quic/quic_frame_list.cc

Issue 1400293002: relnote: refactoring the buffering logic in QUIC's stream sequencer. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: disentangle merge of 104894802 Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/quic/quic_frame_list.h ('k') | net/quic/quic_stream_sequencer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2015 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 "net/quic/quic_frame_list.h"
6
7 #include "base/logging.h"
8
9 namespace net {
10
11 QuicFrameList::FrameData::FrameData(QuicStreamOffset offset, string segment)
12 : offset(offset), segment(segment) {}
13
14 QuicFrameList::QuicFrameList() {}
15
16 QuicFrameList::~QuicFrameList() {
17 Clear();
18 }
19
20 QuicErrorCode QuicFrameList::WriteAtOffset(QuicStreamOffset offset,
21 StringPiece data,
22 size_t* const bytes_written) {
23 *bytes_written = 0;
24 const size_t data_len = data.size();
25 auto insertion_point = FindInsertionPoint(offset, data_len);
26 if (IsDuplicate(offset, data_len, insertion_point)) {
27 return QUIC_NO_ERROR;
28 }
29
30 if (FrameOverlapsBufferedData(offset, data_len, insertion_point)) {
31 return QUIC_INVALID_STREAM_DATA;
32 }
33
34 DVLOG(1) << "Buffering stream data at offset " << offset;
35 // Inserting an empty string and then copying to avoid the extra copy.
36 insertion_point = frame_list_.insert(insertion_point, FrameData(offset, ""));
37 data.CopyToString(&insertion_point->segment);
38 *bytes_written = data_len;
39 return QUIC_NO_ERROR;
40 }
41
42 // Finds the place the frame should be inserted. If an identical frame is
43 // present, stops on the identical frame.
44 list<QuicFrameList::FrameData>::iterator QuicFrameList::FindInsertionPoint(
45 QuicStreamOffset offset,
46 size_t len) {
47 if (frame_list_.empty()) {
48 return frame_list_.begin();
49 }
50 // If it's after all buffered_frames, return the end.
51 if (offset >=
52 (frame_list_.rbegin()->offset + frame_list_.rbegin()->segment.length())) {
53 return frame_list_.end();
54 }
55 auto iter = frame_list_.begin();
56 // Only advance the iterator if the data begins after the already received
57 // frame. If the new frame overlaps with an existing frame, the iterator will
58 // still point to the frame it overlaps with.
59 while (iter != frame_list_.end() &&
60 offset >= iter->offset + iter->segment.length()) {
61 ++iter;
62 }
63 return iter;
64 }
65
66 // Returns true if |frame| contains data which overlaps buffered data
67 // (indicating an invalid stream frame has been received).
68 bool QuicFrameList::FrameOverlapsBufferedData(
69 QuicStreamOffset offset,
70 size_t data_len,
71 list<FrameData>::const_iterator insertion_point) const {
72 if (frame_list_.empty() || insertion_point == frame_list_.end()) {
73 return false;
74 }
75 // If there is a buffered frame with a higher starting offset, then check to
76 // see if the new frame overlaps the beginning of the higher frame.
77 if (offset < insertion_point->offset &&
78 offset + data_len > insertion_point->offset) {
79 DVLOG(1) << "New frame overlaps next frame: " << offset << " + " << data_len
80 << " > " << insertion_point->offset;
81 return true;
82 }
83 // If there is a buffered frame with a lower starting offset, then check to
84 // see if the buffered frame runs into the new frame.
85 if (offset >= insertion_point->offset &&
86 offset < insertion_point->offset + insertion_point->segment.length()) {
87 DVLOG(1) << "Preceeding frame overlaps new frame: "
88 << insertion_point->offset << " + "
89 << insertion_point->segment.length() << " > " << offset;
90 return true;
91 }
92
93 return false;
94 }
95
96 // Returns true if the sequencer has received this frame before.
97 bool QuicFrameList::IsDuplicate(
98 QuicStreamOffset offset,
99 size_t data_len,
100 list<FrameData>::const_iterator insertion_point) const {
101 // A frame is duplicate if the frame offset is smaller than the bytes consumed
102 // or identical to an already received frame.
103 return offset < total_bytes_read_ || (insertion_point != frame_list_.end() &&
104 offset == insertion_point->offset);
105 }
106
107 int QuicFrameList::GetReadableRegions(struct iovec* iov, int iov_len) const {
108 list<FrameData>::const_iterator it = frame_list_.begin();
109 int index = 0;
110 QuicStreamOffset offset = total_bytes_read_;
111 while (it != frame_list_.end() && index < iov_len) {
112 if (it->offset != offset) {
113 return index;
114 }
115
116 iov[index].iov_base =
117 static_cast<void*>(const_cast<char*>(it->segment.data()));
118 iov[index].iov_len = it->segment.size();
119 offset += it->segment.size();
120
121 ++index;
122 ++it;
123 }
124 return index;
125 }
126
127 bool QuicFrameList::IncreaseTotalReadAndInvalidate(size_t bytes_used) {
128 size_t end_offset = total_bytes_read_ + bytes_used;
129 while (!frame_list_.empty() && end_offset != total_bytes_read_) {
130 list<FrameData>::iterator it = frame_list_.begin();
131 if (it->offset != total_bytes_read_) {
132 return false;
133 }
134
135 if (it->offset + it->segment.length() <= end_offset) {
136 total_bytes_read_ += it->segment.length();
137 // This chunk is entirely consumed.
138 frame_list_.erase(it);
139 continue;
140 }
141
142 // Partially consume this frame.
143 size_t delta = end_offset - it->offset;
144 total_bytes_read_ += delta;
145 string new_data = it->segment.substr(delta);
146 frame_list_.erase(it);
147 frame_list_.push_front(FrameData(total_bytes_read_, new_data));
148 break;
149 }
150 return true;
151 }
152
153 size_t QuicFrameList::ReadvAndInvalidate(const struct iovec* iov,
154 size_t iov_len) {
155 list<FrameData>::iterator it = frame_list_.begin();
156 size_t iov_index = 0;
157 size_t iov_offset = 0;
158 size_t frame_offset = 0;
159 QuicStreamOffset initial_bytes_consumed = total_bytes_read_;
160
161 while (iov_index < iov_len && it != frame_list_.end() &&
162 it->offset == total_bytes_read_) {
163 int bytes_to_read = std::min(iov[iov_index].iov_len - iov_offset,
164 it->segment.size() - frame_offset);
165
166 char* iov_ptr = static_cast<char*>(iov[iov_index].iov_base) + iov_offset;
167 memcpy(iov_ptr, it->segment.data() + frame_offset, bytes_to_read);
168 frame_offset += bytes_to_read;
169 iov_offset += bytes_to_read;
170
171 if (iov[iov_index].iov_len == iov_offset) {
172 // We've filled this buffer.
173 iov_offset = 0;
174 ++iov_index;
175 }
176 if (it->segment.size() == frame_offset) {
177 // We've copied this whole frame
178 total_bytes_read_ += it->segment.size();
179 frame_list_.erase(it);
180 it = frame_list_.begin();
181 frame_offset = 0;
182 }
183 }
184 // Done copying. If there is a partial frame, update it.
185 if (frame_offset != 0) {
186 frame_list_.push_front(
187 FrameData(it->offset + frame_offset, it->segment.substr(frame_offset)));
188 frame_list_.erase(it);
189 total_bytes_read_ += frame_offset;
190 }
191 return total_bytes_read_ - initial_bytes_consumed;
192 }
193
194 bool QuicFrameList::HasBytesToRead() const {
195 return !frame_list_.empty() &&
196 frame_list_.begin()->offset == total_bytes_read_;
197 }
198 } // namespace net_quic
OLDNEW
« no previous file with comments | « net/quic/quic_frame_list.h ('k') | net/quic/quic_stream_sequencer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698