Class: Async::Node

Inherits:
Object
  • Object
show all
Defined in:
lib/async/node.rb

Overview

A node in a tree, used for implementing the task hierarchy.

Direct Known Subclasses

Scheduler, Task

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parent = nil, annotation: nil, transient: false) ⇒ Node

Create a new node in the tree.



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/async/node.rb', line 57

def initialize(parent = nil, annotation: nil, transient: false)
	@parent = nil
	@children = nil
	
	@annotation = annotation
	@object_name = nil
	
	@transient = transient
	
	@head = nil
	@tail = nil
	
	if parent
		parent.add_child(self)
	end
end

Instance Attribute Details

#annotationObject (readonly)

A useful identifier for the current node.



92
93
94
# File 'lib/async/node.rb', line 92

def annotation
  @annotation
end

#childrenObject (readonly)

Returns the value of attribute children.



89
90
91
# File 'lib/async/node.rb', line 89

def children
  @children
end

#headObject



80
81
82
# File 'lib/async/node.rb', line 80

def head
  @head
end

#parentObject

Returns the value of attribute parent.



86
87
88
# File 'lib/async/node.rb', line 86

def parent
  @parent
end

#tailObject



83
84
85
# File 'lib/async/node.rb', line 83

def tail
  @tail
end

Instance Method Details

#annotate(annotation) ⇒ Object



110
111
112
113
114
115
116
117
118
119
# File 'lib/async/node.rb', line 110

def annotate(annotation)
	if block_given?
		previous_annotation = @annotation
		@annotation = annotation
		yield
		@annotation = previous_annotation
	else
		@annotation = annotation
	end
end

#backtrace(*arguments) ⇒ Object



133
134
135
# File 'lib/async/node.rb', line 133

def backtrace(*arguments)
	nil
end

#children?Boolean

Whether this node has any children.

Returns:

  • (Boolean)


96
97
98
# File 'lib/async/node.rb', line 96

def children?
	@children && !@children.empty?
end

#consumeObject

If the node has a parent, and is #finished?, then remove this node from the parent.



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/async/node.rb', line 186

def consume
	if parent = @parent and finished?
		parent.remove_child(self)
		
		if @children
			@children.each do |child|
				if child.finished?
					remove_child(child)
				else
					# In theory we don't need to do this... because we are throwing away the list. However, if you don't correctly update the list when moving the child to the parent, it foobars the enumeration, and subsequent nodes will be skipped, or in the worst case you might start enumerating the parents nodes.
					remove_child(child)
					parent.add_child(child)
				end
			end
			
			@children = nil
		end
		
		parent.consume
	end
end

#descriptionObject



121
122
123
124
125
126
127
128
129
130
131
# File 'lib/async/node.rb', line 121

def description
	@object_name ||= "#{self.class}:#{format '%#018x', object_id}#{@transient ? ' transient' : nil}"
	
	if @annotation
		"#{@object_name} #{@annotation}"
	elsif line = self.backtrace(0, 1)&.first
		"#{@object_name} #{line}"
	else
		@object_name
	end
end

#finished?Boolean

Whether the node can be consumed (deleted) safely. By default, checks if the children set is empty.

Returns:

  • (Boolean)


180
181
182
# File 'lib/async/node.rb', line 180

def finished?
	@children.nil? || @children.finished?
end


256
257
258
259
260
261
262
263
264
# File 'lib/async/node.rb', line 256

def print_hierarchy(out = $stdout, backtrace: true)
	self.traverse do |node, level|
		indent = "\t" * level
		
		out.puts "#{indent}#{node}"
		
		print_backtrace(out, indent, node) if backtrace
	end
end

#rootObject



75
76
77
# File 'lib/async/node.rb', line 75

def root
	@parent&.root || self
end

#stop(later = false) ⇒ Object

Attempt to stop the current node immediately, including all non-transient children. Invokes #stop_children to stop all children.



240
241
242
243
# File 'lib/async/node.rb', line 240

def stop(later = false)
	# The implementation of this method may defer calling `stop_children`.
	stop_children(later)
end

#stopped?Boolean

Returns:

  • (Boolean)


252
253
254
# File 'lib/async/node.rb', line 252

def stopped?
	@children.nil?
end

#terminateObject

Immediately terminate all children tasks, including transient tasks. Internally invokes ‘stop(false)` on all children. This should be considered a last ditch effort and is used when closing the scheduler.



227
228
229
230
231
232
233
234
235
# File 'lib/async/node.rb', line 227

def terminate
	# Attempt to stop the current task immediately, and all children:
	stop(false)
	
	# If that doesn't work, take more serious action:
	@children&.each do |child|
		child.terminate
	end
end

#The parent node.=(parentnode. = (value)) ⇒ Object



86
# File 'lib/async/node.rb', line 86

attr :parent

#to_sObject Also known as: inspect



137
138
139
# File 'lib/async/node.rb', line 137

def to_s
	"\#<#{self.description}>"
end

#transient?Boolean

Represents whether a node is transient. Transient nodes are not considered when determining if a node is finished. This is useful for tasks which are internal to an object rather than explicit user concurrency. For example, a child task which is pruning a connection pool is transient, because it is not directly related to the parent task, and should not prevent the parent task from finishing.

Returns:

  • (Boolean)


106
107
108
# File 'lib/async/node.rb', line 106

def transient?
	@transient
end

#traverse(&block) ⇒ Object

Traverse the task tree.



212
213
214
215
216
# File 'lib/async/node.rb', line 212

def traverse(&block)
	return enum_for(:traverse) unless block_given?
	
	self.traverse_recurse(&block)
end