Class: Protocol::HTTP2::Dependency

Inherits:
Object
  • Object
show all
Defined in:
lib/protocol/http2/dependency.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(connection, id, weight = DEFAULT_WEIGHT) ⇒ Dependency

Returns a new instance of Dependency.



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/protocol/http2/dependency.rb', line 40

def initialize(connection, id, weight = DEFAULT_WEIGHT)
  @connection = connection
  @id = id
  
  @parent = nil
  @children = nil
  
  @weight = weight
  
  # Cache of any associated stream:
  @stream = nil
  
  # Cache of children for window allocation:
  @total_weight = 0
  @ordered_children = nil
end

Instance Attribute Details

#childrenObject

The dependent children.



71
72
73
# File 'lib/protocol/http2/dependency.rb', line 71

def children
  @children
end

#connectionObject (readonly)

The connection this stream belongs to.



62
63
64
# File 'lib/protocol/http2/dependency.rb', line 62

def connection
  @connection
end

#idObject (readonly)

Stream ID (odd for client initiated streams, even otherwise).



65
66
67
# File 'lib/protocol/http2/dependency.rb', line 65

def id
  @id
end

#parentObject

The parent dependency.



68
69
70
# File 'lib/protocol/http2/dependency.rb', line 68

def parent
  @parent
end

#weightObject

The weight of the stream relative to other siblings.



74
75
76
# File 'lib/protocol/http2/dependency.rb', line 74

def weight
  @weight
end

Class Method Details

.create(connection, id, priority = nil) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/protocol/http2/dependency.rb', line 11

def self.create(connection, id, priority = nil)
  weight = DEFAULT_WEIGHT
  exclusive = false
  
  if priority
    if parent = connection.dependencies[priority.stream_dependency]
      exclusive = priority.exclusive
    end
    
    weight = priority.weight
  end
  
  if parent.nil?
    parent = connection.dependency
  end
  
  dependency = self.new(connection, id, weight)
  
  connection.dependencies[id] = dependency
  
  if exclusive
    parent.exclusive_child(dependency)
  else
    parent.add_child(dependency)
  end
  
  return dependency
end

Instance Method Details

#<=>(other) ⇒ Object



57
58
59
# File 'lib/protocol/http2/dependency.rb', line 57

def <=> other
  @weight <=> other.weight
end

#add_child(dependency) ⇒ Object



98
99
100
101
102
103
104
105
# File 'lib/protocol/http2/dependency.rb', line 98

def add_child(dependency)
  @children ||= {}
  @children[dependency.id] = dependency
  
  dependency.parent = self
  
  self.clear_cache!
end

#clear_cache!Object



80
81
82
# File 'lib/protocol/http2/dependency.rb', line 80

def clear_cache!
  @ordered_children = nil
end

#consume_window(size) ⇒ Object

Traverse active streams in order of priority and allow them to consume the available flow-control window.

Parameters:

  • amount (Integer)

    the amount of data to write. Defaults to the current window capacity.



191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/protocol/http2/dependency.rb', line 191

def consume_window(size)
  # If there is an associated stream, give it priority:
  if stream = self.stream
    return if stream.window_updated(size)
  end
  
  # Otherwise, allow the dependent children to use up the available window:
  self.ordered_children&.each do |child|
    # Compute the proportional allocation:
    allocated = (child.weight * size) / @total_weight
    
    child.consume_window(allocated) if allocated > 0
  end
end

#delete!Object



84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/protocol/http2/dependency.rb', line 84

def delete!
  @connection.dependencies.delete(@id)
  
  @parent.remove_child(self)
  
  @children&.each do |id, child|
    parent.add_child(child)
  end
  
  @connection = nil
  @parent = nil
  @children = nil
end

#exclusive_child(parent) ⇒ Object

An exclusive flag allows for the insertion of a new level of dependencies. The exclusive flag causes the stream to become the sole dependency of its parent stream, causing other dependencies to become dependent on the exclusive stream.

Parameters:

  • parent (Dependency)

    the dependency which will be inserted, taking control of all current children.



115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/protocol/http2/dependency.rb', line 115

def exclusive_child(parent)
  parent.children = @children
  
  @children&.each_value do |child|
    child.parent = parent
  end
  
  parent.clear_cache!
  
  @children = {parent.id => parent}
  self.clear_cache!
  
  parent.parent = self
end

#inspectObject



206
207
208
# File 'lib/protocol/http2/dependency.rb', line 206

def inspect
  "\#<#{self.class} id=#{@id} parent id=#{@parent&.id} weight=#{@weight} #{@children&.size || 0} children>"
end

#ordered_childrenObject



178
179
180
181
182
183
184
185
186
187
# File 'lib/protocol/http2/dependency.rb', line 178

def ordered_children
  unless @ordered_children
    if @children and !@children.empty?
      @ordered_children = @children.values.sort
      @total_weight = @ordered_children.sum(&:weight)
    end
  end
  
  return @ordered_children
end


210
211
212
213
214
215
# File 'lib/protocol/http2/dependency.rb', line 210

def print_hierarchy(output = $stderr, indent: 0)
  output.puts "#{"\t" * indent}#{self.inspect}"
  @children&.each_value do |child|
    child.print_hierarchy(output, indent: indent+1)
  end
end

#priority(exclusive = false) ⇒ Object

The current local priority of the stream.



160
161
162
# File 'lib/protocol/http2/dependency.rb', line 160

def priority(exclusive = false)
  Priority.new(exclusive, @parent.id, @weight)
end

#priority=(priority) ⇒ Object

Change the priority of the stream both locally and remotely.



154
155
156
157
# File 'lib/protocol/http2/dependency.rb', line 154

def priority= priority
  send_priority(priority)
  process_priority(priority)
end

#process_priority(priority) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/protocol/http2/dependency.rb', line 130

def process_priority(priority)
  dependent_id = priority.stream_dependency
  
  if dependent_id == @id
    raise ProtocolError, "Stream priority for stream id #{@id} cannot depend on itself!"
  end
  
  @weight = priority.weight
  
  # We essentially ignore `dependent_id` if the dependency does not exist:
  if parent = @connection.dependencies[dependent_id]
    if priority.exclusive
      @parent.remove_child(self)
      
      parent.exclusive_child(self)
    elsif !@parent.equal?(parent)
      @parent.remove_child(self)
      
      parent.add_child(self)
    end
  end
end

#receive_priority(frame) ⇒ Object



168
169
170
# File 'lib/protocol/http2/dependency.rb', line 168

def receive_priority(frame)
  self.process_priority(frame.unpack)
end

#remove_child(dependency) ⇒ Object



107
108
109
110
111
# File 'lib/protocol/http2/dependency.rb', line 107

def remove_child(dependency)
  @children&.delete(dependency.id)
  
  self.clear_cache!
end

#send_priority(priority) ⇒ Object



164
165
166
# File 'lib/protocol/http2/dependency.rb', line 164

def send_priority(priority)
  @connection.send_priority(@id, priority)
end

#streamObject



76
77
78
# File 'lib/protocol/http2/dependency.rb', line 76

def stream
  @stream ||= @connection.streams[@id]
end

#total_weightObject



172
173
174
175
176
# File 'lib/protocol/http2/dependency.rb', line 172

def total_weight
  self.ordered_children
  
  return @total_weight
end