| OLD | NEW |
| (Empty) |
| 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 NET_QUIC_QUIC_WRITE_BLOCKED_LIST_H_ | |
| 6 #define NET_QUIC_QUIC_WRITE_BLOCKED_LIST_H_ | |
| 7 | |
| 8 #include <stddef.h> | |
| 9 #include <stdint.h> | |
| 10 | |
| 11 #include <set> | |
| 12 | |
| 13 #include "base/macros.h" | |
| 14 #include "net/base/net_export.h" | |
| 15 #include "net/quic/quic_flags.h" | |
| 16 #include "net/quic/quic_protocol.h" | |
| 17 #include "net/spdy/priority_write_scheduler.h" | |
| 18 | |
| 19 namespace net { | |
| 20 | |
| 21 // Keeps tracks of the QUIC streams that have data to write, sorted by | |
| 22 // priority. QUIC stream priority order is: | |
| 23 // Crypto stream > Headers stream > Data streams by requested priority. | |
| 24 class NET_EXPORT_PRIVATE QuicWriteBlockedList { | |
| 25 private: | |
| 26 typedef PriorityWriteScheduler<QuicStreamId> QuicPriorityWriteScheduler; | |
| 27 | |
| 28 public: | |
| 29 QuicWriteBlockedList(); | |
| 30 ~QuicWriteBlockedList(); | |
| 31 | |
| 32 bool HasWriteBlockedDataStreams() const { | |
| 33 return priority_write_scheduler_.HasReadyStreams(); | |
| 34 } | |
| 35 | |
| 36 bool HasWriteBlockedCryptoOrHeadersStream() const { | |
| 37 return crypto_stream_blocked_ || headers_stream_blocked_; | |
| 38 } | |
| 39 | |
| 40 size_t NumBlockedStreams() const { | |
| 41 size_t num_blocked = priority_write_scheduler_.NumReadyStreams(); | |
| 42 if (crypto_stream_blocked_) { | |
| 43 ++num_blocked; | |
| 44 } | |
| 45 if (headers_stream_blocked_) { | |
| 46 ++num_blocked; | |
| 47 } | |
| 48 | |
| 49 return num_blocked; | |
| 50 } | |
| 51 | |
| 52 bool ShouldYield(QuicStreamId id) const { | |
| 53 if (id == kCryptoStreamId) { | |
| 54 return false; // The crypto stream yields to none. | |
| 55 } | |
| 56 if (crypto_stream_blocked_) { | |
| 57 return true; // If the crypto stream is blocked, all other streams yield. | |
| 58 } | |
| 59 if (id == kHeadersStreamId) { | |
| 60 return false; // The crypto stream isn't blocked so headers won't yield. | |
| 61 } | |
| 62 if (headers_stream_blocked_) { | |
| 63 return true; // All data streams yield to the headers stream. | |
| 64 } | |
| 65 | |
| 66 return priority_write_scheduler_.ShouldYield(id); | |
| 67 } | |
| 68 | |
| 69 // Pops the highest priorty stream, special casing crypto and headers streams. | |
| 70 // Latches the most recently popped data stream for batch writing purposes. | |
| 71 QuicStreamId PopFront() { | |
| 72 if (crypto_stream_blocked_) { | |
| 73 crypto_stream_blocked_ = false; | |
| 74 return kCryptoStreamId; | |
| 75 } | |
| 76 | |
| 77 if (headers_stream_blocked_) { | |
| 78 headers_stream_blocked_ = false; | |
| 79 return kHeadersStreamId; | |
| 80 } | |
| 81 | |
| 82 const auto id_and_precedence = | |
| 83 priority_write_scheduler_.PopNextReadyStreamAndPrecedence(); | |
| 84 const QuicStreamId id = std::get<0>(id_and_precedence); | |
| 85 const SpdyPriority priority = | |
| 86 std::get<1>(id_and_precedence).spdy3_priority(); | |
| 87 | |
| 88 if (!priority_write_scheduler_.HasReadyStreams()) { | |
| 89 // If no streams are blocked, don't bother latching. This stream will be | |
| 90 // the first popped for its priority anyway. | |
| 91 batch_write_stream_id_[priority] = 0; | |
| 92 last_priority_popped_ = priority; | |
| 93 } else if (batch_write_stream_id_[priority] != id) { | |
| 94 // If newly latching this batch write stream, let it write 16k. | |
| 95 batch_write_stream_id_[priority] = id; | |
| 96 bytes_left_for_batch_write_[priority] = 16000; | |
| 97 last_priority_popped_ = priority; | |
| 98 } | |
| 99 | |
| 100 return id; | |
| 101 } | |
| 102 | |
| 103 void RegisterStream(QuicStreamId stream_id, SpdyPriority priority) { | |
| 104 priority_write_scheduler_.RegisterStream(stream_id, | |
| 105 SpdyStreamPrecedence(priority)); | |
| 106 } | |
| 107 | |
| 108 void UnregisterStream(QuicStreamId stream_id) { | |
| 109 priority_write_scheduler_.UnregisterStream(stream_id); | |
| 110 } | |
| 111 | |
| 112 void UpdateStreamPriority(QuicStreamId stream_id, SpdyPriority new_priority) { | |
| 113 priority_write_scheduler_.UpdateStreamPrecedence( | |
| 114 stream_id, SpdyStreamPrecedence(new_priority)); | |
| 115 } | |
| 116 | |
| 117 void UpdateBytesForStream(QuicStreamId stream_id, size_t bytes) { | |
| 118 if (batch_write_stream_id_[last_priority_popped_] == stream_id) { | |
| 119 // If this was the last data stream popped by PopFront, update the | |
| 120 // bytes remaining in its batch write. | |
| 121 bytes_left_for_batch_write_[last_priority_popped_] -= | |
| 122 static_cast<int32_t>(bytes); | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 // Pushes a stream to the back of the list for its priority level *unless* | |
| 127 // it is latched for doing batched writes in which case it goes to the front | |
| 128 // of the list for its priority level. | |
| 129 // Headers and crypto streams are special cased to always resume first. | |
| 130 void AddStream(QuicStreamId stream_id) { | |
| 131 if (stream_id == kCryptoStreamId) { | |
| 132 // TODO(avd) Add DCHECK(!crypto_stream_blocked_) | |
| 133 crypto_stream_blocked_ = true; | |
| 134 return; | |
| 135 } | |
| 136 | |
| 137 if (stream_id == kHeadersStreamId) { | |
| 138 // TODO(avd) Add DCHECK(!headers_stream_blocked_); | |
| 139 headers_stream_blocked_ = true; | |
| 140 return; | |
| 141 } | |
| 142 bool push_front = | |
| 143 stream_id == batch_write_stream_id_[last_priority_popped_] && | |
| 144 bytes_left_for_batch_write_[last_priority_popped_] > 0; | |
| 145 priority_write_scheduler_.MarkStreamReady(stream_id, push_front); | |
| 146 | |
| 147 return; | |
| 148 } | |
| 149 | |
| 150 bool crypto_stream_blocked() const { return crypto_stream_blocked_; } | |
| 151 bool headers_stream_blocked() const { return headers_stream_blocked_; } | |
| 152 | |
| 153 private: | |
| 154 QuicPriorityWriteScheduler priority_write_scheduler_; | |
| 155 | |
| 156 // If performing batch writes, this will be the stream ID of the stream doing | |
| 157 // batch writes for this priority level. We will allow this stream to write | |
| 158 // until it has written kBatchWriteSize bytes, it has no more data to write, | |
| 159 // or a higher priority stream preempts. | |
| 160 QuicStreamId batch_write_stream_id_[kV3LowestPriority + 1]; | |
| 161 // Set to kBatchWriteSize when we set a new batch_write_stream_id_ for a given | |
| 162 // priority. This is decremented with each write the stream does until it is | |
| 163 // done with its batch write. | |
| 164 int32_t bytes_left_for_batch_write_[kV3LowestPriority + 1]; | |
| 165 // Tracks the last priority popped for UpdateBytesForStream. | |
| 166 SpdyPriority last_priority_popped_; | |
| 167 | |
| 168 bool crypto_stream_blocked_; | |
| 169 bool headers_stream_blocked_; | |
| 170 | |
| 171 DISALLOW_COPY_AND_ASSIGN(QuicWriteBlockedList); | |
| 172 }; | |
| 173 | |
| 174 } // namespace net | |
| 175 | |
| 176 #endif // NET_QUIC_QUIC_WRITE_BLOCKED_LIST_H_ | |
| OLD | NEW |