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.



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/protocol/http2/dependency.rb', line 55

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.



86
87
88
# File 'lib/protocol/http2/dependency.rb', line 86

def children
  @children
end

#connectionObject (readonly)

The connection this stream belongs to.



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

def connection
  @connection
end

#idObject (readonly)

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



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

def id
  @id
end

#parentObject

The parent dependency.



83
84
85
# File 'lib/protocol/http2/dependency.rb', line 83

def parent
  @parent
end

#weightObject

The weight of the stream relative to other siblings.



89
90
91
# File 'lib/protocol/http2/dependency.rb', line 89

def weight
  @weight
end

Class Method Details

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



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/protocol/http2/dependency.rb', line 26

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



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

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

#add_child(dependency) ⇒ Object



113
114
115
116
117
118
119
120
# File 'lib/protocol/http2/dependency.rb', line 113

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

#clear_cache!Object



95
96
97
# File 'lib/protocol/http2/dependency.rb', line 95

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.



206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/protocol/http2/dependency.rb', line 206

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



99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/protocol/http2/dependency.rb', line 99

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.



130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/protocol/http2/dependency.rb', line 130

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

#ordered_childrenObject



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

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


225
226
227
228
229
230
# File 'lib/protocol/http2/dependency.rb', line 225

def print_hierarchy(buffer, indent: 0)
	buffer.puts "#{" " * indent}#{self}"
	@children&.each_value do |child|
		child.print_hierarchy(buffer, indent: indent+1)
	end
end

#priority(exclusive = false) ⇒ Object

The current local priority of the stream.



175
176
177
# File 'lib/protocol/http2/dependency.rb', line 175

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

#priority=(priority) ⇒ Object

Change the priority of the stream both locally and remotely.



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

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

#process_priority(priority) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/protocol/http2/dependency.rb', line 145

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



183
184
185
# File 'lib/protocol/http2/dependency.rb', line 183

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

#remove_child(dependency) ⇒ Object



122
123
124
125
126
# File 'lib/protocol/http2/dependency.rb', line 122

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

#send_priority(priority) ⇒ Object



179
180
181
# File 'lib/protocol/http2/dependency.rb', line 179

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

#streamObject



91
92
93
# File 'lib/protocol/http2/dependency.rb', line 91

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

#to_sObject



221
222
223
# File 'lib/protocol/http2/dependency.rb', line 221

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

#total_weightObject



187
188
189
190
191
# File 'lib/protocol/http2/dependency.rb', line 187

def total_weight
	self.orderd_children
	
	return @total_weight
end