Release closed streams capacity back to connection (#334)
Previously, any streams that were dropped or closed while not having consumed the inflight received window capacity would simply leak that capacity for the connection. This could easily happen if a `RecvStream` were dropped before fully consuming the data, and therefore a user would have no idea how much capacity to release in the first place. This resulted in stalled connections that would never have capacity again.
This commit is contained in:
		| @@ -334,7 +334,11 @@ impl Recv { | ||||
|         capacity: WindowSize, | ||||
|         task: &mut Option<Task>, | ||||
|     ) { | ||||
|         trace!("release_connection_capacity; size={}", capacity); | ||||
|         trace!( | ||||
|             "release_connection_capacity; size={}, connection in_flight_data={}", | ||||
|             capacity, | ||||
|             self.in_flight_data, | ||||
|         ); | ||||
|  | ||||
|         // Decrement in-flight data | ||||
|         self.in_flight_data -= capacity; | ||||
| @@ -383,6 +387,31 @@ impl Recv { | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     /// Release any unclaimed capacity for a closed stream. | ||||
|     pub fn release_closed_capacity( | ||||
|         &mut self, | ||||
|         stream: &mut store::Ptr, | ||||
|         task: &mut Option<Task>, | ||||
|     ) { | ||||
|         debug_assert_eq!(stream.ref_count, 0); | ||||
|  | ||||
|         if stream.in_flight_recv_data == 0 { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         trace!( | ||||
|             "auto-release closed stream ({:?}) capacity: {:?}", | ||||
|             stream.id, | ||||
|             stream.in_flight_recv_data, | ||||
|         ); | ||||
|  | ||||
|         self.release_connection_capacity( | ||||
|             stream.in_flight_recv_data, | ||||
|             task, | ||||
|         ); | ||||
|         stream.in_flight_recv_data = 0; | ||||
|     } | ||||
|  | ||||
|     /// Set the "target" connection window size. | ||||
|     /// | ||||
|     /// By default, all new connections start with 64kb of window size. As | ||||
| @@ -515,12 +544,6 @@ impl Recv { | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         // Update stream level flow control | ||||
|         stream.recv_flow.send_data(sz); | ||||
|  | ||||
|         // Track the data as in-flight | ||||
|         stream.in_flight_recv_data += sz; | ||||
|  | ||||
|         if stream.dec_content_length(frame.payload().len()).is_err() { | ||||
|             trace!("content-length overflow"); | ||||
|             return Err(RecvError::Stream { | ||||
| @@ -544,6 +567,12 @@ impl Recv { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Update stream level flow control | ||||
|         stream.recv_flow.send_data(sz); | ||||
|  | ||||
|         // Track the data as in-flight | ||||
|         stream.in_flight_recv_data += sz; | ||||
|  | ||||
|         let event = Event::Data(frame.into_payload()); | ||||
|  | ||||
|         // Push the frame onto the recv buffer | ||||
|   | ||||
| @@ -1118,10 +1118,16 @@ fn drop_stream_ref(inner: &Mutex<Inner>, key: store::Key) { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     me.counts.transition(stream, |counts, stream| { | ||||
|         maybe_cancel(stream, actions, counts); | ||||
|  | ||||
|         if stream.ref_count == 0 { | ||||
|  | ||||
|             // Release any recv window back to connection, no one can access | ||||
|             // it anymore. | ||||
|             actions.recv.release_closed_capacity(stream, &mut actions.task); | ||||
|  | ||||
|             // We won't be able to reach our push promises anymore | ||||
|             let mut ppp = stream.pending_push_promises.take(); | ||||
|             while let Some(promise) = ppp.pop(stream.store_mut()) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user