1*6777b538SAndroid Build Coastguard Worker // Copyright 2013 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "net/spdy/spdy_write_queue.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <cstddef>
8*6777b538SAndroid Build Coastguard Worker #include <utility>
9*6777b538SAndroid Build Coastguard Worker #include <vector>
10*6777b538SAndroid Build Coastguard Worker
11*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/containers/circular_deque.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/trace_event/memory_usage_estimator.h"
14*6777b538SAndroid Build Coastguard Worker #include "net/spdy/spdy_buffer.h"
15*6777b538SAndroid Build Coastguard Worker #include "net/spdy/spdy_buffer_producer.h"
16*6777b538SAndroid Build Coastguard Worker #include "net/spdy/spdy_stream.h"
17*6777b538SAndroid Build Coastguard Worker
18*6777b538SAndroid Build Coastguard Worker namespace net {
19*6777b538SAndroid Build Coastguard Worker
IsSpdyFrameTypeWriteCapped(spdy::SpdyFrameType frame_type)20*6777b538SAndroid Build Coastguard Worker bool IsSpdyFrameTypeWriteCapped(spdy::SpdyFrameType frame_type) {
21*6777b538SAndroid Build Coastguard Worker return frame_type == spdy::SpdyFrameType::RST_STREAM ||
22*6777b538SAndroid Build Coastguard Worker frame_type == spdy::SpdyFrameType::SETTINGS ||
23*6777b538SAndroid Build Coastguard Worker frame_type == spdy::SpdyFrameType::WINDOW_UPDATE ||
24*6777b538SAndroid Build Coastguard Worker frame_type == spdy::SpdyFrameType::PING ||
25*6777b538SAndroid Build Coastguard Worker frame_type == spdy::SpdyFrameType::GOAWAY;
26*6777b538SAndroid Build Coastguard Worker }
27*6777b538SAndroid Build Coastguard Worker
28*6777b538SAndroid Build Coastguard Worker SpdyWriteQueue::PendingWrite::PendingWrite() = default;
29*6777b538SAndroid Build Coastguard Worker
PendingWrite(spdy::SpdyFrameType frame_type,std::unique_ptr<SpdyBufferProducer> frame_producer,const base::WeakPtr<SpdyStream> & stream,const MutableNetworkTrafficAnnotationTag & traffic_annotation)30*6777b538SAndroid Build Coastguard Worker SpdyWriteQueue::PendingWrite::PendingWrite(
31*6777b538SAndroid Build Coastguard Worker spdy::SpdyFrameType frame_type,
32*6777b538SAndroid Build Coastguard Worker std::unique_ptr<SpdyBufferProducer> frame_producer,
33*6777b538SAndroid Build Coastguard Worker const base::WeakPtr<SpdyStream>& stream,
34*6777b538SAndroid Build Coastguard Worker const MutableNetworkTrafficAnnotationTag& traffic_annotation)
35*6777b538SAndroid Build Coastguard Worker : frame_type(frame_type),
36*6777b538SAndroid Build Coastguard Worker frame_producer(std::move(frame_producer)),
37*6777b538SAndroid Build Coastguard Worker stream(stream),
38*6777b538SAndroid Build Coastguard Worker traffic_annotation(traffic_annotation),
39*6777b538SAndroid Build Coastguard Worker has_stream(stream.get() != nullptr) {}
40*6777b538SAndroid Build Coastguard Worker
41*6777b538SAndroid Build Coastguard Worker SpdyWriteQueue::PendingWrite::~PendingWrite() = default;
42*6777b538SAndroid Build Coastguard Worker
43*6777b538SAndroid Build Coastguard Worker SpdyWriteQueue::PendingWrite::PendingWrite(PendingWrite&& other) = default;
44*6777b538SAndroid Build Coastguard Worker SpdyWriteQueue::PendingWrite& SpdyWriteQueue::PendingWrite::operator=(
45*6777b538SAndroid Build Coastguard Worker PendingWrite&& other) = default;
46*6777b538SAndroid Build Coastguard Worker
47*6777b538SAndroid Build Coastguard Worker SpdyWriteQueue::SpdyWriteQueue() = default;
48*6777b538SAndroid Build Coastguard Worker
~SpdyWriteQueue()49*6777b538SAndroid Build Coastguard Worker SpdyWriteQueue::~SpdyWriteQueue() {
50*6777b538SAndroid Build Coastguard Worker DCHECK_GE(num_queued_capped_frames_, 0);
51*6777b538SAndroid Build Coastguard Worker Clear();
52*6777b538SAndroid Build Coastguard Worker }
53*6777b538SAndroid Build Coastguard Worker
IsEmpty() const54*6777b538SAndroid Build Coastguard Worker bool SpdyWriteQueue::IsEmpty() const {
55*6777b538SAndroid Build Coastguard Worker for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; i++) {
56*6777b538SAndroid Build Coastguard Worker if (!queue_[i].empty())
57*6777b538SAndroid Build Coastguard Worker return false;
58*6777b538SAndroid Build Coastguard Worker }
59*6777b538SAndroid Build Coastguard Worker return true;
60*6777b538SAndroid Build Coastguard Worker }
61*6777b538SAndroid Build Coastguard Worker
Enqueue(RequestPriority priority,spdy::SpdyFrameType frame_type,std::unique_ptr<SpdyBufferProducer> frame_producer,const base::WeakPtr<SpdyStream> & stream,const NetworkTrafficAnnotationTag & traffic_annotation)62*6777b538SAndroid Build Coastguard Worker void SpdyWriteQueue::Enqueue(
63*6777b538SAndroid Build Coastguard Worker RequestPriority priority,
64*6777b538SAndroid Build Coastguard Worker spdy::SpdyFrameType frame_type,
65*6777b538SAndroid Build Coastguard Worker std::unique_ptr<SpdyBufferProducer> frame_producer,
66*6777b538SAndroid Build Coastguard Worker const base::WeakPtr<SpdyStream>& stream,
67*6777b538SAndroid Build Coastguard Worker const NetworkTrafficAnnotationTag& traffic_annotation) {
68*6777b538SAndroid Build Coastguard Worker CHECK(!removing_writes_);
69*6777b538SAndroid Build Coastguard Worker CHECK_GE(priority, MINIMUM_PRIORITY);
70*6777b538SAndroid Build Coastguard Worker CHECK_LE(priority, MAXIMUM_PRIORITY);
71*6777b538SAndroid Build Coastguard Worker if (stream.get())
72*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(stream->priority(), priority);
73*6777b538SAndroid Build Coastguard Worker queue_[priority].push_back(
74*6777b538SAndroid Build Coastguard Worker {frame_type, std::move(frame_producer), stream,
75*6777b538SAndroid Build Coastguard Worker MutableNetworkTrafficAnnotationTag(traffic_annotation)});
76*6777b538SAndroid Build Coastguard Worker if (IsSpdyFrameTypeWriteCapped(frame_type)) {
77*6777b538SAndroid Build Coastguard Worker DCHECK_GE(num_queued_capped_frames_, 0);
78*6777b538SAndroid Build Coastguard Worker num_queued_capped_frames_++;
79*6777b538SAndroid Build Coastguard Worker }
80*6777b538SAndroid Build Coastguard Worker }
81*6777b538SAndroid Build Coastguard Worker
Dequeue(spdy::SpdyFrameType * frame_type,std::unique_ptr<SpdyBufferProducer> * frame_producer,base::WeakPtr<SpdyStream> * stream,MutableNetworkTrafficAnnotationTag * traffic_annotation)82*6777b538SAndroid Build Coastguard Worker bool SpdyWriteQueue::Dequeue(
83*6777b538SAndroid Build Coastguard Worker spdy::SpdyFrameType* frame_type,
84*6777b538SAndroid Build Coastguard Worker std::unique_ptr<SpdyBufferProducer>* frame_producer,
85*6777b538SAndroid Build Coastguard Worker base::WeakPtr<SpdyStream>* stream,
86*6777b538SAndroid Build Coastguard Worker MutableNetworkTrafficAnnotationTag* traffic_annotation) {
87*6777b538SAndroid Build Coastguard Worker CHECK(!removing_writes_);
88*6777b538SAndroid Build Coastguard Worker for (int i = MAXIMUM_PRIORITY; i >= MINIMUM_PRIORITY; --i) {
89*6777b538SAndroid Build Coastguard Worker if (!queue_[i].empty()) {
90*6777b538SAndroid Build Coastguard Worker PendingWrite pending_write = std::move(queue_[i].front());
91*6777b538SAndroid Build Coastguard Worker queue_[i].pop_front();
92*6777b538SAndroid Build Coastguard Worker *frame_type = pending_write.frame_type;
93*6777b538SAndroid Build Coastguard Worker *frame_producer = std::move(pending_write.frame_producer);
94*6777b538SAndroid Build Coastguard Worker *stream = pending_write.stream;
95*6777b538SAndroid Build Coastguard Worker *traffic_annotation = pending_write.traffic_annotation;
96*6777b538SAndroid Build Coastguard Worker if (pending_write.has_stream)
97*6777b538SAndroid Build Coastguard Worker DCHECK(stream->get());
98*6777b538SAndroid Build Coastguard Worker if (IsSpdyFrameTypeWriteCapped(*frame_type)) {
99*6777b538SAndroid Build Coastguard Worker num_queued_capped_frames_--;
100*6777b538SAndroid Build Coastguard Worker DCHECK_GE(num_queued_capped_frames_, 0);
101*6777b538SAndroid Build Coastguard Worker }
102*6777b538SAndroid Build Coastguard Worker return true;
103*6777b538SAndroid Build Coastguard Worker }
104*6777b538SAndroid Build Coastguard Worker }
105*6777b538SAndroid Build Coastguard Worker return false;
106*6777b538SAndroid Build Coastguard Worker }
107*6777b538SAndroid Build Coastguard Worker
RemovePendingWritesForStream(SpdyStream * stream)108*6777b538SAndroid Build Coastguard Worker void SpdyWriteQueue::RemovePendingWritesForStream(SpdyStream* stream) {
109*6777b538SAndroid Build Coastguard Worker CHECK(!removing_writes_);
110*6777b538SAndroid Build Coastguard Worker removing_writes_ = true;
111*6777b538SAndroid Build Coastguard Worker RequestPriority priority = stream->priority();
112*6777b538SAndroid Build Coastguard Worker CHECK_GE(priority, MINIMUM_PRIORITY);
113*6777b538SAndroid Build Coastguard Worker CHECK_LE(priority, MAXIMUM_PRIORITY);
114*6777b538SAndroid Build Coastguard Worker
115*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
116*6777b538SAndroid Build Coastguard Worker // |stream| should not have pending writes in a queue not matching
117*6777b538SAndroid Build Coastguard Worker // its priority.
118*6777b538SAndroid Build Coastguard Worker for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
119*6777b538SAndroid Build Coastguard Worker if (priority == i)
120*6777b538SAndroid Build Coastguard Worker continue;
121*6777b538SAndroid Build Coastguard Worker for (auto it = queue_[i].begin(); it != queue_[i].end(); ++it)
122*6777b538SAndroid Build Coastguard Worker DCHECK_NE(it->stream.get(), stream);
123*6777b538SAndroid Build Coastguard Worker }
124*6777b538SAndroid Build Coastguard Worker #endif
125*6777b538SAndroid Build Coastguard Worker
126*6777b538SAndroid Build Coastguard Worker // Defer deletion until queue iteration is complete, as
127*6777b538SAndroid Build Coastguard Worker // SpdyBuffer::~SpdyBuffer() can result in callbacks into SpdyWriteQueue.
128*6777b538SAndroid Build Coastguard Worker std::vector<std::unique_ptr<SpdyBufferProducer>> erased_buffer_producers;
129*6777b538SAndroid Build Coastguard Worker base::circular_deque<PendingWrite>& queue = queue_[priority];
130*6777b538SAndroid Build Coastguard Worker for (auto it = queue.begin(); it != queue.end();) {
131*6777b538SAndroid Build Coastguard Worker if (it->stream.get() == stream) {
132*6777b538SAndroid Build Coastguard Worker if (IsSpdyFrameTypeWriteCapped(it->frame_type)) {
133*6777b538SAndroid Build Coastguard Worker num_queued_capped_frames_--;
134*6777b538SAndroid Build Coastguard Worker DCHECK_GE(num_queued_capped_frames_, 0);
135*6777b538SAndroid Build Coastguard Worker }
136*6777b538SAndroid Build Coastguard Worker erased_buffer_producers.push_back(std::move(it->frame_producer));
137*6777b538SAndroid Build Coastguard Worker it = queue.erase(it);
138*6777b538SAndroid Build Coastguard Worker } else {
139*6777b538SAndroid Build Coastguard Worker ++it;
140*6777b538SAndroid Build Coastguard Worker }
141*6777b538SAndroid Build Coastguard Worker }
142*6777b538SAndroid Build Coastguard Worker removing_writes_ = false;
143*6777b538SAndroid Build Coastguard Worker
144*6777b538SAndroid Build Coastguard Worker // Iteration on |queue| is completed. Now |erased_buffer_producers| goes out
145*6777b538SAndroid Build Coastguard Worker // of scope, SpdyBufferProducers are destroyed.
146*6777b538SAndroid Build Coastguard Worker }
147*6777b538SAndroid Build Coastguard Worker
RemovePendingWritesForStreamsAfter(spdy::SpdyStreamId last_good_stream_id)148*6777b538SAndroid Build Coastguard Worker void SpdyWriteQueue::RemovePendingWritesForStreamsAfter(
149*6777b538SAndroid Build Coastguard Worker spdy::SpdyStreamId last_good_stream_id) {
150*6777b538SAndroid Build Coastguard Worker CHECK(!removing_writes_);
151*6777b538SAndroid Build Coastguard Worker removing_writes_ = true;
152*6777b538SAndroid Build Coastguard Worker
153*6777b538SAndroid Build Coastguard Worker // Defer deletion until queue iteration is complete, as
154*6777b538SAndroid Build Coastguard Worker // SpdyBuffer::~SpdyBuffer() can result in callbacks into SpdyWriteQueue.
155*6777b538SAndroid Build Coastguard Worker std::vector<std::unique_ptr<SpdyBufferProducer>> erased_buffer_producers;
156*6777b538SAndroid Build Coastguard Worker for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
157*6777b538SAndroid Build Coastguard Worker base::circular_deque<PendingWrite>& queue = queue_[i];
158*6777b538SAndroid Build Coastguard Worker for (auto it = queue.begin(); it != queue.end();) {
159*6777b538SAndroid Build Coastguard Worker if (it->stream.get() && (it->stream->stream_id() > last_good_stream_id ||
160*6777b538SAndroid Build Coastguard Worker it->stream->stream_id() == 0)) {
161*6777b538SAndroid Build Coastguard Worker if (IsSpdyFrameTypeWriteCapped(it->frame_type)) {
162*6777b538SAndroid Build Coastguard Worker num_queued_capped_frames_--;
163*6777b538SAndroid Build Coastguard Worker DCHECK_GE(num_queued_capped_frames_, 0);
164*6777b538SAndroid Build Coastguard Worker }
165*6777b538SAndroid Build Coastguard Worker erased_buffer_producers.push_back(std::move(it->frame_producer));
166*6777b538SAndroid Build Coastguard Worker it = queue.erase(it);
167*6777b538SAndroid Build Coastguard Worker } else {
168*6777b538SAndroid Build Coastguard Worker ++it;
169*6777b538SAndroid Build Coastguard Worker }
170*6777b538SAndroid Build Coastguard Worker }
171*6777b538SAndroid Build Coastguard Worker }
172*6777b538SAndroid Build Coastguard Worker removing_writes_ = false;
173*6777b538SAndroid Build Coastguard Worker
174*6777b538SAndroid Build Coastguard Worker // Iteration on each |queue| is completed. Now |erased_buffer_producers| goes
175*6777b538SAndroid Build Coastguard Worker // out of scope, SpdyBufferProducers are destroyed.
176*6777b538SAndroid Build Coastguard Worker }
177*6777b538SAndroid Build Coastguard Worker
ChangePriorityOfWritesForStream(SpdyStream * stream,RequestPriority old_priority,RequestPriority new_priority)178*6777b538SAndroid Build Coastguard Worker void SpdyWriteQueue::ChangePriorityOfWritesForStream(
179*6777b538SAndroid Build Coastguard Worker SpdyStream* stream,
180*6777b538SAndroid Build Coastguard Worker RequestPriority old_priority,
181*6777b538SAndroid Build Coastguard Worker RequestPriority new_priority) {
182*6777b538SAndroid Build Coastguard Worker CHECK(!removing_writes_);
183*6777b538SAndroid Build Coastguard Worker DCHECK(stream);
184*6777b538SAndroid Build Coastguard Worker
185*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
186*6777b538SAndroid Build Coastguard Worker // |stream| should not have pending writes in a queue not matching
187*6777b538SAndroid Build Coastguard Worker // |old_priority|.
188*6777b538SAndroid Build Coastguard Worker for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
189*6777b538SAndroid Build Coastguard Worker if (i == old_priority)
190*6777b538SAndroid Build Coastguard Worker continue;
191*6777b538SAndroid Build Coastguard Worker for (auto it = queue_[i].begin(); it != queue_[i].end(); ++it)
192*6777b538SAndroid Build Coastguard Worker DCHECK_NE(it->stream.get(), stream);
193*6777b538SAndroid Build Coastguard Worker }
194*6777b538SAndroid Build Coastguard Worker #endif
195*6777b538SAndroid Build Coastguard Worker
196*6777b538SAndroid Build Coastguard Worker base::circular_deque<PendingWrite>& old_queue = queue_[old_priority];
197*6777b538SAndroid Build Coastguard Worker base::circular_deque<PendingWrite>& new_queue = queue_[new_priority];
198*6777b538SAndroid Build Coastguard Worker for (auto it = old_queue.begin(); it != old_queue.end();) {
199*6777b538SAndroid Build Coastguard Worker if (it->stream.get() == stream) {
200*6777b538SAndroid Build Coastguard Worker new_queue.push_back(std::move(*it));
201*6777b538SAndroid Build Coastguard Worker it = old_queue.erase(it);
202*6777b538SAndroid Build Coastguard Worker } else {
203*6777b538SAndroid Build Coastguard Worker ++it;
204*6777b538SAndroid Build Coastguard Worker }
205*6777b538SAndroid Build Coastguard Worker }
206*6777b538SAndroid Build Coastguard Worker }
207*6777b538SAndroid Build Coastguard Worker
Clear()208*6777b538SAndroid Build Coastguard Worker void SpdyWriteQueue::Clear() {
209*6777b538SAndroid Build Coastguard Worker CHECK(!removing_writes_);
210*6777b538SAndroid Build Coastguard Worker removing_writes_ = true;
211*6777b538SAndroid Build Coastguard Worker std::vector<std::unique_ptr<SpdyBufferProducer>> erased_buffer_producers;
212*6777b538SAndroid Build Coastguard Worker
213*6777b538SAndroid Build Coastguard Worker for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
214*6777b538SAndroid Build Coastguard Worker for (auto& pending_write : queue_[i]) {
215*6777b538SAndroid Build Coastguard Worker erased_buffer_producers.push_back(
216*6777b538SAndroid Build Coastguard Worker std::move(pending_write.frame_producer));
217*6777b538SAndroid Build Coastguard Worker }
218*6777b538SAndroid Build Coastguard Worker queue_[i].clear();
219*6777b538SAndroid Build Coastguard Worker }
220*6777b538SAndroid Build Coastguard Worker removing_writes_ = false;
221*6777b538SAndroid Build Coastguard Worker num_queued_capped_frames_ = 0;
222*6777b538SAndroid Build Coastguard Worker }
223*6777b538SAndroid Build Coastguard Worker
224*6777b538SAndroid Build Coastguard Worker } // namespace net
225