Skip to content

Commit f65fb86

Browse files
committed
Improve flow control handling allowing connection local window to have desired high water mark.
1 parent d9a367d commit f65fb86

File tree

4 files changed

+35
-15
lines changed

4 files changed

+35
-15
lines changed

lib/protocol/http2/connection.rb

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ def initialize(framer, local_stream_id)
5555
@decoder = HPACK::Context.new
5656
@encoder = HPACK::Context.new
5757

58-
@local_window = Window.new(@local_settings.initial_window_size)
59-
@remote_window = Window.new(@remote_settings.initial_window_size)
58+
@local_window = LocalWindow.new
59+
@remote_window = Window.new
6060
end
6161

6262
def id
@@ -183,13 +183,6 @@ def send_settings(changes)
183183
frame.pack(changes)
184184

185185
write_frame(frame)
186-
187-
# If the initial window size is set to something bigger than the default, we want to increase it.
188-
difference = @local_settings.pending.initial_window_size - @local_window.capacity
189-
190-
if difference > 0
191-
send_window_update(difference)
192-
end
193186
end
194187

195188
# Transition the connection into the closed state.
@@ -235,6 +228,8 @@ def update_local_settings(changes)
235228
@streams.each_value do |stream|
236229
stream.local_window.capacity = capacity
237230
end
231+
232+
@local_window.desired = capacity
238233
end
239234

240235
def update_remote_settings(changes)

lib/protocol/http2/flow_controlled.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,14 @@ def update_local_window(frame)
6060
end
6161

6262
def consume_local_window(frame)
63+
# For flow-control calculations, the 9-octet frame header is not counted.
6364
amount = frame.length
6465
@local_window.consume(amount)
6566
end
6667

6768
def request_window_update
6869
if @local_window.limited?
69-
self.send_window_update(@local_window.used)
70+
self.send_window_update(@local_window.wanted)
7071
end
7172
end
7273

lib/protocol/http2/window_update_frame.rb

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ def initialize(capacity = 0xFFFF)
3333
@capacity = capacity
3434
end
3535

36-
def dup
37-
return self.class.new(@capacity)
38-
end
39-
4036
# The window is completely full?
4137
def full?
4238
@available <= 0
@@ -73,6 +69,10 @@ def expand(amount)
7369
end
7470
end
7571

72+
def wanted
73+
@used
74+
end
75+
7676
def limited?
7777
@available < (@capacity / 2)
7878
end
@@ -82,6 +82,30 @@ def to_s
8282
end
8383
end
8484

85+
# This is a window which efficiently maintains a desired capacity.
86+
class LocalWindow < Window
87+
def initialize(capacity = 0xFFFF, desired: nil)
88+
super(capacity)
89+
90+
@desired = desired
91+
end
92+
93+
attr_accessor :desired
94+
95+
def wanted
96+
if @desired
97+
# We must send an update which allows at least @desired bytes to be sent.
98+
(@desired - @capacity) + @used
99+
else
100+
@used
101+
end
102+
end
103+
104+
def limited?
105+
@available < ((@desired || @capacity) / 2)
106+
end
107+
end
108+
85109
# The WINDOW_UPDATE frame is used to implement flow control.
86110
#
87111
# +-+-------------------------------------------------------------+

spec/protocol/http2/window_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
expect(frame.unpack).to eq 120
8888
end
8989

90-
context '#receive_window_update' do
90+
describe '#receive_window_update' do
9191
it "should be invoked when window update is received" do
9292
# Write 200 bytes of data (client -> server) which exhausts server local window
9393
stream.send_data("*" * 200)

0 commit comments

Comments
 (0)