protocol-http2 0.11.3 → 0.11.4

Sign up to get free protection for your applications and to get access to all the features.
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.