blob: 7bf8c4ed475dbe52eabf5a23ca6933585f0db6a8 [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>
bnc44712912019-08-15 18:58:14 -070010#include <string>
fayang94113fe2019-07-31 07:32:14 -070011
vasilvv1ea0b542020-12-03 15:21:00 -080012#include "absl/strings/str_cat.h"
QUICHE team5be974e2020-12-29 18:35:24 -050013#include "spdy/core/write_scheduler.h"
14#include "spdy/platform/api/spdy_string_utils.h"
fayang94113fe2019-07-31 07:32:14 -070015
16namespace spdy {
17
18// A write scheduler where the stream with the smallest stream ID will have the
19// highest priority.
20template <typename StreamIdType>
21class FifoWriteScheduler : public WriteScheduler<StreamIdType> {
22 public:
23 using typename WriteScheduler<StreamIdType>::StreamPrecedenceType;
24
25 FifoWriteScheduler() = default;
26
27 // WriteScheduler methods
28 void RegisterStream(StreamIdType stream_id,
29 const StreamPrecedenceType& precedence) override;
30 void UnregisterStream(StreamIdType stream_id) override;
31 bool StreamRegistered(StreamIdType stream_id) const override;
haoyuewang3889d1e2020-06-12 09:23:02 -070032 // Stream precedence is available but note that it is not used for scheduling
33 // in this scheduler.
fayang94113fe2019-07-31 07:32:14 -070034 StreamPrecedenceType GetStreamPrecedence(
35 StreamIdType stream_id) const override;
36 void UpdateStreamPrecedence(StreamIdType stream_id,
37 const StreamPrecedenceType& precedence) override;
38 std::vector<StreamIdType> GetStreamChildren(
39 StreamIdType stream_id) const override;
40 void RecordStreamEventTime(StreamIdType stream_id,
41 int64_t now_in_usec) override;
42 int64_t GetLatestEventWithPrecedence(StreamIdType stream_id) const override;
43 bool ShouldYield(StreamIdType stream_id) const override;
44 void MarkStreamReady(StreamIdType stream_id, bool add_to_front) override;
45 void MarkStreamNotReady(StreamIdType stream_id) override;
46 bool HasReadyStreams() const override;
47 StreamIdType PopNextReadyStream() override;
48 std::tuple<StreamIdType, StreamPrecedenceType>
49 PopNextReadyStreamAndPrecedence() override;
50 size_t NumReadyStreams() const override;
51 bool IsStreamReady(StreamIdType stream_id) const override;
52 size_t NumRegisteredStreams() const override;
bnc44712912019-08-15 18:58:14 -070053 std::string DebugString() const override;
fayang94113fe2019-07-31 07:32:14 -070054
55 private:
haoyuewang3889d1e2020-06-12 09:23:02 -070056 struct StreamInfo {
57 SpdyPriority priority;
58 int64_t event_time; // read/write event time (us since Unix epoch).
59 };
60
fayang94113fe2019-07-31 07:32:14 -070061 std::set<StreamIdType> ready_streams_;
haoyuewang3889d1e2020-06-12 09:23:02 -070062 std::map<StreamIdType, StreamInfo> registered_streams_;
fayang94113fe2019-07-31 07:32:14 -070063};
64
65template <typename StreamIdType>
66void FifoWriteScheduler<StreamIdType>::RegisterStream(
67 StreamIdType stream_id,
haoyuewang3889d1e2020-06-12 09:23:02 -070068 const StreamPrecedenceType& precedence) {
fayang94113fe2019-07-31 07:32:14 -070069 if (StreamRegistered(stream_id)) {
70 SPDY_BUG << "Stream " << stream_id << " already registered";
71 return;
72 }
haoyuewang3889d1e2020-06-12 09:23:02 -070073 registered_streams_.emplace_hint(
74 registered_streams_.end(), stream_id,
75 StreamInfo{/*priority=*/precedence.spdy3_priority(), /*event_time=*/0});
fayang94113fe2019-07-31 07:32:14 -070076}
77
78template <typename StreamIdType>
79void FifoWriteScheduler<StreamIdType>::UnregisterStream(
80 StreamIdType stream_id) {
81 if (!StreamRegistered(stream_id)) {
82 SPDY_BUG << "Stream " << stream_id << " is not registered";
83 return;
84 }
85 registered_streams_.erase(stream_id);
86 ready_streams_.erase(stream_id);
87}
88
89template <typename StreamIdType>
90bool FifoWriteScheduler<StreamIdType>::StreamRegistered(
91 StreamIdType stream_id) const {
92 return registered_streams_.find(stream_id) != registered_streams_.end();
93}
94
95// Stream precedence is not supported by this scheduler.
96template <typename StreamIdType>
97typename FifoWriteScheduler<StreamIdType>::StreamPrecedenceType
98FifoWriteScheduler<StreamIdType>::GetStreamPrecedence(
haoyuewang3889d1e2020-06-12 09:23:02 -070099 StreamIdType stream_id) const {
100 auto it = registered_streams_.find(stream_id);
101 if (it == registered_streams_.end()) {
102 SPDY_DVLOG(1) << "Stream " << stream_id << " not registered";
103 return StreamPrecedenceType(kV3LowestPriority);
104 }
105 return StreamPrecedenceType(it->second.priority);
fayang94113fe2019-07-31 07:32:14 -0700106}
107
108template <typename StreamIdType>
109void FifoWriteScheduler<StreamIdType>::UpdateStreamPrecedence(
haoyuewang3889d1e2020-06-12 09:23:02 -0700110 StreamIdType stream_id,
111 const StreamPrecedenceType& precedence) {
112 auto it = registered_streams_.find(stream_id);
113 if (it == registered_streams_.end()) {
114 SPDY_DVLOG(1) << "Stream " << stream_id << " not registered";
115 return;
116 }
117 it->second.priority = precedence.spdy3_priority();
118}
fayang94113fe2019-07-31 07:32:14 -0700119
120template <typename StreamIdType>
121std::vector<StreamIdType> FifoWriteScheduler<StreamIdType>::GetStreamChildren(
122 StreamIdType /*stream_id*/) const {
123 return std::vector<StreamIdType>();
124}
125
126template <typename StreamIdType>
127void FifoWriteScheduler<StreamIdType>::RecordStreamEventTime(
128 StreamIdType stream_id,
129 int64_t now_in_usec) {
130 auto it = registered_streams_.find(stream_id);
131 if (it != registered_streams_.end()) {
haoyuewang3889d1e2020-06-12 09:23:02 -0700132 it->second.event_time = now_in_usec;
fayang94113fe2019-07-31 07:32:14 -0700133 } else {
134 SPDY_BUG << "Stream " << stream_id << " is not registered";
135 }
136}
137
138template <typename StreamIdType>
139int64_t FifoWriteScheduler<StreamIdType>::GetLatestEventWithPrecedence(
140 StreamIdType stream_id) const {
141 if (!StreamRegistered(stream_id)) {
142 SPDY_BUG << "Stream " << stream_id << " is not registered";
143 return 0;
144 }
145 int64_t latest_event_time_us = 0;
146 for (auto it = registered_streams_.begin(); it != registered_streams_.end();
147 ++it) {
148 if (stream_id <= it->first) {
149 break;
150 }
haoyuewang3889d1e2020-06-12 09:23:02 -0700151 latest_event_time_us =
152 std::max(latest_event_time_us, it->second.event_time);
fayang94113fe2019-07-31 07:32:14 -0700153 }
154 return latest_event_time_us;
155}
156
157template <typename StreamIdType>
158bool FifoWriteScheduler<StreamIdType>::ShouldYield(
159 StreamIdType stream_id) const {
160 return !ready_streams_.empty() && stream_id > *ready_streams_.begin();
161}
162
163template <typename StreamIdType>
164void FifoWriteScheduler<StreamIdType>::MarkStreamReady(StreamIdType stream_id,
165 bool /*add_to_front*/) {
166 if (!StreamRegistered(stream_id)) {
167 SPDY_BUG << "Stream " << stream_id << " is not registered";
168 return;
169 }
170 if (ready_streams_.find(stream_id) != ready_streams_.end()) {
171 SPDY_DVLOG(1) << "Stream already exists in the list";
172 return;
173 }
174 ready_streams_.insert(stream_id);
175}
176
177template <typename StreamIdType>
178void FifoWriteScheduler<StreamIdType>::MarkStreamNotReady(
179 StreamIdType stream_id) {
180 auto it = ready_streams_.find(stream_id);
181 if (it == ready_streams_.end()) {
182 SPDY_DVLOG(1) << "Try to remove a stream that is not on list";
183 return;
184 }
185 ready_streams_.erase(it);
186}
187
188template <typename StreamIdType>
189bool FifoWriteScheduler<StreamIdType>::HasReadyStreams() const {
190 return !ready_streams_.empty();
191}
192
193template <typename StreamIdType>
194StreamIdType FifoWriteScheduler<StreamIdType>::PopNextReadyStream() {
195 if (ready_streams_.empty()) {
196 SPDY_BUG << "No ready streams available";
197 return 0;
198 }
199 auto it = ready_streams_.begin();
200 StreamIdType id = *it;
201 ready_streams_.erase(it);
202 return id;
203}
204
205template <typename StreamIdType>
206std::tuple<StreamIdType,
207 typename FifoWriteScheduler<StreamIdType>::StreamPrecedenceType>
208FifoWriteScheduler<StreamIdType>::PopNextReadyStreamAndPrecedence() {
209 return std::make_tuple(PopNextReadyStream(),
210 StreamPrecedenceType(kV3LowestPriority));
211}
212
213template <typename StreamIdType>
214size_t FifoWriteScheduler<StreamIdType>::NumReadyStreams() const {
215 return ready_streams_.size();
216}
217
218template <typename StreamIdType>
219bool FifoWriteScheduler<StreamIdType>::IsStreamReady(
220 StreamIdType stream_id) const {
221 if (!StreamRegistered(stream_id)) {
222 SPDY_BUG << "Stream " << stream_id << " is not registered";
223 return false;
224 }
225 return ready_streams_.find(stream_id) != ready_streams_.end();
226}
227
228template <typename StreamIdType>
229size_t FifoWriteScheduler<StreamIdType>::NumRegisteredStreams() const {
230 return registered_streams_.size();
231}
232
233template <typename StreamIdType>
bnc44712912019-08-15 18:58:14 -0700234std::string FifoWriteScheduler<StreamIdType>::DebugString() const {
vasilvv1ea0b542020-12-03 15:21:00 -0800235 return absl::StrCat(
fayang94113fe2019-07-31 07:32:14 -0700236 "FifoWriteScheduler {num_streams=", registered_streams_.size(),
237 " num_ready_streams=", NumReadyStreams(), "}");
238}
239
240} // namespace spdy
241
242#endif // QUICHE_SPDY_CORE_FIFO_WRITE_SCHEDULER_H_