-
Notifications
You must be signed in to change notification settings - Fork 91
Closed
Description
RubyTree uses recursion for methods such as each and detached_subtree_copy. This is ok for smaller well-balanced trees, but fails for unbalanced trees when Fiber or Threads are involved.
Constructing and Walking a Linear Tree
See the following example method to construct a linear tree:
#!/usr/bin/ruby
require "tree"
def run_test(depth=100)
tree = Tree::TreeNode.new("/")
current = tree
depth.times do |i|
new_node = Tree::TreeNode.new("#{i}")
current << new_node
current = new_node
end
tree.each{|n| nil}
endThis runs fine when executed in the main thread...
puts "Run test in the main thread"
run_test()...but fails when a Fiber or Thread is involved:
puts "Run test in a fiber"
begin
Fiber.new do
run_test()
end.resume
rescue SystemStackError
puts "Fiber died."
end
puts "Run test in a thread"
begin
Thread.abort_on_exception = true
Thread.new do
run_test(600) # 600 is not chosen arbitrary: this is the first number where it fails here.
end
sleep(3)
rescue SystemStackError
puts "Thread died."
endNote that the recursion depth between Fiber and Thread differs.
Demo Output
The example script above produces the following output with my machine:
% ./example.rb
Run test in the main thread
Run test in a fiber
Fiber died.
Run test in a thread
Thread died.
Possible Solution
This should be resolvable by replacing the recursion in each, detached_subtree_copy and elsewhere with the respective iterative representation. each could possibly be fixed like this:
module Tree
class TreeNode
def each(&blk)
expand_nodes = [self]
while expand_nodes != []
current = expand_nodes.shift
yield current
expand_nodes = current.children.concat(expand_nodes)
end
end
endReactions are currently unavailable