Move lengthy inline functions from headers file to the .cc file. This is following the C++ style guide: "Define functions inline only when they are small, say, 10 lines or fewer. Inlining a very small accessor function will usually decrease code size while inlining a very large function can dramatically increase code size." No behavior change. not protected. PiperOrigin-RevId: 325052309 Change-Id: Iede30d11e3ca118e763db000d11f56fbd7cae1f6
diff --git a/quic/core/quic_write_blocked_list.cc b/quic/core/quic_write_blocked_list.cc index 123a963..3c1edc4 100644 --- a/quic/core/quic_write_blocked_list.cc +++ b/quic/core/quic_write_blocked_list.cc
@@ -23,4 +23,229 @@ QuicWriteBlockedList::~QuicWriteBlockedList() {} +bool QuicWriteBlockedList::ShouldYield(QuicStreamId id) const { + for (const auto& stream : static_stream_collection_) { + if (stream.id == id) { + // Static streams should never yield to data streams, or to lower + // priority static stream. + return false; + } + if (stream.is_blocked) { + return true; // All data streams yield to static streams. + } + } + + return priority_write_scheduler_->ShouldYield(id); +} + +bool QuicWriteBlockedList::SwitchWriteScheduler(spdy::WriteSchedulerType type, + QuicTransportVersion version) { + if (scheduler_type_ == type) { + return true; + } + if (priority_write_scheduler_->NumRegisteredStreams() != 0) { + QUIC_BUG << "Cannot switch scheduler with registered streams"; + return false; + } + QUIC_DVLOG(1) << "Switching to scheduler type: " + << spdy::WriteSchedulerTypeToString(type); + switch (type) { + case spdy::WriteSchedulerType::LIFO: + priority_write_scheduler_ = + std::make_unique<spdy::LifoWriteScheduler<QuicStreamId>>(); + break; + case spdy::WriteSchedulerType::SPDY: + priority_write_scheduler_ = + std::make_unique<spdy::PriorityWriteScheduler<QuicStreamId>>( + QuicVersionUsesCryptoFrames(version) + ? std::numeric_limits<QuicStreamId>::max() + : 0); + break; + case spdy::WriteSchedulerType::HTTP2: + priority_write_scheduler_ = + std::make_unique<spdy::Http2PriorityWriteScheduler<QuicStreamId>>(); + break; + case spdy::WriteSchedulerType::FIFO: + priority_write_scheduler_ = + std::make_unique<spdy::FifoWriteScheduler<QuicStreamId>>(); + break; + default: + QUIC_BUG << "Scheduler is not supported for type: " + << spdy::WriteSchedulerTypeToString(type); + return false; + } + scheduler_type_ = type; + return true; +} + +QuicStreamId QuicWriteBlockedList::PopFront() { + QuicStreamId static_stream_id; + if (static_stream_collection_.UnblockFirstBlocked(&static_stream_id)) { + return static_stream_id; + } + + const auto id_and_precedence = + priority_write_scheduler_->PopNextReadyStreamAndPrecedence(); + const QuicStreamId id = std::get<0>(id_and_precedence); + if (scheduler_type_ != spdy::WriteSchedulerType::SPDY) { + // No batch writing logic for non-SPDY priority write scheduler. + return id; + } + const spdy::SpdyPriority priority = + std::get<1>(id_and_precedence).spdy3_priority(); + + if (!priority_write_scheduler_->HasReadyStreams()) { + // If no streams are blocked, don't bother latching. This stream will be + // the first popped for its priority anyway. + batch_write_stream_id_[priority] = 0; + last_priority_popped_ = priority; + } else if (batch_write_stream_id_[priority] != id) { + // If newly latching this batch write stream, let it write 16k. + batch_write_stream_id_[priority] = id; + bytes_left_for_batch_write_[priority] = 16000; + last_priority_popped_ = priority; + } + + return id; +} + +void QuicWriteBlockedList::RegisterStream( + QuicStreamId stream_id, + bool is_static_stream, + const spdy::SpdyStreamPrecedence& precedence) { + DCHECK(!priority_write_scheduler_->StreamRegistered(stream_id)) + << "stream " << stream_id << " already registered"; + DCHECK(PrecedenceMatchesSchedulerType(precedence)); + if (is_static_stream) { + static_stream_collection_.Register(stream_id); + return; + } + + priority_write_scheduler_->RegisterStream(stream_id, precedence); +} + +void QuicWriteBlockedList::UnregisterStream(QuicStreamId stream_id, + bool is_static) { + if (is_static) { + static_stream_collection_.Unregister(stream_id); + return; + } + priority_write_scheduler_->UnregisterStream(stream_id); +} + +void QuicWriteBlockedList::UpdateStreamPriority( + QuicStreamId stream_id, + const spdy::SpdyStreamPrecedence& new_precedence) { + DCHECK(!static_stream_collection_.IsRegistered(stream_id)); + DCHECK(PrecedenceMatchesSchedulerType(new_precedence)); + priority_write_scheduler_->UpdateStreamPrecedence(stream_id, new_precedence); +} + +void QuicWriteBlockedList::UpdateBytesForStream(QuicStreamId stream_id, + size_t bytes) { + if (scheduler_type_ != spdy::WriteSchedulerType::SPDY) { + return; + } + if (batch_write_stream_id_[last_priority_popped_] == stream_id) { + // If this was the last data stream popped by PopFront, update the + // bytes remaining in its batch write. + bytes_left_for_batch_write_[last_priority_popped_] -= + static_cast<int32_t>(bytes); + } +} + +void QuicWriteBlockedList::AddStream(QuicStreamId stream_id) { + if (static_stream_collection_.SetBlocked(stream_id)) { + return; + } + + bool push_front = + scheduler_type_ == spdy::WriteSchedulerType::SPDY && + stream_id == batch_write_stream_id_[last_priority_popped_] && + bytes_left_for_batch_write_[last_priority_popped_] > 0; + priority_write_scheduler_->MarkStreamReady(stream_id, push_front); +} + +bool QuicWriteBlockedList::IsStreamBlocked(QuicStreamId stream_id) const { + for (const auto& stream : static_stream_collection_) { + if (stream.id == stream_id) { + return stream.is_blocked; + } + } + + return priority_write_scheduler_->IsStreamReady(stream_id); +} + +bool QuicWriteBlockedList::PrecedenceMatchesSchedulerType( + const spdy::SpdyStreamPrecedence& precedence) { + switch (scheduler_type_) { + case spdy::WriteSchedulerType::LIFO: + break; + case spdy::WriteSchedulerType::SPDY: + return precedence.is_spdy3_priority(); + case spdy::WriteSchedulerType::HTTP2: + return !precedence.is_spdy3_priority(); + case spdy::WriteSchedulerType::FIFO: + break; + default: + DCHECK(false); + return false; + } + return true; +} + +void QuicWriteBlockedList::StaticStreamCollection::Register(QuicStreamId id) { + DCHECK(!IsRegistered(id)); + streams_.push_back({id, false}); +} + +bool QuicWriteBlockedList::StaticStreamCollection::IsRegistered( + QuicStreamId id) const { + for (const auto& stream : streams_) { + if (stream.id == id) { + return true; + } + } + return false; +} + +void QuicWriteBlockedList::StaticStreamCollection::Unregister(QuicStreamId id) { + for (auto it = streams_.begin(); it != streams_.end(); ++it) { + if (it->id == id) { + if (it->is_blocked) { + --num_blocked_; + } + streams_.erase(it); + return; + } + } + DCHECK(false) << "Erasing a non-exist stream with id " << id; +} + +bool QuicWriteBlockedList::StaticStreamCollection::SetBlocked(QuicStreamId id) { + for (auto& stream : streams_) { + if (stream.id == id) { + if (!stream.is_blocked) { + stream.is_blocked = true; + ++num_blocked_; + } + return true; + } + } + return false; +} + +bool QuicWriteBlockedList::StaticStreamCollection::UnblockFirstBlocked( + QuicStreamId* id) { + for (auto& stream : streams_) { + if (stream.is_blocked) { + --num_blocked_; + stream.is_blocked = false; + *id = stream.id; + return true; + } + } + return false; +} + } // namespace quic
diff --git a/quic/core/quic_write_blocked_list.h b/quic/core/quic_write_blocked_list.h index 4100df0..fd875bc 100644 --- a/quic/core/quic_write_blocked_list.h +++ b/quic/core/quic_write_blocked_list.h
@@ -51,20 +51,7 @@ priority_write_scheduler_->NumReadyStreams(); } - bool ShouldYield(QuicStreamId id) const { - for (const auto& stream : static_stream_collection_) { - if (stream.id == id) { - // Static streams should never yield to data streams, or to lower - // priority static stream. - return false; - } - if (stream.is_blocked) { - return true; // All data streams yield to static streams. - } - } - - return priority_write_scheduler_->ShouldYield(id); - } + bool ShouldYield(QuicStreamId id) const; spdy::SpdyPriority GetSpdyPriorityofStream(QuicStreamId id) const { return priority_write_scheduler_->GetStreamPrecedence(id).spdy3_priority(); @@ -73,168 +60,38 @@ // Switches write scheduler. This can only be called before any stream is // registered. bool SwitchWriteScheduler(spdy::WriteSchedulerType type, - QuicTransportVersion version) { - if (scheduler_type_ == type) { - return true; - } - if (priority_write_scheduler_->NumRegisteredStreams() != 0) { - QUIC_BUG << "Cannot switch scheduler with registered streams"; - return false; - } - QUIC_DVLOG(1) << "Switching to scheduler type: " - << spdy::WriteSchedulerTypeToString(type); - switch (type) { - case spdy::WriteSchedulerType::LIFO: - priority_write_scheduler_ = - std::make_unique<spdy::LifoWriteScheduler<QuicStreamId>>(); - break; - case spdy::WriteSchedulerType::SPDY: - priority_write_scheduler_ = - std::make_unique<spdy::PriorityWriteScheduler<QuicStreamId>>( - QuicVersionUsesCryptoFrames(version) - ? std::numeric_limits<QuicStreamId>::max() - : 0); - break; - case spdy::WriteSchedulerType::HTTP2: - priority_write_scheduler_ = - std::make_unique<spdy::Http2PriorityWriteScheduler<QuicStreamId>>(); - break; - case spdy::WriteSchedulerType::FIFO: - priority_write_scheduler_ = - std::make_unique<spdy::FifoWriteScheduler<QuicStreamId>>(); - break; - default: - QUIC_BUG << "Scheduler is not supported for type: " - << spdy::WriteSchedulerTypeToString(type); - return false; - } - scheduler_type_ = type; - return true; - } + QuicTransportVersion version); // Pops the highest priority stream, special casing crypto and headers // streams. Latches the most recently popped data stream for batch writing // purposes. - QuicStreamId PopFront() { - QuicStreamId static_stream_id; - if (static_stream_collection_.UnblockFirstBlocked(&static_stream_id)) { - return static_stream_id; - } - - const auto id_and_precedence = - priority_write_scheduler_->PopNextReadyStreamAndPrecedence(); - const QuicStreamId id = std::get<0>(id_and_precedence); - if (scheduler_type_ != spdy::WriteSchedulerType::SPDY) { - // No batch writing logic for non-SPDY priority write scheduler. - return id; - } - const spdy::SpdyPriority priority = - std::get<1>(id_and_precedence).spdy3_priority(); - - if (!priority_write_scheduler_->HasReadyStreams()) { - // If no streams are blocked, don't bother latching. This stream will be - // the first popped for its priority anyway. - batch_write_stream_id_[priority] = 0; - last_priority_popped_ = priority; - } else if (batch_write_stream_id_[priority] != id) { - // If newly latching this batch write stream, let it write 16k. - batch_write_stream_id_[priority] = id; - bytes_left_for_batch_write_[priority] = 16000; - last_priority_popped_ = priority; - } - - return id; - } + QuicStreamId PopFront(); void RegisterStream(QuicStreamId stream_id, bool is_static_stream, - const spdy::SpdyStreamPrecedence& precedence) { - DCHECK(!priority_write_scheduler_->StreamRegistered(stream_id)) - << "stream " << stream_id << " already registered"; - DCHECK(PrecedenceMatchesSchedulerType(precedence)); - if (is_static_stream) { - static_stream_collection_.Register(stream_id); - return; - } + const spdy::SpdyStreamPrecedence& precedence); - priority_write_scheduler_->RegisterStream(stream_id, precedence); - } - - void UnregisterStream(QuicStreamId stream_id, bool is_static) { - if (is_static) { - static_stream_collection_.Unregister(stream_id); - return; - } - priority_write_scheduler_->UnregisterStream(stream_id); - } + void UnregisterStream(QuicStreamId stream_id, bool is_static); void UpdateStreamPriority(QuicStreamId stream_id, - const spdy::SpdyStreamPrecedence& new_precedence) { - DCHECK(!static_stream_collection_.IsRegistered(stream_id)); - DCHECK(PrecedenceMatchesSchedulerType(new_precedence)); - priority_write_scheduler_->UpdateStreamPrecedence(stream_id, - new_precedence); - } + const spdy::SpdyStreamPrecedence& new_precedence); - void UpdateBytesForStream(QuicStreamId stream_id, size_t bytes) { - if (scheduler_type_ != spdy::WriteSchedulerType::SPDY) { - return; - } - if (batch_write_stream_id_[last_priority_popped_] == stream_id) { - // If this was the last data stream popped by PopFront, update the - // bytes remaining in its batch write. - bytes_left_for_batch_write_[last_priority_popped_] -= - static_cast<int32_t>(bytes); - } - } + void UpdateBytesForStream(QuicStreamId stream_id, size_t bytes); // Pushes a stream to the back of the list for its priority level *unless* it // is latched for doing batched writes in which case it goes to the front of // the list for its priority level. // Headers and crypto streams are special cased to always resume first. - void AddStream(QuicStreamId stream_id) { - if (static_stream_collection_.SetBlocked(stream_id)) { - return; - } - - bool push_front = - scheduler_type_ == spdy::WriteSchedulerType::SPDY && - stream_id == batch_write_stream_id_[last_priority_popped_] && - bytes_left_for_batch_write_[last_priority_popped_] > 0; - priority_write_scheduler_->MarkStreamReady(stream_id, push_front); - } + void AddStream(QuicStreamId stream_id); // Returns true if stream with |stream_id| is write blocked. - bool IsStreamBlocked(QuicStreamId stream_id) const { - for (const auto& stream : static_stream_collection_) { - if (stream.id == stream_id) { - return stream.is_blocked; - } - } - - return priority_write_scheduler_->IsStreamReady(stream_id); - } + bool IsStreamBlocked(QuicStreamId stream_id) const; spdy::WriteSchedulerType scheduler_type() const { return scheduler_type_; } private: bool PrecedenceMatchesSchedulerType( - const spdy::SpdyStreamPrecedence& precedence) { - switch (scheduler_type_) { - case spdy::WriteSchedulerType::LIFO: - break; - case spdy::WriteSchedulerType::SPDY: - return precedence.is_spdy3_priority(); - case spdy::WriteSchedulerType::HTTP2: - return !precedence.is_spdy3_priority(); - case spdy::WriteSchedulerType::FIFO: - break; - default: - DCHECK(false); - return false; - } - return true; - } + const spdy::SpdyStreamPrecedence& precedence); std::unique_ptr<QuicPriorityWriteScheduler> priority_write_scheduler_; @@ -269,66 +126,24 @@ size_t num_blocked() const { return num_blocked_; } // Add |id| to the collection in unblocked state. - void Register(QuicStreamId id) { - DCHECK(!IsRegistered(id)); - streams_.push_back({id, false}); - } + void Register(QuicStreamId id); // True if |id| is in the collection, regardless of its state. - bool IsRegistered(QuicStreamId id) const { - for (const auto& stream : streams_) { - if (stream.id == id) { - return true; - } - } - return false; - } + bool IsRegistered(QuicStreamId id) const; // Remove |id| from the collection, if it is in the blocked state, reduce // |num_blocked_| by 1. - void Unregister(QuicStreamId id) { - for (auto it = streams_.begin(); it != streams_.end(); ++it) { - if (it->id == id) { - if (it->is_blocked) { - --num_blocked_; - } - streams_.erase(it); - return; - } - } - DCHECK(false) << "Erasing a non-exist stream with id " << id; - } + void Unregister(QuicStreamId id); // Set |id| to be blocked. If |id| is not already blocked, increase // |num_blocked_| by 1. // Return true if |id| is in the collection. - bool SetBlocked(QuicStreamId id) { - for (auto& stream : streams_) { - if (stream.id == id) { - if (!stream.is_blocked) { - stream.is_blocked = true; - ++num_blocked_; - } - return true; - } - } - return false; - } + bool SetBlocked(QuicStreamId id); // Unblock the first blocked stream in the collection. // If no stream is blocked, return false. Otherwise return true, set *id to // the unblocked stream id and reduce |num_blocked_| by 1. - bool UnblockFirstBlocked(QuicStreamId* id) { - for (auto& stream : streams_) { - if (stream.is_blocked) { - --num_blocked_; - stream.is_blocked = false; - *id = stream.id; - return true; - } - } - return false; - } + bool UnblockFirstBlocked(QuicStreamId* id); private: size_t num_blocked_ = 0;