• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 #ifndef QUICHE_QUIC_CORE_QUIC_WRITE_BLOCKED_LIST_H_
6 #define QUICHE_QUIC_CORE_QUIC_WRITE_BLOCKED_LIST_H_
7 
8 #include <cstddef>
9 #include <cstdint>
10 #include <utility>
11 
12 #include "absl/container/inlined_vector.h"
13 #include "quiche/http2/core/priority_write_scheduler.h"
14 #include "quiche/quic/core/quic_packets.h"
15 #include "quiche/quic/core/quic_stream_priority.h"
16 #include "quiche/quic/platform/api/quic_bug_tracker.h"
17 #include "quiche/quic/platform/api/quic_export.h"
18 #include "quiche/quic/platform/api/quic_flags.h"
19 #include "quiche/spdy/core/spdy_protocol.h"
20 
21 namespace quic {
22 
23 // Keeps tracks of the order of QUIC streams that have data to write.
24 // Static streams come first, in the order they were registered with
25 // QuicWriteBlockedList.  They are followed by non-static streams, ordered by
26 // priority.
27 class QUICHE_EXPORT QuicWriteBlockedListInterface {
28  public:
29   virtual ~QuicWriteBlockedListInterface() = default;
30 
31   virtual bool HasWriteBlockedDataStreams() const = 0;
32   virtual size_t NumBlockedSpecialStreams() const = 0;
33   virtual size_t NumBlockedStreams() const = 0;
HasWriteBlockedSpecialStream()34   bool HasWriteBlockedSpecialStream() const {
35     return NumBlockedSpecialStreams() > 0;
36   }
37 
38   // Returns true if there is another stream with higher priority in the queue.
39   virtual bool ShouldYield(QuicStreamId id) const = 0;
40 
41   // Returns the priority of the specified stream.
42   virtual QuicStreamPriority GetPriorityOfStream(QuicStreamId id) const = 0;
43 
44   // Pops the highest priority stream, special casing static streams. Latches
45   // the most recently popped data stream for batch writing purposes.
46   virtual QuicStreamId PopFront() = 0;
47 
48   // Register a stream with given priority.
49   // `priority` is ignored for static streams.
50   virtual void RegisterStream(QuicStreamId stream_id, bool is_static_stream,
51                               const QuicStreamPriority& priority) = 0;
52 
53   // Unregister a stream.  `stream_id` must be registered, either as a static
54   // stream or as a non-static stream.
55   virtual void UnregisterStream(QuicStreamId stream_id) = 0;
56 
57   // Updates the stored priority of a stream.  Must not be called for static
58   // streams.
59   virtual void UpdateStreamPriority(QuicStreamId stream_id,
60                                     const QuicStreamPriority& new_priority) = 0;
61 
62   // TODO(b/147306124): Remove when deprecating
63   // reloadable_flag_quic_disable_batch_write.
64   virtual void UpdateBytesForStream(QuicStreamId stream_id, size_t bytes) = 0;
65 
66   // Pushes a stream to the back of the list for its priority level *unless* it
67   // is latched for doing batched writes in which case it goes to the front of
68   // the list for its priority level.
69   // Static streams are special cased to always resume first.
70   // Stream must already be registered.
71   virtual void AddStream(QuicStreamId stream_id) = 0;
72 
73   // Returns true if stream with |stream_id| is write blocked.
74   virtual bool IsStreamBlocked(QuicStreamId stream_id) const = 0;
75 };
76 
77 // Default implementation of QuicWriteBlockedListInterface.
78 class QUIC_EXPORT_PRIVATE QuicWriteBlockedList
79     : public QuicWriteBlockedListInterface {
80  public:
81   explicit QuicWriteBlockedList();
82   QuicWriteBlockedList(const QuicWriteBlockedList&) = delete;
83   QuicWriteBlockedList& operator=(const QuicWriteBlockedList&) = delete;
84 
HasWriteBlockedDataStreams()85   bool HasWriteBlockedDataStreams() const override {
86     return priority_write_scheduler_.HasReadyStreams();
87   }
88 
NumBlockedSpecialStreams()89   size_t NumBlockedSpecialStreams() const override {
90     return static_stream_collection_.num_blocked();
91   }
92 
NumBlockedStreams()93   size_t NumBlockedStreams() const override {
94     return NumBlockedSpecialStreams() +
95            priority_write_scheduler_.NumReadyStreams();
96   }
97 
98   bool ShouldYield(QuicStreamId id) const override;
99 
GetPriorityOfStream(QuicStreamId id)100   QuicStreamPriority GetPriorityOfStream(QuicStreamId id) const override {
101     return QuicStreamPriority(priority_write_scheduler_.GetStreamPriority(id));
102   }
103 
104   // Pops the highest priority stream, special casing static streams. Latches
105   // the most recently popped data stream for batch writing purposes.
106   QuicStreamId PopFront() override;
107 
108   // Register a stream with given priority.
109   // `priority` is ignored for static streams.
110   void RegisterStream(QuicStreamId stream_id, bool is_static_stream,
111                       const QuicStreamPriority& priority) override;
112 
113   // Unregister a stream.  `stream_id` must be registered, either as a static
114   // stream or as a non-static stream.
115   void UnregisterStream(QuicStreamId stream_id) override;
116 
117   // Updates the stored priority of a stream.  Must not be called for static
118   // streams.
119   void UpdateStreamPriority(QuicStreamId stream_id,
120                             const QuicStreamPriority& new_priority) override;
121 
122   // TODO(b/147306124): Remove when deprecating
123   // reloadable_flag_quic_disable_batch_write.
124   void UpdateBytesForStream(QuicStreamId stream_id, size_t bytes) override;
125 
126   // Pushes a stream to the back of the list for its priority level *unless* it
127   // is latched for doing batched writes in which case it goes to the front of
128   // the list for its priority level.
129   // Static streams are special cased to always resume first.
130   // Stream must already be registered.
131   void AddStream(QuicStreamId stream_id) override;
132 
133   // Returns true if stream with |stream_id| is write blocked.
134   bool IsStreamBlocked(QuicStreamId stream_id) const override;
135 
136  private:
137   struct QUICHE_EXPORT HttpStreamPriorityToInt {
operatorHttpStreamPriorityToInt138     int operator()(const HttpStreamPriority& priority) {
139       return priority.urgency;
140     }
141   };
142 
143   struct QUICHE_EXPORT IntToHttpStreamPriority {
operatorIntToHttpStreamPriority144     HttpStreamPriority operator()(int urgency) {
145       return HttpStreamPriority{urgency};
146     }
147   };
148   http2::PriorityWriteScheduler<QuicStreamId, HttpStreamPriority,
149                                 HttpStreamPriorityToInt,
150                                 IntToHttpStreamPriority>
151       priority_write_scheduler_;
152 
153   // If performing batch writes, this will be the stream ID of the stream doing
154   // batch writes for this priority level.  We will allow this stream to write
155   // until it has written kBatchWriteSize bytes, it has no more data to write,
156   // or a higher priority stream preempts.
157   QuicStreamId batch_write_stream_id_[spdy::kV3LowestPriority + 1];
158   // Set to kBatchWriteSize when we set a new batch_write_stream_id_ for a given
159   // priority.  This is decremented with each write the stream does until it is
160   // done with its batch write.
161   // TODO(b/147306124): Remove when deprecating
162   // reloadable_flag_quic_disable_batch_write.
163   size_t bytes_left_for_batch_write_[spdy::kV3LowestPriority + 1];
164   // Tracks the last priority popped for UpdateBytesForStream() and AddStream().
165   spdy::SpdyPriority last_priority_popped_;
166 
167   // A StaticStreamCollection is a vector of <QuicStreamId, bool> pairs plus a
168   // eagerly-computed number of blocked static streams.
169   class QUIC_EXPORT_PRIVATE StaticStreamCollection {
170    public:
171     struct QUIC_EXPORT_PRIVATE StreamIdBlockedPair {
172       QuicStreamId id;
173       bool is_blocked;
174     };
175 
176     // Optimized for the typical case of 2 static streams per session.
177     using StreamsVector = absl::InlinedVector<StreamIdBlockedPair, 2>;
178 
begin()179     StreamsVector::const_iterator begin() const { return streams_.cbegin(); }
180 
end()181     StreamsVector::const_iterator end() const { return streams_.cend(); }
182 
num_blocked()183     size_t num_blocked() const { return num_blocked_; }
184 
185     // Add |id| to the collection in unblocked state.
186     void Register(QuicStreamId id);
187 
188     // True if |id| is in the collection, regardless of its state.
189     bool IsRegistered(QuicStreamId id) const;
190 
191     // Remove |id| from the collection.  If it is in the blocked state, reduce
192     // |num_blocked_| by 1.  Returns true if |id| was in the collection.
193     bool Unregister(QuicStreamId id);
194 
195     // Set |id| to be blocked. If |id| is not already blocked, increase
196     // |num_blocked_| by 1.
197     // Return true if |id| is in the collection.
198     bool SetBlocked(QuicStreamId id);
199 
200     // Unblock the first blocked stream in the collection.
201     // If no stream is blocked, return false. Otherwise return true, set *id to
202     // the unblocked stream id and reduce |num_blocked_| by 1.
203     bool UnblockFirstBlocked(QuicStreamId* id);
204 
205    private:
206     size_t num_blocked_ = 0;
207     StreamsVector streams_;
208   };
209 
210   StaticStreamCollection static_stream_collection_;
211 
212   // Latched value of reloadable_flag_quic_priority_respect_incremental.
213   const bool respect_incremental_;
214   // Latched value of reloadable_flag_quic_disable_batch_write.
215   const bool disable_batch_write_;
216 };
217 
218 }  // namespace quic
219 
220 #endif  // QUICHE_QUIC_CORE_QUIC_WRITE_BLOCKED_LIST_H_
221