Project

General

Profile

Actions

Feature #8119

closed

more efficient version of Rinda::TupleSpaceProxy.take

Added by vjoel (Joel VanderWerf) almost 12 years ago. Updated over 11 years ago.

Status:
Closed
Target version:
-
[ruby-core:53512]

Description

=begin

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 = Port.new
    
  •  @ts.move_fast(DRbObject.new(port), 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
    end

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

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

  •  template = WaitTemplateEntry.new(self, 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)

=end


Files

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 (zzak _) almost 12 years ago

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

Updated by drbrain (Eric Hodel) almost 12 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 11 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 11 years ago

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

Updated by naruse (Yui NARUSE) over 11 years ago

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

Actions #6

Updated by drbrain (Eric Hodel) over 11 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]
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0