protocol-http2 0.11.3 → 0.11.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b022547ae1f667d447eacb064d19730d31172074f190b86918fbf1f98a815fd
4
- data.tar.gz: 8ae5a803210cffae68a5742724e6eaf3dd3525151ad3a2a44f22dc8167dc6058
3
+ metadata.gz: 1f02e8cbaee2f19317b390dc39177277184fe4a991b6780dcac1196303f63f2f
4
+ data.tar.gz: b10e1e173deddc82eb51f1f06d12df54b0c468b5db5154e13f0b01a2347ed182
5
5
  SHA512:
6
- metadata.gz: 429cf7a735c1a99a525cb33ad0e0ffbf0b4e8b52c776bfa365bff6095f585e0cde7574698521153ab068ecca5e57ccde04375a7265b2caee47309cf4b7f5f32d
7
- data.tar.gz: 29a1f37e144a4713471a73df47f3c2b56b32bd3ef79b83e2da874a77d6a5f28eb8f3800d9208abc93a8d73cb78489e4d8ab18f75602e1f82b4059141bf9457b6
6
+ metadata.gz: b326149b77c6064f93eb206aed282668ad2163f93f073ccba935e8c84c4e608d90ccc1d9f17841e88794915594e91aaaeb73b42c39175440a2603ed65a825275
7
+ data.tar.gz: f844428f6a8755569e915edf5089a56d039d21076e391c13d2766be0ceffbddbb58ea285ba143aac7f8668626c0b8509d7d37e15c80f891bcc402bef313c4987
@@ -20,13 +20,14 @@
20
20
 
21
21
  require_relative 'framer'
22
22
  require_relative 'dependency'
23
+ require_relative 'flow_controlled'
23
24
 
24
25
  require 'protocol/hpack'
25
26
 
26
27
  module Protocol
27
28
  module HTTP2
28
29
  class Connection
29
- include FlowControl
30
+ include FlowControlled
30
31
 
31
32
  def initialize(framer, local_stream_id)
32
33
  super()
@@ -465,6 +466,15 @@ module Protocol
465
466
  end
466
467
  end
467
468
 
469
+ # Traverse active streams in order of priority and allow them to consume the available flow-control window.
470
+ # @param amount [Integer] the amount of data to write. Defaults to the current window capacity.
471
+ def consume_window(size = self.available_size)
472
+ # Return if there is no window to consume:
473
+ return unless size > 0
474
+
475
+ @dependency.consume_window(size)
476
+ end
477
+
468
478
  def receive_window_update(frame)
469
479
  if frame.connection?
470
480
  super
@@ -18,14 +18,12 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require_relative 'flow_control'
22
-
23
21
  module Protocol
24
22
  module HTTP2
25
23
  DEFAULT_WEIGHT = 16
26
24
 
27
25
  class Dependency
28
- def initialize(connection, id, dependent_id = 0, weight = DEFAULT_WEIGHT, children = nil)
26
+ def initialize(connection, id, dependent_id = 0, weight = DEFAULT_WEIGHT)
29
27
  @connection = connection
30
28
  @id = id
31
29
 
@@ -33,8 +31,18 @@ module Protocol
33
31
  @dependent_id = dependent_id
34
32
  @weight = weight
35
33
 
36
- # A cache of dependencies that have child.dependent_id = self.id
37
- @children = children
34
+ @children = nil
35
+
36
+ # Cache of any associated stream:
37
+ @stream = nil
38
+
39
+ # Cache of children for window allocation:
40
+ @total_weight = 0
41
+ @ordered_children = nil
42
+ end
43
+
44
+ def <=> other
45
+ @weight <=> other.weight
38
46
  end
39
47
 
40
48
  def irrelevant?
@@ -62,34 +70,36 @@ module Protocol
62
70
  attr_accessor :weight
63
71
 
64
72
  def stream
65
- @connection.streams[@id]
73
+ @stream ||= @connection.streams[@id]
66
74
  end
67
75
 
68
- def streams
69
- if @children
70
- # TODO this O(N) operation affects performance.
71
- # It would be better to maintain a sorted list of children streams.
72
- @children.map{|id, dependency| dependency.stream}.compact
73
- end
76
+ def clear_cache!
77
+ @ordered_children = nil
74
78
  end
75
79
 
76
80
  def add_child(dependency)
77
81
  @children ||= {}
78
82
  @children[dependency.id] = dependency
83
+
84
+ self.clear_cache!
79
85
  end
80
86
 
81
87
  def remove_child(dependency)
82
88
  @children&.delete(dependency.id)
89
+
90
+ self.clear_cache!
83
91
  end
84
92
 
85
93
  def exclusive_child(parent)
86
94
  parent.children = @children
95
+ parent.clear_cache!
87
96
 
88
97
  @children.each_value do |child|
89
98
  child.dependent_id = parent.id
90
99
  end
91
100
 
92
101
  @children = {parent.id => parent}
102
+ self.clear_cache!
93
103
 
94
104
  parent.dependent_id = @id
95
105
  end
@@ -125,6 +135,8 @@ module Protocol
125
135
  @dependent_id = dependent_id
126
136
 
127
137
  self.parent.add_child(self)
138
+ else
139
+ self.parent&.clear_cache!
128
140
  end
129
141
  end
130
142
 
@@ -146,6 +158,34 @@ module Protocol
146
158
  def receive_priority(frame)
147
159
  self.process_priority(frame.unpack)
148
160
  end
161
+
162
+ def ordered_children
163
+ unless @ordered_children
164
+ if @children and !@children.empty?
165
+ @ordered_children = @children.values.sort
166
+ @total_weight = @ordered_children.sum(&:weight)
167
+ end
168
+ end
169
+
170
+ return @ordered_children
171
+ end
172
+
173
+ # Traverse active streams in order of priority and allow them to consume the available flow-control window.
174
+ # @param amount [Integer] the amount of data to write. Defaults to the current window capacity.
175
+ def consume_window(size)
176
+ # If there is an associated stream, give it priority:
177
+ if stream = self.stream
178
+ return if stream.window_updated(size)
179
+ end
180
+
181
+ # Otherwise, allow the dependent children to use up the available window:
182
+ self.ordered_children&.each do |child|
183
+ # Compute the proportional allocation:
184
+ allocated = (child.weight * size) / @total_weight
185
+
186
+ child.consume_window(allocated) if allocated > 0
187
+ end
188
+ end
149
189
  end
150
190
  end
151
191
  end
@@ -23,7 +23,7 @@ require_relative 'extensions/sum'
23
23
 
24
24
  module Protocol
25
25
  module HTTP2
26
- module FlowControl
26
+ module FlowControlled
27
27
  def available_size
28
28
  @remote_window.available
29
29
  end
@@ -98,35 +98,9 @@ module Protocol
98
98
  # The window has been expanded by the given amount.
99
99
  # @param size [Integer] the maximum amount of data to send.
100
100
  # @return [Boolean] whether the window update was used or not.
101
- def window_updated(size = self.available_size)
101
+ def window_updated(size)
102
102
  return false
103
103
  end
104
-
105
- # Traverse active streams in order of priority and allow them to consume the available flow-control window.
106
- # @todo This function can get slow when there are a lot of children [INEFFICIENT].
107
- # @param amount [Integer] the amount of data to write. Defaults to the current window capacity.
108
- def consume_window(size = self.available_size)
109
- # Don't consume more than the available window size:
110
- size = [self.available_size, size].min
111
- # puts "consume_window(#{size}) local_window=#{@local_window} remote_window=#{@remote_window}"
112
-
113
- # Return if there is no window to consume:
114
- return unless size > 0
115
-
116
- # Allow the current flow-controlled instance to use up the window:
117
- if !self.window_updated(size) and children = self.children
118
- children = children.sort_by(&:weight)
119
-
120
- # This must always be at least >= `children.size`, since stream weight can't be 0.
121
- total = children.sum(&:weight)
122
-
123
- children.each do |child|
124
- # Compute the proportional allocation:
125
- allocated = (child.weight * size) / total
126
- child.consume_window(allocated)
127
- end
128
- end
129
- end
130
104
  end
131
105
  end
132
106
  end
@@ -72,7 +72,7 @@ module Protocol
72
72
  #
73
73
  # State transition methods use a trailing "!".
74
74
  class Stream
75
- include FlowControl
75
+ include FlowControlled
76
76
 
77
77
  def self.create(connection, id)
78
78
  stream = self.new(connection, id)
@@ -124,10 +124,6 @@ module Protocol
124
124
  @dependency.parent = stream.dependency
125
125
  end
126
126
 
127
- def children
128
- @dependency&.streams
129
- end
130
-
131
127
  # The stream is being closed because the connection is being closed.
132
128
  def close(error = nil)
133
129
  end
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Protocol
22
22
  module HTTP2
23
- VERSION = "0.11.3"
23
+ VERSION = "0.11.4"
24
24
  end
25
25
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: protocol-http2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.3
4
+ version: 0.11.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -118,7 +118,7 @@ files:
118
118
  - lib/protocol/http2/error.rb
119
119
  - lib/protocol/http2/extensions/sum.rb
120
120
  - lib/protocol/http2/extensions/unpack.rb
121
- - lib/protocol/http2/flow_control.rb
121
+ - lib/protocol/http2/flow_controlled.rb
122
122
  - lib/protocol/http2/frame.rb
123
123
  - lib/protocol/http2/framer.rb
124
124
  - lib/protocol/http2/goaway_frame.rb
@@ -153,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
153
  - !ruby/object:Gem::Version
154
154
  version: '0'
155
155
  requirements: []
156
- rubygems_version: 3.0.6
156
+ rubygems_version: 3.1.2
157
157
  signing_key:
158
158
  specification_version: 4
159
159
  summary: A low level implementation of the HTTP/2 protocol.