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