-
-
Notifications
You must be signed in to change notification settings - Fork 102
Use loop-based DFS to resolve #341 (SystemStackError) #343
Use loop-based DFS to resolve #341 (SystemStackError) #343
Conversation
d0dc6d7
to
6c64ad2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This LGTM. Nice work! It's always great when users solve their own problems :).
I want to let @yujinakayama review this before we merge since he knows this code the best.
lib/rspec/support/source/node.rb
Outdated
return to_enum(__method__) unless block_given? | ||
|
||
yield self | ||
outstanding_nodes = [] | ||
outstanding_nodes << self |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can these two lines be combined into outstanding_nodes = [self]
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like combining these lines causes a segfault on 1.9.2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bizarre! Let’s keep them separate then.
lib/rspec/support/source/node.rb
Outdated
@@ -45,13 +45,18 @@ def location | |||
@location ||= args.find { |arg| arg.is_a?(Location) } | |||
end | |||
|
|||
def each(&block) | |||
def each |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the lack of spec to cover this (which is completely understandable!), can you leave a comment on this method explaining why it uses a loop-based approach instead of recursion?
Hmmm, according to this blog post we can configure the stack size with the
unless ENV['RUBY_THREAD_VM_STACK_SIZE'] == expected_value
message = "This spec is only valid when RUBY_THREAD_VM_STACK_SIZE is set to #{expected_value}"
ENV['CI'] ? fail(message) : skip(message)
end That should give us a spec that is skipped in non-CI environments (unless the developer sets the ENV var), covers the fix on travis, and ensures we don't accidentally remove the ENV export for CI in the future. Thoughts? |
@myronmarston I had to set it to I then investigated the alpine stack size defaults, and they seem normal:
Something strange seems to occur when executing ruby inside Docker. |
More digging... https://wiki.musl-libc.org/functional-differences-from-glibc.html#Thread-stack-size Possibly related to the fact Alpine linux uses musl glibc which has a far smaller stack size. 😬 |
@craigjbass Thanks for the fix! The new loop-based logic basically looks good, but it can be simplified as follows: def each
return to_enum(__method__) unless block_given?
node_queue = []
node_queue.push(self)
while (current_node = node_queue.shift)
yield current_node
node_queue.concat(current_node.children)
end
end |
Hey @yujinakayama the assignment inside the while loop conditional feels a bit obfuscated to me. You comfortable with this code being in the repo? |
9514946
to
bbb2c88
Compare
@yujinakayama have refactored and squashed my commits |
Hey - what are the steps to getting this merged and a release rolled out |
3.7.1 has been released with the fix. |
@myronmarston just a heads up: https://bugs.ruby-lang.org/issues/14387 |
This resolves performance issues in #341.
I tried to write a spec for this, but I couldn't get it to fail consistently. Stack-size is platform specific.