Feature #8119


more efficient version of Rinda::TupleSpaceProxy.take

Added by vjoel (Joel VanderWerf) over 8 years ago. Updated over 8 years ago.

Target version:



The purpose of Rinda::TupleSpaceProxy is to avoid losing tuples when a client disconnects during a #take call. This is implemented by sending the result value ((twice)): first by pushing it to a client-side array, second by returning the result as a DRb response. If the first fails, then the #take is aborted, so that the tuple is not lost. In case of success, the client only uses the pushed value, not the response value.

This involves a total of ((three)) marshal operations by DRb: the push argument, the push return value (which is an array containing the push argument), and the #take return value. Only the first is necessary.

The following patch adds Rinda::TupleSpaceProxy#take_fast, which avoids the two redundant marshal operations. The unit tests in the ruby source pass when calling this method instead of #take.

The improvement is small when the object is simple. However, for complex objects, eliminating the redundant marshalling reduces network traffic and increases speed by a factor of 2. See the attached bench.rb.

diff --git a/rinda/rinda.rb b/rinda/rinda.rb
index 18e284a..5d280f4 100644
--- a/rinda/rinda.rb
+++ b/rinda/rinda.rb
@@ -206,6 +206,13 @@ module Rinda
# TupleSpaceProxy allows a remote Tuplespace to appear as local.

 class TupleSpaceProxy
  • class Port
  • attr_reader :val
  • def push val
  • @val = val
  • nil # so that val doesn't get marshalled again
  • end
  • end

    # Creates a new TupleSpaceProxy to wrap +ts+.
    @@ -223,6 +230,17 @@ module Rinda

    # Takes +tuple+ from the proxied TupleSpace. See TupleSpace#take.

  • # This is sometimes a bit faster than #take bacause it uses a version

  • # of TupleSpace#move that never marshals the result more than once.

  • def take_fast(tuple, sec=nil, &block)

  •  port =
  •  @ts.move_fast(, tuple, sec, &block)
  •  port.val
  • end

  • ##

  • # Takes +tuple+ from the proxied TupleSpace. See TupleSpace#take.

    def take(tuple, sec=nil, &block)
    port = []
    diff --git a/rinda/tuplespace.rb b/rinda/tuplespace.rb
    index ba494aa..042c605 100644
    --- a/rinda/tuplespace.rb
    +++ b/rinda/tuplespace.rb
    @@ -480,6 +480,43 @@ module Rinda


  • # Moves +tuple+ to +port+, returning nil

  • def move_fast(port, tuple, sec=nil)

  •  template =, tuple, sec)
  •  yield(template) if block_given?
  •  synchronize do
  •    entry = @bag.find(template)
  •    if entry
  •      port.push(entry.value)
  •      @bag.delete(entry)
  •      notify_event('take', entry.value)
  •      return nil
  •    end
  •    raise RequestExpiredError if template.expired?


  •    begin
  •      @take_waiter.push(template)
  •      start_keeper if template.expires
  •      while true
  •        raise RequestCanceledError if template.canceled?
  •        raise RequestExpiredError if template.expired?
  •        entry = @bag.find(template)
  •        if entry
  •          port.push(entry.value)
  •          @bag.delete(entry)
  •          notify_event('take', entry.value)
  •          return nil
  •        end
  •        template.wait
  •      end
  •    ensure
  •      @take_waiter.delete(template)
  •    end
  •  end
  • end

  • ##
    # Moves +tuple+ to +port+.

    def move(port, tuple, sec=nil)



bench.rb (1.14 KB) bench.rb vjoel (Joel VanderWerf), 03/19/2013 06:13 AM
rinda.rb.8119.patch (783 Bytes) rinda.rb.8119.patch Backwards compatible version of original patch drbrain (Eric Hodel), 03/24/2013 11:20 AM

Updated by zzak (Zachary Scott) over 8 years ago

  • Status changed from Open to Assigned
  • Assignee set to seki (Masatoshi Seki)

Updated by drbrain (Eric Hodel) over 8 years ago

  • Priority changed from 3 to Normal

I think #8125 should be applied, then a new patch be generated for this issue.

Updated by drbrain (Eric Hodel) over 8 years ago

With #8125, your benchmark is 40% faster +/- 2% at 95% confidence.

With #8119, your benchmark is ~120% faster, but the tests fail as #take calls #move with a port of nil, so local users of the TupleSpace will experience a behavior change.

I've updated your patch to have the same speed gains while maintaining backwards compatibility. The attached patch, compared to rinda in ruby 2.0.0p57 is 120% faster +/- 2.4% at 95% confidence.

Updated by seki (Masatoshi Seki) over 8 years ago

  • Assignee changed from seki (Masatoshi Seki) to drbrain (Eric Hodel)

Updated by naruse (Yui NARUSE) over 8 years ago

Just FYI, you can use =begin ... =end for commenting out multiline

Actions #6

Updated by drbrain (Eric Hodel) over 8 years ago

  • Status changed from Assigned to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r39923.
Joel, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.

  • lib/rinda/tuplespace.rb: Only return tuple entry once on move, either through port or regular return, not both. This results in a 120% speedup when combined with #8125. Patch by Joel VanderWerf. [ruby-trunk - Feature #8119]

Also available in: Atom PDF