History | Log In     View a printable version of the current page.  
Issue Details (XML | Word | Printable)

Key: JRUBY-572
Type: Bug Bug
Status: Closed Closed
Resolution: Fixed
Priority: Major Major
Assignee: Unassigned
Reporter: Derek Townsend
Votes: 2
Watchers: 2
Operations

If you were logged in you would be able to see more operations.
JRuby

Drb Client hangs on second call

Created: 09/Feb/07 12:54 PM   Updated: 06/May/07 09:49 PM
Component/s: Core Classes/Modules
Affects Version/s: JRuby 0.9.0, JRuby 0.9.1, JRuby 0.9.2
Fix Version/s: JRuby 1.0.0RC1

Time Tracking:
Not Specified

File Attachments: 1. Text File bufferedIoSelect.patch (7 kb)
2. Text File bufferedIoSelect_3536.patch (6 kb)

Environment: J2SE 6 running on RedHat FC6, using Jrubytrunk
Issue Links:
Duplicate
 

Testcase included: yes


 Description  « Hide
Second call to remote object hangs the client in Jruby. When tested with ruby confirmed that the client side hangs on the call. ruby client to Jruby server works.

Test_client.rb
require 'drb'

DRb.start_service()
obj = DRbObject.new(nil, 'druby://localhost:9000')

puts "First sum is #{obj.add(1, 2, 3)}"

puts "Second sum is #{obj.add(10,20,30)}"

puts "Shutting the service down remotely"

obj.shutdown()

puts "Done!"

test_server.rb
require 'drb'

class TestServer
def add(*args)
args.inject {|n,v| n+v}
end

def shutdown
DRb.stop_service
end
end

server = TestServer.new
DRb.start_service('druby://localhost:9000', server)
DRb.thread.join



 All   Comments   Work Log   Change History      Sort Order: Ascending order - Click to sort in descending order
Terry Woloszyn - 10/Feb/07 08:54 PM
have narrowed it down to the IO.select call in DRbTCPSocket#alive?
  • if IO.select([@socket], nil, nil, 0) - hangs forever.
    If a timeout is added, even as little as 0.05, then the call is retried twice, and proceeds normally, continuing to use the same connection.
    e.g. IO.select(socket, nil, nil, 0.05)

Probably a good reason why timeout was 0 to begin with, but this is working as a workaround in the test cases.

Threading issue? And if we leave the timeout in place, will it come back to bite us somewhere else?


Terry Woloszyn - 10/Feb/07 08:56 PM
sorry - the workaround should read
  • IO.select([@socket], nil, nil, 0.05)

Lyle Johnson - 22/Mar/07 04:43 PM
Also seeing this with Java5 on Mac OS X 10.4.9, using JRuby 0.9.8. Lemme know if I can help test a fix!

Bill Dortch - 22/Mar/07 11:40 PM
The request hangs here, in org.jruby.runtime.builtin.meta.IOMetaClass.select_static (lines 265-269):
if(args.length > 3) {
    selector.select(timeout);
  } else {
    selector.select();
  }

The selector.select call is made with a timeout value of 0.

I recall seeing something like this in a project I worked on a few years ago, but that was in C under Solaris. As I recall, the solution had to do with retrying after EAGAIN/EWOULDBLOCK was received, but I'm not sure how that maps into NIO (which I haven't worked with).

Meanwhile, I've been using Terry Woloszyn's solution, as follows:

require 'drb'
# temporary hack to work around jruby-drb problem
module DRb
class DRbTCPSocket
  def alive?
    return false unless @socket
    if IO.select([@socket], nil, nil, 0.05)
      close
      return false
    end
    true
  end
end #DRbTCPSocket
end #DRb

Jonathan Paisley - 23/Mar/07 09:58 AM
I took a look at this and determined the following:
  • A timeout of 0 on MRI is non-blocking, whereas JRuby blocks (since Selector.select interprets 0 timeout as blocking).
  • The TCP socket is buffered, and there is data in the buffer but not available on the socket.
  • IOMetaClass.registerSelect ignores any buffered data (from ungotc or the inBuffer in IOHandlerNio).

(on another note, it looks like IOHandlerNio won't reliably let you 'ungotc' a zero byte because there are several checks for 'ungotc>0' which should be 'ungotc>=0')

  • IOMetaClass.select_static should consider whether there is buffered data available, and do a non-blocking select and manually add to the read result array any io objects that were selected for reading and have buffered data.
  • io.c:rb_f_select from MRI does this buffered check business as described above.

I made some nasty hacks to verify that fixing the above resolves the problem with drb, but I suspect it's best left to the people who properly understand the JRuby IO infrastructure to make the proper interfaces.

Hope that helps!


Jonathan Paisley - 23/Mar/07 02:37 PM
I've attached a patch containing a variation on the nasty hacks alluded to in my earlier comment today.

IOHandler.hasPendingBuffered() perhaps has to be implemented correctly for other subclasses of IOHandler (currently only IOHandlerNio).

I've not tested this very thoroughly, so it may break some other things. It does seem to fix the test case described in this issue.


Terry Woloszyn - 23/Apr/07 02:00 PM
For ruby 1.8.5 (2007-04-23 rev 3489) [i386-jruby0.9.9-pre]
, the IOMetaClass.java has been folded into RubyIO. I recreated the original bufferedIoSelect patch for this release. Just "patch -p1 <..." to apply to current trunk.
BTW - nice job on the threading etc.! This release appears to have cured both a hanging issue, as well as InterruptedException issue I was having with concurrent access to DRb objects. I will continue testing, but this is real progress for DRb! Thanks!

Terry Woloszyn - 23/Apr/07 02:02 PM
here is the patch as desribed previously, updating the original patch for BufferedIoSelect. The original caveats still apply, but it seems to work for my test cases.

Thomas E Enebo - 26/Apr/07 03:29 PM
I applied the later patch for the most part. Drb works much better with this...

Charles Oliver Nutter - 06/May/07 09:49 PM
Closing for 1.0RC1