DRbIdConv without _id2ref

  • Thread starter Charles Oliver Nutter
  • Start date
C

Charles Oliver Nutter

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top