DRbIdConv without _id2ref

As mentioned in a previous thread on ruby-talk, we are looking to
remove ObjectSpace_id2ref from JRuby. Matz explained that it was added
to support WeakRef, for which we have our own (Java-based)
implementation. Supporting it on the JVM (or any VM where objects move
in memory) is rather expensive.

The only place in stdlib that uses id2ref is this class in drb/drb.rb:

class DRbIdConv

# Convert an object reference id to an object.
#
# This implementation looks up the reference id in the local object
# space and returns the object it refers to.
def to_obj(ref)
  ObjectSpace._id2ref(ref)
end

# Convert an object into a reference id.
#
# This implementation returns the object's __id__ in the local
# object space.
def to_id(obj)
  obj.nil? ? nil : obj.__id__
end

end

I have come up with a possible replacement for this that uses WeakRef.
I’d like a few more eyes on it. It’s not concurrency-safe, which might
be a good addition. The ‘clean’ method is also not very efficient, but
Ruby’s WeakRef doesn’t have the notion of a reference queue you can
poll cheaply. Adding finalizers would be a heavy-weight way to add
support for a reference queue.

Here’s the code I’ve come up with (plus a “require ‘weakref’” near the
top of drb/drb.rb):

class DRbIdConv
def initialize
@id2ref = {}
end

# Convert an object reference id to an object.
#
# This implementation looks up the reference id in the local object
# space and returns the object it refers to.
def to_obj(ref)
  _get(ref)
end

# Convert an object into a reference id.
#
# This implementation returns the object's __id__ in the local
# object space.
def to_id(obj)
  obj.nil? ? nil : _put(obj)
end

def _clean
  dead = []
  @id2ref.each {|id,weakref| dead << id unless 

weakref.weakref_alive?}
dead.each {|id| @id2ref.delete(id)}
end

def _put(obj)
  _clean
  @id2ref[obj.__id__] = WeakRef.new(obj)
  obj.__id__
end

def _get(id)
  weakref = @id2ref[id]
  if weakref
    result = weakref.__getobj__ rescue nil
    if result
      return result
    else
      @id2ref.delete id
    end
  end
  nil
end
private :_clean, :_put, :_get

end

And here is a test for it:

require ‘test/unit’
require ‘drb’
require ‘java’

class TestWeakDrbIdConv < Test::Unit::TestCase
def test_weak_drb_id_conv
conv = DRb::DRbIdConv.new
obj_ary = []
id_ary = []

# populate
100.times do
  obj = Object.new
  obj_ary << obj
  id_ary << conv.to_id(obj)
end

# confirm they're there
id_ary.each do |id|
  assert conv.to_obj(id)
end

# dereference objects and force GC
obj_ary = nil
2.times {java.lang.System.gc}

# confirm they're gone
id_ary.each do |id|
  assert !conv.to_obj(id)
end

end
end

  • Charlie

Hi,

At Fri, 30 Oct 2009 02:07:04 +0900,
Charles Oliver N. wrote in [ruby-core:26414]:

As mentioned in a previous thread on ruby-talk, we are looking to
remove ObjectSpace_id2ref from JRuby. Matz explained that it was added
to support WeakRef, for which we have our own (Java-based)
implementation. Supporting it on the JVM (or any VM where objects move
in memory) is rather expensive.

I agree. Could you show the link to that thread? I have
stopped ruby-talk for a while.

Hello!

On Thu, Oct 29, 2009 at 7:48 PM, Nobuyoshi N. [email protected]
wrote:

I agree. Â Could you show the link to that thread? Â I have
stopped ruby-talk for a while.

http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-talk/348859?348709-349085

You may also be interested in the JRuby commit
7ed527822b6d2ad3e2b071376a5cd8062392ef08.

  • Charlie