From: "zzak (Zachary Scott)" Date: 2013-03-19T06:23:09+09:00 Subject: [ruby-core:53513] [ruby-trunk - Feature #8119][Assigned] more efficient version of Rinda::TupleSpaceProxy.take Issue #8119 has been updated by zzak (Zachary Scott). Status changed from Open to Assigned Assignee set to seki (Masatoshi Seki) ---------------------------------------- Feature #8119: more efficient version of Rinda::TupleSpaceProxy.take https://bugs.ruby-lang.org/issues/8119#change-37704 Author: vjoel (Joel VanderWerf) Status: Assigned Priority: Low Assignee: seki (Masatoshi Seki) Category: lib Target version: =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 -- http://bugs.ruby-lang.org/