blob: 1a72c82c4309d6f11804b5094682295b19d14ed0 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef QUICHE_QUIC_CORE_QUIC_WRITE_BLOCKED_LIST_H_
#define QUICHE_QUIC_CORE_QUIC_WRITE_BLOCKED_LIST_H_
#include <cstddef>
#include <cstdint>
#include <utility>
#include "absl/container/inlined_vector.h"
#include "quiche/http2/core/priority_write_scheduler.h"
#include "quiche/quic/core/quic_packets.h"
#include "quiche/quic/core/quic_stream_priority.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/platform/api/quic_bug_tracker.h"
#include "quiche/quic/platform/api/quic_export.h"
#include "quiche/quic/platform/api/quic_flags.h"
#include "quiche/spdy/core/spdy_protocol.h"
namespace quic {
// Keeps tracks of the order of QUIC streams that have data to write.
// Static streams come first, in the order they were registered with
// QuicWriteBlockedList. They are followed by non-static streams, ordered by
// priority.
class QUICHE_EXPORT QuicWriteBlockedListInterface {
public:
virtual ~QuicWriteBlockedListInterface() = default;
virtual bool HasWriteBlockedDataStreams() const = 0;
virtual size_t NumBlockedSpecialStreams() const = 0;
virtual size_t NumBlockedStreams() const = 0;
bool HasWriteBlockedSpecialStream() const {
return NumBlockedSpecialStreams() > 0;
}
// Returns true if there is another stream with higher priority in the queue.
virtual bool ShouldYield(QuicStreamId id) const = 0;
// Returns the priority of the specified stream.
virtual QuicStreamPriority GetPriorityOfStream(QuicStreamId id) const = 0;
// Pops the highest priority stream, special casing static streams. Latches
// the most recently popped data stream for batch writing purposes.
virtual QuicStreamId PopFront() = 0;
// Register a stream with given priority.
// `priority` is ignored for static streams.
virtual void RegisterStream(QuicStreamId stream_id, bool is_static_stream,
const QuicStreamPriority& priority) = 0;
// Unregister a stream. `stream_id` must be registered, either as a static
// stream or as a non-static stream.
virtual void UnregisterStream(QuicStreamId stream_id) = 0;
// Updates the stored priority of a stream. Must not be called for static
// streams.
virtual void UpdateStreamPriority(QuicStreamId stream_id,
const QuicStreamPriority& new_priority) = 0;
// TODO(b/147306124): Remove when deprecating
// reloadable_flag_quic_disable_batch_write.
virtual void UpdateBytesForStream(QuicStreamId stream_id, size_t bytes) = 0;
// 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.
// Static streams are special cased to always resume first.
// Stream must already be registered.
virtual void AddStream(QuicStreamId stream_id) = 0;
// Returns true if stream with |stream_id| is write blocked.
virtual bool IsStreamBlocked(QuicStreamId stream_id) const = 0;
};
// Default implementation of QuicWriteBlockedListInterface.
class QUICHE_EXPORT QuicWriteBlockedList
: public QuicWriteBlockedListInterface {
public:
explicit QuicWriteBlockedList();
QuicWriteBlockedList(const QuicWriteBlockedList&) = delete;
QuicWriteBlockedList& operator=(const QuicWriteBlockedList&) = delete;
bool HasWriteBlockedDataStreams() const override {
return priority_write_scheduler_.HasReadyStreams();
}
size_t NumBlockedSpecialStreams() const override {
return static_stream_collection_.num_blocked();
}
size_t NumBlockedStreams() const override {
return NumBlockedSpecialStreams() +
priority_write_scheduler_.NumReadyStreams();
}
bool ShouldYield(QuicStreamId id) const override;
QuicStreamPriority GetPriorityOfStream(QuicStreamId id) const override {
return QuicStreamPriority(priority_write_scheduler_.GetStreamPriority(id));
}
// Pops the highest priority stream, special casing static streams. Latches
// the most recently popped data stream for batch writing purposes.
QuicStreamId PopFront() override;
// Register a stream with given priority.
// `priority` is ignored for static streams.
void RegisterStream(QuicStreamId stream_id, bool is_static_stream,
const QuicStreamPriority& priority) override;
// Unregister a stream. `stream_id` must be registered, either as a static
// stream or as a non-static stream.
void UnregisterStream(QuicStreamId stream_id) override;
// Updates the stored priority of a stream. Must not be called for static
// streams.
void UpdateStreamPriority(QuicStreamId stream_id,
const QuicStreamPriority& new_priority) override;
// TODO(b/147306124): Remove when deprecating
// reloadable_flag_quic_disable_batch_write.
void UpdateBytesForStream(QuicStreamId stream_id, size_t bytes) override;
// 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.
// Static streams are special cased to always resume first.
// Stream must already be registered.
void AddStream(QuicStreamId stream_id) override;
// Returns true if stream with |stream_id| is write blocked.
bool IsStreamBlocked(QuicStreamId stream_id) const override;
private:
struct QUICHE_EXPORT HttpStreamPriorityToInt {
int operator()(const HttpStreamPriority& priority) {
return priority.urgency;
}
};
struct QUICHE_EXPORT IntToHttpStreamPriority {
HttpStreamPriority operator()(int urgency) {
return HttpStreamPriority{urgency};
}
};
http2::PriorityWriteScheduler<QuicStreamId, HttpStreamPriority,
HttpStreamPriorityToInt,
IntToHttpStreamPriority>
priority_write_scheduler_;
// If performing batch writes, this will be the stream ID of the stream doing
// batch writes for this priority level. We will allow this stream to write
// until it has written kBatchWriteSize bytes, it has no more data to write,
// or a higher priority stream preempts.
QuicStreamId batch_write_stream_id_[spdy::kV3LowestPriority + 1];
// Set to kBatchWriteSize when we set a new batch_write_stream_id_ for a given
// priority. This is decremented with each write the stream does until it is
// done with its batch write.
// TODO(b/147306124): Remove when deprecating
// reloadable_flag_quic_disable_batch_write.
size_t bytes_left_for_batch_write_[spdy::kV3LowestPriority + 1];
// Tracks the last priority popped for UpdateBytesForStream() and AddStream().
spdy::SpdyPriority last_priority_popped_;
// A StaticStreamCollection is a vector of <QuicStreamId, bool> pairs plus a
// eagerly-computed number of blocked static streams.
class QUICHE_EXPORT StaticStreamCollection {
public:
struct QUICHE_EXPORT StreamIdBlockedPair {
QuicStreamId id;
bool is_blocked;
};
// Optimized for the typical case of 2 static streams per session.
using StreamsVector = absl::InlinedVector<StreamIdBlockedPair, 2>;
StreamsVector::const_iterator begin() const { return streams_.cbegin(); }
StreamsVector::const_iterator end() const { return streams_.cend(); }
size_t num_blocked() const { return num_blocked_; }
// Add |id| to the collection in unblocked state.
void Register(QuicStreamId id);
// True if |id| is in the collection, regardless of its state.
bool IsRegistered(QuicStreamId id) const;
// Remove |id| from the collection. If it is in the blocked state, reduce
// |num_blocked_| by 1. Returns true if |id| was in the collection.
bool 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);
// 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);
private:
size_t num_blocked_ = 0;
StreamsVector streams_;
};
StaticStreamCollection static_stream_collection_;
// Latched value of reloadable_flag_quic_priority_respect_incremental.
const bool respect_incremental_;
// Latched value of reloadable_flag_quic_disable_batch_write.
const bool disable_batch_write_;
};
} // namespace quic
#endif // QUICHE_QUIC_CORE_QUIC_WRITE_BLOCKED_LIST_H_