/src/h2/src/proto/streams/counts.rs
Line | Count | Source |
1 | | use super::*; |
2 | | |
3 | | #[derive(Debug)] |
4 | | struct Budget { |
5 | | available: usize, |
6 | | max: usize, |
7 | | } |
8 | | |
9 | | #[derive(Debug)] |
10 | | pub(super) struct BudgetExhausted; |
11 | | |
12 | | impl Budget { |
13 | 12.7k | fn new(max: usize) -> Self { |
14 | 12.7k | Budget { |
15 | 12.7k | available: max, |
16 | 12.7k | max, |
17 | 12.7k | } |
18 | 12.7k | } |
19 | | |
20 | 696 | fn consume(&mut self, amount: usize) -> Result<(), BudgetExhausted> { |
21 | 696 | self.available = self.available.checked_sub(amount).ok_or(BudgetExhausted)?; |
22 | 696 | Ok(()) |
23 | 696 | } |
24 | | |
25 | 456 | fn replenish(&mut self, amount: usize) { |
26 | 456 | self.available = self.available.saturating_add(amount).min(self.max); |
27 | 456 | } |
28 | | } |
29 | | |
30 | | #[derive(Debug)] |
31 | | pub(super) struct Counts { |
32 | | /// Acting as a client or server. This allows us to track which values to |
33 | | /// inc / dec. |
34 | | peer: peer::Dyn, |
35 | | |
36 | | /// Maximum number of locally initiated streams |
37 | | max_send_streams: usize, |
38 | | |
39 | | /// Current number of remote initiated streams |
40 | | num_send_streams: usize, |
41 | | |
42 | | /// Maximum number of remote initiated streams |
43 | | max_recv_streams: usize, |
44 | | |
45 | | /// Current number of locally initiated streams |
46 | | num_recv_streams: usize, |
47 | | |
48 | | /// Maximum number of pending locally reset streams |
49 | | max_local_reset_streams: usize, |
50 | | |
51 | | /// Current number of pending locally reset streams |
52 | | num_local_reset_streams: usize, |
53 | | |
54 | | /// Max number of "pending accept" streams that were remotely reset |
55 | | max_remote_reset_streams: usize, |
56 | | |
57 | | /// Current number of "pending accept" streams that were remotely reset |
58 | | num_remote_reset_streams: usize, |
59 | | |
60 | | /// Maximum number of locally reset streams due to protocol error across |
61 | | /// the lifetime of the connection. |
62 | | /// |
63 | | /// When this gets exceeded, we issue GOAWAYs. |
64 | | max_local_error_reset_streams: Option<usize>, |
65 | | |
66 | | /// Total number of locally reset streams due to protocol error across the |
67 | | /// lifetime of the connection. |
68 | | num_local_error_reset_streams: usize, |
69 | | |
70 | | /// connection-level budget for DATA framing overhead. |
71 | | data_frame_budget: Budget, |
72 | | |
73 | | /// Number of empty, non-final DATA frames received over the lifetime of |
74 | | /// the connection. |
75 | | num_recv_empty_data_frames: usize, |
76 | | } |
77 | | |
78 | | impl Counts { |
79 | | /// Create a new `Counts` using the provided configuration values. |
80 | 12.7k | pub fn new(peer: peer::Dyn, config: &Config) -> Self { |
81 | 12.7k | Counts { |
82 | 12.7k | peer, |
83 | 12.7k | max_send_streams: config.initial_max_send_streams, |
84 | 12.7k | num_send_streams: 0, |
85 | 12.7k | max_recv_streams: config.remote_max_initiated.unwrap_or(usize::MAX), |
86 | 12.7k | num_recv_streams: 0, |
87 | 12.7k | max_local_reset_streams: config.local_reset_max, |
88 | 12.7k | num_local_reset_streams: 0, |
89 | 12.7k | max_remote_reset_streams: config.remote_reset_max, |
90 | 12.7k | num_remote_reset_streams: 0, |
91 | 12.7k | max_local_error_reset_streams: config.local_max_error_reset_streams, |
92 | 12.7k | num_local_error_reset_streams: 0, |
93 | 12.7k | data_frame_budget: Budget::new(config.data_frame_budget), |
94 | 12.7k | num_recv_empty_data_frames: 0, |
95 | 12.7k | } |
96 | 12.7k | } |
97 | | |
98 | | /// Records the framing overhead of a DATA frame. |
99 | 1.65k | pub fn record_data_frame(&mut self, payload_len: usize) -> Result<(), BudgetExhausted> { |
100 | 1.65k | if payload_len == 0 { |
101 | 935 | self.num_recv_empty_data_frames = self |
102 | 935 | .num_recv_empty_data_frames |
103 | 935 | .checked_add(1) |
104 | 935 | .ok_or(BudgetExhausted)?; |
105 | 935 | if self.num_recv_empty_data_frames > MAX_RECV_EMPTY_DATA_FRAMES { |
106 | 2 | return Err(BudgetExhausted); |
107 | 933 | } |
108 | 933 | Ok(()) |
109 | 719 | } else if payload_len < DEFAULT_DATA_FRAME_OVERHEAD_THRESHOLD { |
110 | 696 | self.data_frame_budget |
111 | 696 | .consume(DEFAULT_DATA_FRAME_OVERHEAD_THRESHOLD - payload_len) |
112 | | } else { |
113 | 23 | self.data_frame_budget |
114 | 23 | .replenish(payload_len - DEFAULT_DATA_FRAME_OVERHEAD_THRESHOLD); |
115 | 23 | Ok(()) |
116 | | } |
117 | 1.65k | } |
118 | | |
119 | | /// Releases the framing overhead of a DATA frame that is no longer |
120 | | /// buffered internally. |
121 | 439 | pub fn release_data_frame(&mut self, payload_len: usize) { |
122 | 439 | if payload_len != 0 && payload_len < DEFAULT_DATA_FRAME_OVERHEAD_THRESHOLD { |
123 | 433 | self.data_frame_budget |
124 | 433 | .replenish(DEFAULT_DATA_FRAME_OVERHEAD_THRESHOLD - payload_len); |
125 | 433 | } |
126 | 439 | } |
127 | | |
128 | | /// Returns true when the next opened stream will reach capacity of outbound streams |
129 | | /// |
130 | | /// The number of client send streams is incremented in prioritize; send_request has to guess if |
131 | | /// it should wait before allowing another request to be sent. |
132 | 406k | pub fn next_send_stream_will_reach_capacity(&self) -> bool { |
133 | 406k | self.max_send_streams <= (self.num_send_streams + 1) |
134 | 406k | } |
135 | | |
136 | | /// Returns the current peer |
137 | 904k | pub fn peer(&self) -> peer::Dyn { |
138 | 904k | self.peer |
139 | 904k | } |
140 | | |
141 | 3.59M | pub fn has_streams(&self) -> bool { |
142 | 3.59M | self.num_send_streams != 0 || self.num_recv_streams != 0 |
143 | 3.59M | } |
144 | | |
145 | | /// Returns true if we can issue another local reset due to protocol error. |
146 | 67.3k | pub fn can_inc_num_local_error_resets(&self) -> bool { |
147 | 67.3k | if let Some(max) = self.max_local_error_reset_streams { |
148 | 67.3k | max > self.num_local_error_reset_streams |
149 | | } else { |
150 | 0 | true |
151 | | } |
152 | 67.3k | } |
153 | | |
154 | 33.6k | pub fn inc_num_local_error_resets(&mut self) { |
155 | 33.6k | assert!(self.can_inc_num_local_error_resets()); |
156 | | |
157 | | // Increment the number of remote initiated streams |
158 | 33.6k | self.num_local_error_reset_streams += 1; |
159 | 33.6k | } |
160 | | |
161 | 0 | pub(crate) fn max_local_error_resets(&self) -> Option<usize> { |
162 | 0 | self.max_local_error_reset_streams |
163 | 0 | } |
164 | | |
165 | | /// Returns true if the receive stream concurrency can be incremented |
166 | 914 | pub fn can_inc_num_recv_streams(&self) -> bool { |
167 | 914 | self.max_recv_streams > self.num_recv_streams |
168 | 914 | } |
169 | | |
170 | | /// Increments the number of concurrent receive streams. |
171 | | /// |
172 | | /// # Panics |
173 | | /// |
174 | | /// Panics on failure as this should have been validated before hand. |
175 | 3 | pub fn inc_num_recv_streams(&mut self, stream: &mut store::Ptr) { |
176 | 3 | assert!(self.can_inc_num_recv_streams()); |
177 | 3 | assert!(!stream.is_counted); |
178 | | |
179 | | // Increment the number of remote initiated streams |
180 | 3 | self.num_recv_streams += 1; |
181 | 3 | stream.is_counted = true; |
182 | 3 | } |
183 | | |
184 | | /// Returns true if the send stream concurrency can be incremented |
185 | 874k | pub fn can_inc_num_send_streams(&self) -> bool { |
186 | 874k | self.max_send_streams > self.num_send_streams |
187 | 874k | } |
188 | | |
189 | | /// Increments the number of concurrent send streams. |
190 | | /// |
191 | | /// # Panics |
192 | | /// |
193 | | /// Panics on failure as this should have been validated before hand. |
194 | 201k | pub fn inc_num_send_streams(&mut self, stream: &mut store::Ptr) { |
195 | 201k | assert!(self.can_inc_num_send_streams()); |
196 | 201k | assert!(!stream.is_counted); |
197 | | |
198 | | // Increment the number of remote initiated streams |
199 | 201k | self.num_send_streams += 1; |
200 | 201k | stream.is_counted = true; |
201 | 201k | } |
202 | | |
203 | | /// Returns true if the number of pending reset streams can be incremented. |
204 | 129k | pub fn can_inc_num_reset_streams(&self) -> bool { |
205 | 129k | self.max_local_reset_streams > self.num_local_reset_streams |
206 | 129k | } |
207 | | |
208 | | /// Increments the number of pending reset streams. |
209 | | /// |
210 | | /// # Panics |
211 | | /// |
212 | | /// Panics on failure as this should have been validated before hand. |
213 | 43.0k | pub fn inc_num_reset_streams(&mut self) { |
214 | 43.0k | assert!(self.can_inc_num_reset_streams()); |
215 | | |
216 | 43.0k | self.num_local_reset_streams += 1; |
217 | 43.0k | } |
218 | | |
219 | 0 | pub(crate) fn max_remote_reset_streams(&self) -> usize { |
220 | 0 | self.max_remote_reset_streams |
221 | 0 | } |
222 | | |
223 | | /// Returns true if the number of pending REMOTE reset streams can be |
224 | | /// incremented. |
225 | 0 | pub(crate) fn can_inc_num_remote_reset_streams(&self) -> bool { |
226 | 0 | self.max_remote_reset_streams > self.num_remote_reset_streams |
227 | 0 | } |
228 | | |
229 | | /// Increments the number of pending REMOTE reset streams. |
230 | | /// |
231 | | /// # Panics |
232 | | /// |
233 | | /// Panics on failure as this should have been validated before hand. |
234 | 0 | pub(crate) fn inc_num_remote_reset_streams(&mut self) { |
235 | 0 | assert!(self.can_inc_num_remote_reset_streams()); |
236 | | |
237 | 0 | self.num_remote_reset_streams += 1; |
238 | 0 | } |
239 | | |
240 | 0 | pub(crate) fn dec_num_remote_reset_streams(&mut self) { |
241 | 0 | assert!(self.num_remote_reset_streams > 0); |
242 | | |
243 | 0 | self.num_remote_reset_streams -= 1; |
244 | 0 | } |
245 | | |
246 | 5.30k | pub fn apply_remote_settings(&mut self, settings: &frame::Settings, is_initial: bool) { |
247 | 5.30k | match settings.max_concurrent_streams() { |
248 | 542 | Some(val) => self.max_send_streams = val as usize, |
249 | 662 | None if is_initial => self.max_send_streams = usize::MAX, |
250 | 4.10k | None => {} |
251 | | } |
252 | 5.30k | } |
253 | | |
254 | | /// Run a block of code that could potentially transition a stream's state. |
255 | | /// |
256 | | /// If the stream state transitions to closed, this function will perform |
257 | | /// all necessary cleanup. |
258 | | /// |
259 | | /// TODO: Is this function still needed? |
260 | 1.77M | pub fn transition<F, U>(&mut self, mut stream: store::Ptr, f: F) -> U |
261 | 1.77M | where |
262 | 1.77M | F: FnOnce(&mut Self, &mut store::Ptr) -> U, |
263 | | { |
264 | | // TODO: Does this need to be computed before performing the action? |
265 | 1.77M | let is_pending_reset = stream.is_pending_reset_expiration(); |
266 | | |
267 | | // Run the action |
268 | 1.77M | let ret = f(self, &mut stream); |
269 | | |
270 | 1.77M | self.transition_after(stream, is_pending_reset); |
271 | | |
272 | 1.77M | ret |
273 | 1.77M | } <h2::proto::streams::counts::Counts>::transition::<<h2::proto::streams::prioritize::Prioritize>::assign_connection_capacity<h2::proto::streams::store::Ptr>::{closure#0}, ()>Line | Count | Source | 260 | 25.2k | pub fn transition<F, U>(&mut self, mut stream: store::Ptr, f: F) -> U | 261 | 25.2k | where | 262 | 25.2k | F: FnOnce(&mut Self, &mut store::Ptr) -> U, | 263 | | { | 264 | | // TODO: Does this need to be computed before performing the action? | 265 | 25.2k | let is_pending_reset = stream.is_pending_reset_expiration(); | 266 | | | 267 | | // Run the action | 268 | 25.2k | let ret = f(self, &mut stream); | 269 | | | 270 | 25.2k | self.transition_after(stream, is_pending_reset); | 271 | | | 272 | 25.2k | ret | 273 | 25.2k | } |
<h2::proto::streams::counts::Counts>::transition::<<h2::proto::streams::prioritize::Prioritize>::assign_connection_capacity<h2::proto::streams::store::Store>::{closure#0}, ()>Line | Count | Source | 260 | 42.1k | pub fn transition<F, U>(&mut self, mut stream: store::Ptr, f: F) -> U | 261 | 42.1k | where | 262 | 42.1k | F: FnOnce(&mut Self, &mut store::Ptr) -> U, | 263 | | { | 264 | | // TODO: Does this need to be computed before performing the action? | 265 | 42.1k | let is_pending_reset = stream.is_pending_reset_expiration(); | 266 | | | 267 | | // Run the action | 268 | 42.1k | let ret = f(self, &mut stream); | 269 | | | 270 | 42.1k | self.transition_after(stream, is_pending_reset); | 271 | | | 272 | 42.1k | ret | 273 | 42.1k | } |
<h2::proto::streams::counts::Counts>::transition::<h2::proto::streams::streams::drop_stream_ref::{closure#0}::{closure#0}, ()>Line | Count | Source | 260 | 169 | pub fn transition<F, U>(&mut self, mut stream: store::Ptr, f: F) -> U | 261 | 169 | where | 262 | 169 | F: FnOnce(&mut Self, &mut store::Ptr) -> U, | 263 | | { | 264 | | // TODO: Does this need to be computed before performing the action? | 265 | 169 | let is_pending_reset = stream.is_pending_reset_expiration(); | 266 | | | 267 | | // Run the action | 268 | 169 | let ret = f(self, &mut stream); | 269 | | | 270 | 169 | self.transition_after(stream, is_pending_reset); | 271 | | | 272 | 169 | ret | 273 | 169 | } |
<h2::proto::streams::counts::Counts>::transition::<<h2::proto::streams::prioritize::Prioritize>::clear_pending_capacity::{closure#0}, ()>Line | Count | Source | 260 | 12.9k | pub fn transition<F, U>(&mut self, mut stream: store::Ptr, f: F) -> U | 261 | 12.9k | where | 262 | 12.9k | F: FnOnce(&mut Self, &mut store::Ptr) -> U, | 263 | | { | 264 | | // TODO: Does this need to be computed before performing the action? | 265 | 12.9k | let is_pending_reset = stream.is_pending_reset_expiration(); | 266 | | | 267 | | // Run the action | 268 | 12.9k | let ret = f(self, &mut stream); | 269 | | | 270 | 12.9k | self.transition_after(stream, is_pending_reset); | 271 | | | 272 | 12.9k | ret | 273 | 12.9k | } |
Unexecuted instantiation: <h2::proto::streams::counts::Counts>::transition::<<h2::proto::streams::recv::Recv>::clear_stream_window_update_queue::{closure#0}, ()><h2::proto::streams::counts::Counts>::transition::<h2::proto::streams::streams::drop_stream_ref::{closure#0}, ()>Line | Count | Source | 260 | 814k | pub fn transition<F, U>(&mut self, mut stream: store::Ptr, f: F) -> U | 261 | 814k | where | 262 | 814k | F: FnOnce(&mut Self, &mut store::Ptr) -> U, | 263 | | { | 264 | | // TODO: Does this need to be computed before performing the action? | 265 | 814k | let is_pending_reset = stream.is_pending_reset_expiration(); | 266 | | | 267 | | // Run the action | 268 | 814k | let ret = f(self, &mut stream); | 269 | | | 270 | 814k | self.transition_after(stream, is_pending_reset); | 271 | | | 272 | 814k | ret | 273 | 814k | } |
<h2::proto::streams::counts::Counts>::transition::<<h2::proto::streams::streams::Inner>::recv_eof<bytes::bytes::Bytes>::{closure#0}::{closure#0}, ()>Line | Count | Source | 260 | 713 | pub fn transition<F, U>(&mut self, mut stream: store::Ptr, f: F) -> U | 261 | 713 | where | 262 | 713 | F: FnOnce(&mut Self, &mut store::Ptr) -> U, | 263 | | { | 264 | | // TODO: Does this need to be computed before performing the action? | 265 | 713 | let is_pending_reset = stream.is_pending_reset_expiration(); | 266 | | | 267 | | // Run the action | 268 | 713 | let ret = f(self, &mut stream); | 269 | | | 270 | 713 | self.transition_after(stream, is_pending_reset); | 271 | | | 272 | 713 | ret | 273 | 713 | } |
Unexecuted instantiation: <h2::proto::streams::counts::Counts>::transition::<<h2::proto::streams::recv::Recv>::send_stream_window_updates<fuzz_e2e::MockIo, bytes::bytes::Bytes>::{closure#0}, ()><h2::proto::streams::counts::Counts>::transition::<<h2::proto::streams::streams::Inner>::recv_reset<bytes::bytes::Bytes>::{closure#0}, core::result::Result<(), h2::proto::error::Error>>Line | Count | Source | 260 | 321 | pub fn transition<F, U>(&mut self, mut stream: store::Ptr, f: F) -> U | 261 | 321 | where | 262 | 321 | F: FnOnce(&mut Self, &mut store::Ptr) -> U, | 263 | | { | 264 | | // TODO: Does this need to be computed before performing the action? | 265 | 321 | let is_pending_reset = stream.is_pending_reset_expiration(); | 266 | | | 267 | | // Run the action | 268 | 321 | let ret = f(self, &mut stream); | 269 | | | 270 | 321 | self.transition_after(stream, is_pending_reset); | 271 | | | 272 | 321 | ret | 273 | 321 | } |
<h2::proto::streams::counts::Counts>::transition::<<h2::proto::streams::streams::Inner>::recv_headers<bytes::bytes::Bytes>::{closure#0}, core::result::Result<(), h2::proto::error::Error>>Line | Count | Source | 260 | 2.00k | pub fn transition<F, U>(&mut self, mut stream: store::Ptr, f: F) -> U | 261 | 2.00k | where | 262 | 2.00k | F: FnOnce(&mut Self, &mut store::Ptr) -> U, | 263 | | { | 264 | | // TODO: Does this need to be computed before performing the action? | 265 | 2.00k | let is_pending_reset = stream.is_pending_reset_expiration(); | 266 | | | 267 | | // Run the action | 268 | 2.00k | let ret = f(self, &mut stream); | 269 | | | 270 | 2.00k | self.transition_after(stream, is_pending_reset); | 271 | | | 272 | 2.00k | ret | 273 | 2.00k | } |
<h2::proto::streams::counts::Counts>::transition::<<h2::proto::streams::streams::Inner>::recv_push_promise<bytes::bytes::Bytes>::{closure#0}, core::result::Result<core::option::Option<h2::proto::streams::store::Key>, h2::proto::error::Error>>Line | Count | Source | 260 | 911 | pub fn transition<F, U>(&mut self, mut stream: store::Ptr, f: F) -> U | 261 | 911 | where | 262 | 911 | F: FnOnce(&mut Self, &mut store::Ptr) -> U, | 263 | | { | 264 | | // TODO: Does this need to be computed before performing the action? | 265 | 911 | let is_pending_reset = stream.is_pending_reset_expiration(); | 266 | | | 267 | | // Run the action | 268 | 911 | let ret = f(self, &mut stream); | 269 | | | 270 | 911 | self.transition_after(stream, is_pending_reset); | 271 | | | 272 | 911 | ret | 273 | 911 | } |
<h2::proto::streams::counts::Counts>::transition::<<h2::proto::streams::streams::Inner>::recv_data<bytes::bytes::Bytes>::{closure#0}, core::result::Result<(), h2::proto::error::Error>>Line | Count | Source | 260 | 1.91k | pub fn transition<F, U>(&mut self, mut stream: store::Ptr, f: F) -> U | 261 | 1.91k | where | 262 | 1.91k | F: FnOnce(&mut Self, &mut store::Ptr) -> U, | 263 | | { | 264 | | // TODO: Does this need to be computed before performing the action? | 265 | 1.91k | let is_pending_reset = stream.is_pending_reset_expiration(); | 266 | | | 267 | | // Run the action | 268 | 1.91k | let ret = f(self, &mut stream); | 269 | | | 270 | 1.91k | self.transition_after(stream, is_pending_reset); | 271 | | | 272 | 1.91k | ret | 273 | 1.91k | } |
<h2::proto::streams::counts::Counts>::transition::<<h2::proto::streams::streams::Actions>::send_reset<bytes::bytes::Bytes>::{closure#0}, core::result::Result<(), h2::proto::error::GoAway>>Line | Count | Source | 260 | 32.8k | pub fn transition<F, U>(&mut self, mut stream: store::Ptr, f: F) -> U | 261 | 32.8k | where | 262 | 32.8k | F: FnOnce(&mut Self, &mut store::Ptr) -> U, | 263 | | { | 264 | | // TODO: Does this need to be computed before performing the action? | 265 | 32.8k | let is_pending_reset = stream.is_pending_reset_expiration(); | 266 | | | 267 | | // Run the action | 268 | 32.8k | let ret = f(self, &mut stream); | 269 | | | 270 | 32.8k | self.transition_after(stream, is_pending_reset); | 271 | | | 272 | 32.8k | ret | 273 | 32.8k | } |
<h2::proto::streams::counts::Counts>::transition::<<h2::proto::streams::streams::Inner>::handle_error<bytes::bytes::Bytes>::{closure#0}::{closure#0}, ()>Line | Count | Source | 260 | 237k | pub fn transition<F, U>(&mut self, mut stream: store::Ptr, f: F) -> U | 261 | 237k | where | 262 | 237k | F: FnOnce(&mut Self, &mut store::Ptr) -> U, | 263 | | { | 264 | | // TODO: Does this need to be computed before performing the action? | 265 | 237k | let is_pending_reset = stream.is_pending_reset_expiration(); | 266 | | | 267 | | // Run the action | 268 | 237k | let ret = f(self, &mut stream); | 269 | | | 270 | 237k | self.transition_after(stream, is_pending_reset); | 271 | | | 272 | 237k | ret | 273 | 237k | } |
<h2::proto::streams::counts::Counts>::transition::<<h2::proto::streams::streams::Inner>::recv_go_away<bytes::bytes::Bytes>::{closure#0}::{closure#0}, ()>Line | Count | Source | 260 | 4.00k | pub fn transition<F, U>(&mut self, mut stream: store::Ptr, f: F) -> U | 261 | 4.00k | where | 262 | 4.00k | F: FnOnce(&mut Self, &mut store::Ptr) -> U, | 263 | | { | 264 | | // TODO: Does this need to be computed before performing the action? | 265 | 4.00k | let is_pending_reset = stream.is_pending_reset_expiration(); | 266 | | | 267 | | // Run the action | 268 | 4.00k | let ret = f(self, &mut stream); | 269 | | | 270 | 4.00k | self.transition_after(stream, is_pending_reset); | 271 | | | 272 | 4.00k | ret | 273 | 4.00k | } |
<h2::proto::streams::counts::Counts>::transition::<<h2::proto::streams::streams::Inner>::recv_eof<bytes::bytes::Bytes>::{closure#0}::{closure#0}, ()>Line | Count | Source | 260 | 190k | pub fn transition<F, U>(&mut self, mut stream: store::Ptr, f: F) -> U | 261 | 190k | where | 262 | 190k | F: FnOnce(&mut Self, &mut store::Ptr) -> U, | 263 | | { | 264 | | // TODO: Does this need to be computed before performing the action? | 265 | 190k | let is_pending_reset = stream.is_pending_reset_expiration(); | 266 | | | 267 | | // Run the action | 268 | 190k | let ret = f(self, &mut stream); | 269 | | | 270 | 190k | self.transition_after(stream, is_pending_reset); | 271 | | | 272 | 190k | ret | 273 | 190k | } |
<h2::proto::streams::counts::Counts>::transition::<<h2::proto::streams::streams::StreamRef<bytes::bytes::Bytes>>::send_data::{closure#0}, core::result::Result<(), h2::codec::error::UserError>>Line | Count | Source | 260 | 406k | pub fn transition<F, U>(&mut self, mut stream: store::Ptr, f: F) -> U | 261 | 406k | where | 262 | 406k | F: FnOnce(&mut Self, &mut store::Ptr) -> U, | 263 | | { | 264 | | // TODO: Does this need to be computed before performing the action? | 265 | 406k | let is_pending_reset = stream.is_pending_reset_expiration(); | 266 | | | 267 | | // Run the action | 268 | 406k | let ret = f(self, &mut stream); | 269 | | | 270 | 406k | self.transition_after(stream, is_pending_reset); | 271 | | | 272 | 406k | ret | 273 | 406k | } |
|
274 | | |
275 | | // TODO: move this to macro? |
276 | 2.42M | pub fn transition_after(&mut self, mut stream: store::Ptr, is_reset_counted: bool) { |
277 | 2.42M | tracing::trace!( |
278 | 0 | "transition_after; stream={:?}; state={:?}; is_closed={:?}; \ |
279 | 0 | pending_send_empty={:?}; buffered_send_data={}; \ |
280 | 0 | num_recv={}; num_send={}", |
281 | 0 | stream.id, |
282 | 0 | stream.state, |
283 | 0 | stream.is_closed(), |
284 | 0 | stream.pending_send.is_empty(), |
285 | 0 | stream.buffered_send_data, |
286 | | self.num_recv_streams, |
287 | | self.num_send_streams |
288 | | ); |
289 | | |
290 | 2.42M | if stream.is_closed() { |
291 | 1.22M | if !stream.is_pending_reset_expiration() { |
292 | 1.16M | stream.unlink(); |
293 | 1.16M | if is_reset_counted { |
294 | 43.0k | self.dec_num_reset_streams(); |
295 | 1.12M | } |
296 | 57.3k | } |
297 | | |
298 | 1.22M | if !stream.state.is_scheduled_reset() && stream.is_counted { |
299 | 201k | tracing::trace!("dec_num_streams; stream={:?}", stream.id); |
300 | | // Decrement the number of active streams. |
301 | 201k | self.dec_num_streams(&mut stream); |
302 | 1.02M | } |
303 | 1.20M | } |
304 | | |
305 | | // Release the stream if it requires releasing |
306 | 2.42M | if stream.is_released() { |
307 | 421k | stream.remove(); |
308 | 2.00M | } |
309 | 2.42M | } |
310 | | |
311 | | /// Returns the maximum number of streams that can be initiated by this |
312 | | /// peer. |
313 | 0 | pub(crate) fn max_send_streams(&self) -> usize { |
314 | 0 | self.max_send_streams |
315 | 0 | } |
316 | | |
317 | | /// Returns the maximum number of streams that can be initiated by the |
318 | | /// remote peer. |
319 | 0 | pub(crate) fn max_recv_streams(&self) -> usize { |
320 | 0 | self.max_recv_streams |
321 | 0 | } |
322 | | |
323 | 201k | fn dec_num_streams(&mut self, stream: &mut store::Ptr) { |
324 | 201k | assert!(stream.is_counted); |
325 | | |
326 | 201k | if self.peer.is_local_init(stream.id) { |
327 | 201k | assert!(self.num_send_streams > 0); |
328 | 201k | self.num_send_streams -= 1; |
329 | 201k | stream.is_counted = false; |
330 | | } else { |
331 | 3 | assert!(self.num_recv_streams > 0); |
332 | 3 | self.num_recv_streams -= 1; |
333 | 3 | stream.is_counted = false; |
334 | | } |
335 | 201k | } |
336 | | |
337 | 43.0k | fn dec_num_reset_streams(&mut self) { |
338 | 43.0k | assert!(self.num_local_reset_streams > 0); |
339 | 43.0k | self.num_local_reset_streams -= 1; |
340 | 43.0k | } |
341 | | } |
342 | | |
343 | | impl Drop for Counts { |
344 | 12.7k | fn drop(&mut self) { |
345 | | use std::thread; |
346 | | |
347 | 12.7k | if !thread::panicking() { |
348 | 12.7k | debug_assert!(!self.has_streams()); |
349 | 0 | } |
350 | 12.7k | } |
351 | | } |
352 | | |
353 | | #[cfg(test)] |
354 | | mod tests { |
355 | | use super::*; |
356 | | use crate::frame::DEFAULT_INITIAL_WINDOW_SIZE; |
357 | | |
358 | | fn counts() -> Counts { |
359 | | Counts::new( |
360 | | peer::Dyn::Server, |
361 | | &Config { |
362 | | initial_max_send_streams: 0, |
363 | | local_max_buffer_size: 0, |
364 | | local_next_stream_id: 2.into(), |
365 | | local_push_enabled: false, |
366 | | extended_connect_protocol_enabled: false, |
367 | | local_reset_duration: Duration::ZERO, |
368 | | local_reset_max: 0, |
369 | | remote_reset_max: 0, |
370 | | remote_init_window_sz: DEFAULT_INITIAL_WINDOW_SIZE, |
371 | | remote_max_initiated: None, |
372 | | local_max_error_reset_streams: None, |
373 | | data_frame_budget: DEFAULT_DATA_FRAME_BUDGET, |
374 | | }, |
375 | | ) |
376 | | } |
377 | | |
378 | | #[test] |
379 | | fn budget_is_bounded() { |
380 | | let mut budget = Budget::new(10); |
381 | | |
382 | | budget.consume(4).unwrap(); |
383 | | budget.replenish(20); |
384 | | assert_eq!(budget.available, 10); |
385 | | } |
386 | | |
387 | | #[test] |
388 | | fn budget_reports_exhaustion_without_underflowing() { |
389 | | let mut budget = Budget::new(10); |
390 | | |
391 | | budget.consume(10).unwrap(); |
392 | | assert!(budget.consume(1).is_err()); |
393 | | assert_eq!(budget.available, 0); |
394 | | } |
395 | | |
396 | | #[test] |
397 | | fn good_sized_data_frames_do_not_exhaust_budget() { |
398 | | let mut counts = counts(); |
399 | | |
400 | | for _ in 0..1_000_000 { |
401 | | counts |
402 | | .record_data_frame(DEFAULT_DATA_FRAME_OVERHEAD_THRESHOLD) |
403 | | .unwrap(); |
404 | | } |
405 | | } |
406 | | |
407 | | #[test] |
408 | | fn consumed_small_data_frames_do_not_exhaust_budget() { |
409 | | let mut counts = counts(); |
410 | | |
411 | | for _ in 0..1_000_000 { |
412 | | counts.record_data_frame(1).unwrap(); |
413 | | counts.release_data_frame(1); |
414 | | } |
415 | | } |
416 | | |
417 | | #[test] |
418 | | fn empty_data_frames_do_not_consume_data_frame_budget() { |
419 | | let mut counts = counts(); |
420 | | counts.data_frame_budget = Budget::new(0); |
421 | | |
422 | | for _ in 0..MAX_RECV_EMPTY_DATA_FRAMES { |
423 | | counts.record_data_frame(0).unwrap(); |
424 | | } |
425 | | |
426 | | // Empty frames have their own limit, while a non-empty small frame |
427 | | // still consumes the independently configured DATA frame budget. |
428 | | assert!(counts.record_data_frame(0).is_err()); |
429 | | assert!(counts.record_data_frame(1).is_err()); |
430 | | } |
431 | | |
432 | | #[test] |
433 | | fn large_data_frames_do_not_replenish_empty_data_frame_limit() { |
434 | | let mut counts = counts(); |
435 | | |
436 | | for _ in 0..MAX_RECV_EMPTY_DATA_FRAMES { |
437 | | counts.record_data_frame(0).unwrap(); |
438 | | counts |
439 | | .record_data_frame(DEFAULT_DATA_FRAME_OVERHEAD_THRESHOLD * 2) |
440 | | .unwrap(); |
441 | | } |
442 | | assert!(counts.record_data_frame(0).is_err()); |
443 | | } |
444 | | } |