Drb bug?

The code I just posted on the client/server observer thread[1] seems to
expose a drb or ruby bug. It runs fine for about 20-30 seconds, and then:

(druby://tercel:32915)
/usr/local/lib/ruby/site_ruby/1.7/drb/drb.rb:22:in _id2ref': 0x200e1608 is recycled object (RangeError) from (druby://tercel:32915) /usr/local/lib/ruby/site_ruby/1.7/drb/drb.rb:22:into_obj’
from (druby://tercel:32915)
/usr/local/lib/ruby/site_ruby/1.7/drb/drb.rb:398:in to_obj' from (druby://tercel:32915) /usr/local/lib/ruby/site_ruby/1.7/drb/drb.rb:572:into_obj’
from (druby://tercel:32915)
/usr/local/lib/ruby/site_ruby/1.7/drb/drb.rb:143:in recv_request' from (druby://tercel:32915) /usr/local/lib/ruby/site_ruby/1.7/drb/drb.rb:490:inproc’
from (druby://tercel:32915)
/usr/local/lib/ruby/site_ruby/1.7/drb/drb.rb:483:in loop' from (druby://tercel:32915) /usr/local/lib/ruby/site_ruby/1.7/drb/drb.rb:532:inproc’
from (druby://tercel:32915)
/usr/local/lib/ruby/site_ruby/1.7/drb/drb.rb:482:in start' ... 12 levels... from server.rb:14:inx='
from server.rb:34
from server.rb:33:in `loop’
from server.rb:40

This is with ruby 1.7.3, 2002-12-12.

[1] http://ruby-talk.org/61263

Hi, Joel.

The code I just posted on the client/server observer thread[1] seems
to expose a drb or ruby bug. It runs fine for about 20-30 seconds, and
then:

I think, its blocks were GCed.
Application should hold reference of Proc object.

[http://ruby-talk.org/blade/61263]

========= client.rb =======

require ‘drb’
DRb.start_service()
server = DRbObject.new(nil, ‘druby://localhost:9500’)

(0…9).each do |i|
server.register 100*i + i do |val| puts val end
===================== Proc object
end

sleep

for example … # sorry, it is untested.

block = Proc.new { |val| puts val }
(0…9).each do |i|
server.register(100*i + 1, &block)
end

···

On 2003.1.12, at 11:14 AM, Joel VanderWerf wrote:

Masatoshi SEKI wrote:

Hi, Joel.

The code I just posted on the client/server observer thread[1] seems
to expose a drb or ruby bug. It runs fine for about 20-30 seconds, and
then:

I think, its blocks were GCed.
Application should hold reference of Proc object.

[http://ruby-talk.org/blade/61263]

========= client.rb =======

require ‘drb’
DRb.start_service()
server = DRbObject.new(nil, ‘druby://localhost:9500’)

(0…9).each do |i|
server.register 100*i + i do |val| puts val end
===================== Proc object
end

sleep

for example … # sorry, it is untested.

block = Proc.new { |val| puts val }
(0…9).each do |i|
server.register(100*i + 1, &block)
end

Same problem, after this change.

But you are right about GC being involved. GC.disable in the client
prevents the problem from happening. So something else is getting
collected. (Is it possible that the proc is copied internally?)

···

On 2003.1.12, at 11:14 AM, Joel VanderWerf wrote:

Hi,

for example … # sorry, it is untested.

block = Proc.new { |val| puts val }
(0…9).each do |i|
server.register(100*i + 1, &block)
end

Same problem, after this change.

But you are right about GC being involved. GC.disable in the client
prevents the problem from happening. So something else is getting
collected. (Is it possible that the proc is copied internally?)

oops. it is drb’s problem. I have noticed this behavior just now.

blk = Proc.new { |x| }
p blk.id # → 537833186
p blk # → #Proc:0x401d5dd8

def foo(b0, &b)
p [b0.__id__, b0]
p [b.__id__, b]
end

foo(blk, &blk) # → [537833186, #Proc:0x401d5dd8]
# → [537966706, #Proc:0x401d5dd8]

In drb, The given block cannot be used after a method is returned.
You can avoid a problem if using the Proc object instead of giving block.

— server.rb

class Server

def register(value, action) ## not &action
@observers << [value, action]
end

end

— client.rb

block = Proc.new { |val|
puts val
}
(0…9).each do |i|
server.register(100*i + 1, block) ## not &block
end

Or, use DRb::TimerIdConv.
— client.rb
require ‘drb’
require ‘drb/timeridconv’
DRb.install_id_conv(DRb::TimerIdConv.new)

DRb.start_service()
server = DRbObject.new(nil, ‘druby://localhost:9500’)

block = Proc.new { |val|
puts val
}
(0…9).each do |i|
server.register(100*i + 1, &block)
end

sleep

m_seki@mva.biglobe.ne.jp wrote:

You can avoid a problem if using the Proc object instead of giving block.

Or, use DRb::TimerIdConv.

Thanks, both of those work. I understand the first one, but for the
second one I am motivated to read some source code… :slight_smile: