blob: 3c38bd59f7e9e2cb9b7c8f0be97a5a16fe64cf36 [file] [log] [blame]
fayang94113fe2019-07-31 07:32:14 -07001// Copyright (c) 2019 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_SPDY_CORE_FIFO_WRITE_SCHEDULER_H_
6#define QUICHE_SPDY_CORE_FIFO_WRITE_SCHEDULER_H_
7
8#include <map>
9#include <set>
10
11#include "net/third_party/quiche/src/spdy/core/write_scheduler.h"
12#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h"
13
14namespace spdy {
15
16// A write scheduler where the stream with the smallest stream ID will have the
17// highest priority.
18template <typename StreamIdType>
19class FifoWriteScheduler : public WriteScheduler<StreamIdType> {
20 public:
21 using typename WriteScheduler<StreamIdType>::StreamPrecedenceType;
22
23 FifoWriteScheduler() = default;
24
25 // WriteScheduler methods
26 void RegisterStream(StreamIdType stream_id,
27 const StreamPrecedenceType& precedence) override;
28 void UnregisterStream(StreamIdType stream_id) override;
29 bool StreamRegistered(StreamIdType stream_id) const override;
30 StreamPrecedenceType GetStreamPrecedence(
31 StreamIdType stream_id) const override;
32 void UpdateStreamPrecedence(StreamIdType stream_id,
33 const StreamPrecedenceType& precedence) override;
34 std::vector<StreamIdType> GetStreamChildren(
35 StreamIdType stream_id) const override;
36 void RecordStreamEventTime(StreamIdType stream_id,
37 int64_t now_in_usec) override;
38 int64_t GetLatestEventWithPrecedence(StreamIdType stream_id) const override;
39 bool ShouldYield(StreamIdType stream_id) const override;
40 void MarkStreamReady(StreamIdType stream_id, bool add_to_front) override;
41 void MarkStreamNotReady(StreamIdType stream_id) override;
42 bool HasReadyStreams() const override;
43 StreamIdType PopNextReadyStream() override;
44 std::tuple<StreamIdType, StreamPrecedenceType>
45 PopNextReadyStreamAndPrecedence() override;
46 size_t NumReadyStreams() const override;
47 bool IsStreamReady(StreamIdType stream_id) const override;
48 size_t NumRegisteredStreams() const override;
49 SpdyString DebugString() const override;
50
51 private:
52 std::set<StreamIdType> ready_streams_;
53 // This map maps stream ID to read/write event time (us since Unix epoch).
54 std::map<StreamIdType, int64_t> registered_streams_;
55};
56
57template <typename StreamIdType>
58void FifoWriteScheduler<StreamIdType>::RegisterStream(
59 StreamIdType stream_id,
60 const StreamPrecedenceType& /*precedence*/) {
61 if (StreamRegistered(stream_id)) {
62 SPDY_BUG << "Stream " << stream_id << " already registered";
63 return;
64 }
65 registered_streams_.emplace_hint(registered_streams_.end(), stream_id, 0);
66}
67
68template <typename StreamIdType>
69void FifoWriteScheduler<StreamIdType>::UnregisterStream(
70 StreamIdType stream_id) {
71 if (!StreamRegistered(stream_id)) {
72 SPDY_BUG << "Stream " << stream_id << " is not registered";
73 return;
74 }
75 registered_streams_.erase(stream_id);
76 ready_streams_.erase(stream_id);
77}
78
79template <typename StreamIdType>
80bool FifoWriteScheduler<StreamIdType>::StreamRegistered(
81 StreamIdType stream_id) const {
82 return registered_streams_.find(stream_id) != registered_streams_.end();
83}
84
85// Stream precedence is not supported by this scheduler.
86template <typename StreamIdType>
87typename FifoWriteScheduler<StreamIdType>::StreamPrecedenceType
88FifoWriteScheduler<StreamIdType>::GetStreamPrecedence(
89 StreamIdType /*stream_id*/) const {
90 return StreamPrecedenceType(kV3LowestPriority);
91}
92
93template <typename StreamIdType>
94void FifoWriteScheduler<StreamIdType>::UpdateStreamPrecedence(
95 StreamIdType /*stream_id*/,
96 const StreamPrecedenceType& /*precedence*/) {}
97
98template <typename StreamIdType>
99std::vector<StreamIdType> FifoWriteScheduler<StreamIdType>::GetStreamChildren(
100 StreamIdType /*stream_id*/) const {
101 return std::vector<StreamIdType>();
102}
103
104template <typename StreamIdType>
105void FifoWriteScheduler<StreamIdType>::RecordStreamEventTime(
106 StreamIdType stream_id,
107 int64_t now_in_usec) {
108 auto it = registered_streams_.find(stream_id);
109 if (it != registered_streams_.end()) {
110 it->second = now_in_usec;
111 } else {
112 SPDY_BUG << "Stream " << stream_id << " is not registered";
113 }
114}
115
116template <typename StreamIdType>
117int64_t FifoWriteScheduler<StreamIdType>::GetLatestEventWithPrecedence(
118 StreamIdType stream_id) const {
119 if (!StreamRegistered(stream_id)) {
120 SPDY_BUG << "Stream " << stream_id << " is not registered";
121 return 0;
122 }
123 int64_t latest_event_time_us = 0;
124 for (auto it = registered_streams_.begin(); it != registered_streams_.end();
125 ++it) {
126 if (stream_id <= it->first) {
127 break;
128 }
129 latest_event_time_us = std::max(latest_event_time_us, it->second);
130 }
131 return latest_event_time_us;
132}
133
134template <typename StreamIdType>
135bool FifoWriteScheduler<StreamIdType>::ShouldYield(
136 StreamIdType stream_id) const {
137 return !ready_streams_.empty() && stream_id > *ready_streams_.begin();
138}
139
140template <typename StreamIdType>
141void FifoWriteScheduler<StreamIdType>::MarkStreamReady(StreamIdType stream_id,
142 bool /*add_to_front*/) {
143 if (!StreamRegistered(stream_id)) {
144 SPDY_BUG << "Stream " << stream_id << " is not registered";
145 return;
146 }
147 if (ready_streams_.find(stream_id) != ready_streams_.end()) {
148 SPDY_DVLOG(1) << "Stream already exists in the list";
149 return;
150 }
151 ready_streams_.insert(stream_id);
152}
153
154template <typename StreamIdType>
155void FifoWriteScheduler<StreamIdType>::MarkStreamNotReady(
156 StreamIdType stream_id) {
157 auto it = ready_streams_.find(stream_id);
158 if (it == ready_streams_.end()) {
159 SPDY_DVLOG(1) << "Try to remove a stream that is not on list";
160 return;
161 }
162 ready_streams_.erase(it);
163}
164
165template <typename StreamIdType>
166bool FifoWriteScheduler<StreamIdType>::HasReadyStreams() const {
167 return !ready_streams_.empty();
168}
169
170template <typename StreamIdType>
171StreamIdType FifoWriteScheduler<StreamIdType>::PopNextReadyStream() {
172 if (ready_streams_.empty()) {
173 SPDY_BUG << "No ready streams available";
174 return 0;
175 }
176 auto it = ready_streams_.begin();
177 StreamIdType id = *it;
178 ready_streams_.erase(it);
179 return id;
180}
181
182template <typename StreamIdType>
183std::tuple<StreamIdType,
184 typename FifoWriteScheduler<StreamIdType>::StreamPrecedenceType>
185FifoWriteScheduler<StreamIdType>::PopNextReadyStreamAndPrecedence() {
186 return std::make_tuple(PopNextReadyStream(),
187 StreamPrecedenceType(kV3LowestPriority));
188}
189
190template <typename StreamIdType>
191size_t FifoWriteScheduler<StreamIdType>::NumReadyStreams() const {
192 return ready_streams_.size();
193}
194
195template <typename StreamIdType>
196bool FifoWriteScheduler<StreamIdType>::IsStreamReady(
197 StreamIdType stream_id) const {
198 if (!StreamRegistered(stream_id)) {
199 SPDY_BUG << "Stream " << stream_id << " is not registered";
200 return false;
201 }
202 return ready_streams_.find(stream_id) != ready_streams_.end();
203}
204
205template <typename StreamIdType>
206size_t FifoWriteScheduler<StreamIdType>::NumRegisteredStreams() const {
207 return registered_streams_.size();
208}
209
210template <typename StreamIdType>
fayang7e3c1a12019-08-02 08:07:13 -0700211SpdyString FifoWriteScheduler<StreamIdType>::DebugString() const {
fayang94113fe2019-07-31 07:32:14 -0700212 return SpdyStrCat(
213 "FifoWriteScheduler {num_streams=", registered_streams_.size(),
214 " num_ready_streams=", NumReadyStreams(), "}");
215}
216
217} // namespace spdy
218
219#endif // QUICHE_SPDY_CORE_FIFO_WRITE_SCHEDULER_H_