Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hang with threads and Hash[]= on unfrozen keys #3171

Closed
Freaky opened this issue Jul 23, 2015 · 5 comments
Closed

Hang with threads and Hash[]= on unfrozen keys #3171

Freaky opened this issue Jul 23, 2015 · 5 comments

Comments

@Freaky
Copy link
Contributor

Freaky commented Jul 23, 2015

The following code reliably hangs JRuby 9k. Note the hashes are not shared between threads:

require 'securerandom'

Array.new(4).map do
  Thread.new do
    100_000.times do |i|
      print "#{Thread.current.inspect}: #{i}\n" if i % 1000 == 0
      key = SecureRandom.random_bytes(4)
      hash = {}
      hash[key] = true
    end
  end
end.map(&:join)

The hung threads are ending up here:

    at java.util.WeakHashMap.get(WeakHashMap.java:403)
    at org.jruby.Ruby.freezeAndDedupString(Ruby.java:4733)
    at org.jruby.RubyHash.op_asetForString(RubyHash.java:1017)
    at org.jruby.RubyHash.fastASetCheckString(RubyHash.java:969)
    at org.jruby.RubyHash.op_aset(RubyHash.java:1006)

Calling key.freeze prevents the problem.

Reproduced in:

  • jruby 9.0.0.0 (2.2.2) 2015-07-21 e10ec96 OpenJDK 64-Bit Server VM 25.51-b03 on 1.8.0_51-b16 +jit [FreeBSD-amd64]
  • jruby 9.0.0.0 (2.2.2) 2015-07-21 e10ec96 Java HotSpot(TM) 64-Bit Server VM 25.51-b03 on 1.8.0_51-b16 +jit [Windows 8.1-amd64]
@nirvdrum
Copy link
Contributor

The problem is WeakHashMap isn't thread-safe and an internal iterator can be corrupted, causing WeakHashMap#get to go into an infinite loop. The easiest solution is to synchronize the whole thing, but this will incur a small penalty on all reads.

@nirvdrum
Copy link
Contributor

@headius @enebo This is a naive fix, by synchronizing all the operations on that map. It's possible a ReadWriteLock could yield better performance if you're expecting mostly read-only entries. That lock is heavier weight than a mutex, however, so you'd need to make sure it pays for itself.

@enebo
Copy link
Member

enebo commented Jul 23, 2015

I think we should review this cache if this is the solution...re-opening

@enebo enebo reopened this Jul 23, 2015
@kares
Copy link
Member

kares commented Jul 23, 2015

a org.jruby.util.collections.WeakValuedMap should provide a ConcurrentHashMap-like cache

@headius
Copy link
Member

headius commented Jul 8, 2020

The logic here has been reworked since this bug was filed, most recently in 8d3bb53 which was included in JRuby 9.2.10.

The original case no longer hangs. I will mark this as fixed as of 9.2.1.0.

If you run into problems in the future, please file a new issue.

@headius headius closed this as completed Jul 8, 2020
@headius headius added this to the JRuby 9.2.1.0 milestone Jul 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants