ruby-changes:6713
From: seki <ko1@a...>
Date: Sun, 27 Jul 2008 09:04:59 +0900 (JST)
Subject: [ruby-changes:6713] Ruby:r18228 (trunk): merged from 1.8
seki 2008-07-27 09:04:38 +0900 (Sun, 27 Jul 2008) New Revision: 18228 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=18228 Log: merged from 1.8 Modified files: trunk/ChangeLog trunk/lib/rinda/tuplespace.rb trunk/test/rinda/test_rinda.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 18227) +++ ChangeLog (revision 18228) @@ -1,3 +1,9 @@ +Sun Jul 27 09:02:32 2008 Masatoshi SEKI <m_seki@m...> + + * lib/rinda/tuplespace.rb: merged from 1.8. + + * test/rinda/test_rinda.rb: merged from 1.8. + Sat Jul 26 22:45:18 2008 Yuki Sonoda (Yugui) <yugui@y...> * sample/exyacc.rb: fixed NoMethodError(Kernel#sub!). Index: lib/rinda/tuplespace.rb =================================================================== --- lib/rinda/tuplespace.rb (revision 18227) +++ lib/rinda/tuplespace.rb (revision 18228) @@ -2,6 +2,8 @@ require 'thread' require 'drb/drb' require 'rinda/rinda' +require 'enumerator' +require 'forwardable' module Rinda @@ -286,45 +288,70 @@ # of Tuplespace. class TupleBag + class TupleBin + extend Forwardable + def_delegators '@bin', :find_all, :delete_if, :each, :empty? + def initialize + @bin = [] + end + + def add(tuple) + @bin.push(tuple) + end + + def delete(tuple) + idx = @bin.rindex(tuple) + @bin.delete_at(idx) if idx + end + + def find(&blk) + @bin.reverse_each do |x| + return x if yield(x) + end + nil + end + end + def initialize # :nodoc: @hash = {} + @enum = Enumerable::Enumerator.new(self, :each_entry) end ## # +true+ if the TupleBag to see if it has any expired entries. def has_expires? - @hash.each do |k, v| - v.each do |tuple| - return true if tuple.expires - end + @enum.find do |tuple| + tuple.expires end - false end ## - # Add +ary+ to the TupleBag. + # Add +tuple+ to the TupleBag. - def push(ary) - size = ary.size - @hash[size] ||= [] - @hash[size].push(ary) + def push(tuple) + key = bin_key(tuple) + @hash[key] ||= TupleBin.new + @hash[key].add(tuple) end ## - # Removes +ary+ from the TupleBag. + # Removes +tuple+ from the TupleBag. - def delete(ary) - size = ary.size - @hash.fetch(size, []).delete(ary) + def delete(tuple) + key = bin_key(tuple) + bin = @hash[key] + return nil unless bin + bin.delete(tuple) + @hash.delete(key) if bin.empty? + tuple end ## # Finds all live tuples that match +template+. - def find_all(template) - @hash.fetch(template.size, []).find_all do |tuple| + bin_for_find(template).find_all do |tuple| tuple.alive? && template.match(tuple) end end @@ -333,7 +360,7 @@ # Finds a live tuple that matches +template+. def find(template) - @hash.fetch(template.size, []).find do |tuple| + bin_for_find(template).find do |tuple| tuple.alive? && template.match(tuple) end end @@ -343,7 +370,7 @@ # +tuple+ and are alive. def find_all_template(tuple) - @hash.fetch(tuple.size, []).find_all do |template| + @enum.find_all do |template| template.alive? && template.match(tuple) end end @@ -354,20 +381,39 @@ def delete_unless_alive deleted = [] - @hash.keys.each do |size| - ary = [] - @hash[size].each do |tuple| + @hash.each do |key, bin| + bin.delete_if do |tuple| if tuple.alive? - ary.push(tuple) + false else deleted.push(tuple) + true end end - @hash[size] = ary end deleted end + private + def each_entry(&blk) + @hash.each do |k, v| + v.each(&blk) + end + end + + def bin_key(tuple) + head = tuple[0] + if head.class == Symbol + return head + else + false + end + end + + def bin_for_find(template) + key = bin_key(template) + key ? @hash.fetch(key, []) : @enum + end end ## @@ -403,8 +449,7 @@ # Adds +tuple+ def write(tuple, sec=nil) - entry = TupleEntry.new(tuple, sec) - start_keeper + entry = create_entry(tuple, sec) synchronize do if entry.expired? @read_waiter.find_all_template(entry).each do |template| @@ -414,6 +459,7 @@ notify_event('delete', entry.value) else @bag.push(entry) + start_keeper if entry.expires @read_waiter.find_all_template(entry).each do |template| template.read(tuple) end @@ -439,7 +485,6 @@ def move(port, tuple, sec=nil) template = WaitTemplateEntry.new(self, tuple, sec) yield(template) if block_given? - start_keeper synchronize do entry = @bag.find(template) if entry @@ -452,6 +497,7 @@ begin @take_waiter.push(template) + start_keeper if template.expires while true raise RequestCanceledError if template.canceled? raise RequestExpiredError if template.expired? @@ -476,7 +522,6 @@ def read(tuple, sec=nil) template = WaitTemplateEntry.new(self, tuple, sec) yield(template) if block_given? - start_keeper synchronize do entry = @bag.find(template) return entry.value if entry @@ -484,6 +529,7 @@ begin @read_waiter.push(template) + start_keeper if template.expires template.wait raise RequestCanceledError if template.canceled? raise RequestExpiredError if template.expired? @@ -529,6 +575,10 @@ private + def create_entry(tuple, sec) + TupleEntry.new(tuple, sec) + end + ## # Removes dead tuples. @@ -566,9 +616,12 @@ def start_keeper return if @keeper && @keeper.alive? @keeper = Thread.new do - while need_keeper? - keep_clean + while true sleep(@period) + synchronize do + break unless need_keeper? + keep_clean + end end end end Index: test/rinda/test_rinda.rb =================================================================== --- test/rinda/test_rinda.rb (revision 18227) +++ test/rinda/test_rinda.rb (revision 18228) @@ -12,14 +12,14 @@ include Singleton class MyTS < Rinda::TupleSpace - def keeper + def keeper_thread nil end end def initialize @now = 2 - @reso = 0.1 + @reso = 1 @ts = MyTS.new @ts.write([2, :now]) @inf = 2**31 - 1 @@ -33,17 +33,18 @@ n end - def _forward(n=@reso) + def _forward(n=nil) now ,= @ts.take([nil, :now]) @now = now + n n = @reso if n.nil? @ts.write([@now, :now]) end - def forward(n=@reso) + def forward(n) while n > 0 _forward(@reso) n -= @reso + Thread.pass end end @@ -55,21 +56,11 @@ @ts.write([2, :now]) end - def sleep(n=@reso) - while will_deadlock? - n -= @reso - forward - return 0 if n <= 0 - end + def sleep(n=nil) now ,= @ts.read([nil, :now]) @ts.read([(now + n)..@inf, :now]) 0 end - - def will_deadlock? - sz = Thread.current.group.list.find_all {|x| x.status != 'sleep'}.size - sz <= 1 - end end module Time @@ -115,6 +106,14 @@ Time.sleep(n) end end + + def thread_join(th) + while th.alive? + Kernel.sleep(0.1) + sleep(1) + end + th.value + end def test_00_tuple tuple = Rinda::TupleEntry.new([1,2,3]) @@ -240,6 +239,28 @@ end end + def test_ruby_talk_264062 + th = Thread.new { @ts.take([:empty], 1) } + sleep(10) + assert_raises(Rinda::RequestExpiredError) do + thread_join(th) + end + + th = Thread.new { @ts.read([:empty], 1) } + sleep(10) + assert_raises(Rinda::RequestExpiredError) do + thread_join(th) + end + end + + def test_symbol_tuple + @ts.write([:symbol, :symbol]) + @ts.write(['string', :string]) + assert_equal([[:symbol, :symbol]], @ts.read_all([:symbol, nil])) + assert_equal([[:symbol, :symbol]], @ts.read_all([Symbol, nil])) + assert_equal([], @ts.read_all([:nil, nil])) + end + def test_core_01 5.times do |n| @ts.write([:req, 2]) @@ -252,7 +273,7 @@ s = 0 while true begin - tuple = @ts.take([:req, Integer], 0.5) + tuple = @ts.take([:req, Integer], 1) assert_equal(2, tuple[1]) s += tuple[1] rescue Rinda::RequestExpiredError @@ -263,10 +284,9 @@ s end - sleep(20) + assert_equal(10, thread_join(taker)) tuple = @ts.take([:ans, nil]) assert_equal(10, tuple[1]) - assert_equal(10, taker.value) end def test_core_02 @@ -274,7 +294,7 @@ s = 0 while true begin - tuple = @ts.take([:req, Integer], 1.0) + tuple = @ts.take([:req, Integer], 1) assert_equal(2, tuple[1]) s += tuple[1] rescue Rinda::RequestExpiredError @@ -289,10 +309,9 @@ @ts.write([:req, 2]) end - sleep(20) + assert_equal(10, thread_join(taker)) tuple = @ts.take([:ans, nil]) assert_equal(10, tuple[1]) - assert_equal(10, taker.value) assert_equal([], @ts.read_all([nil, nil])) end @@ -349,7 +368,7 @@ s = 0 while true begin - tuple = @ts.take([:req, Integer], 1.0) + tuple = @ts.take([:req, Integer], 1) s += tuple[1] rescue Rinda::RequestExpiredError break @@ -359,26 +378,23 @@ s end - writer = Thread.new do - 5.times do |n| - @ts.write([:req, 2]) - sleep 0.1 - end + 5.times do |n| + @ts.write([:req, 2]) end @ts.take({"message"=>"first", "name"=>"3"}) sleep(4) + assert_equal(10, thread_join(taker)) tuple = @ts.take([:ans, nil]) assert_equal(10, tuple[1]) - assert_equal(10, taker.value) assert_equal([], @ts.read_all([nil, nil])) notify1.cancel sleep(3) # notify2 expired - assert_equal([0, 11], listener1.value) - assert_equal([0, 3], listener2.value) + assert_equal([0, 11], thread_join(listener1)) + assert_equal([0, 3], thread_join(listener2)) ary = [] ary.push(["write", {"message"=>"first", "name"=>"3"}]) @@ -403,23 +419,24 @@ template = nil taker = Thread.new do - @ts.take([:take, nil], 10) do |template| + @ts.take([:take, nil], 10) do |t| + template = t Thread.new do - sleep 0.2 template.cancel end end end - sleep(1) + sleep(2) + + assert_raises(Rinda::RequestCanceledError) do + assert_nil(thread_join(taker)) + end + assert(template.canceled?) @ts.write([:take, 1]) - assert_raises(Rinda::RequestCanceledError) do - assert_nil(taker.value) - end - assert_equal([[:take, 1]], @ts.read_all([nil, nil])) end @@ -431,23 +448,24 @@ template = nil reader = Thread.new do - @ts.read([:take, nil], 10) do |template| + @ts.read([:take, nil], 10) do |t| + template = t Thread.new do - sleep 0.2 template.cancel end end end - sleep(1) + sleep(2) + + assert_raises(Rinda::RequestCanceledError) do + assert_nil(thread_join(reader)) + end + assert(template.canceled?) @ts.write([:take, 1]) - assert_raises(Rinda::RequestCanceledError) do - assert_nil(reader.value) - end - assert_equal([[:take, 1]], @ts.read_all([nil, nil])) end @@ -478,30 +496,22 @@ assert(tuple.expired?) assert(!tuple.alive?) - tuple = Rinda::TupleEntry.new([1,2,3], SimpleRenewer.new(1,2)) + @renewer = SimpleRenewer.new(1,2) + tuple = Rinda::TupleEntry.new([1,2,3], @renewer) assert(!tuple.canceled?) assert(!tuple.expired?) assert(tuple.alive?) - sleep(1.5) + sleep(1) assert(!tuple.canceled?) assert(!tuple.expired?) assert(tuple.alive?) - sleep(1.5) + sleep(2) assert(tuple.expired?) assert(!tuple.alive?) end end class TupleSpaceTest < Test::Unit::TestCase - def test_message - flunk("YARV doesn't support Rinda") - end -end - -end -__END__ - -class TupleSpaceTest < Test::Unit::TestCase include TupleSpaceTestModule def setup @@ -520,13 +530,9 @@ end def test_remote_array_and_hash - ary = [1, 2, 3] - @ts.write(DRbObject.new(ary)) - GC.start + @ts.write(DRbObject.new([1, 2, 3])) assert_equal([1, 2, 3], @ts.take([1, 2, 3], 0)) - hash = {'head' => 1, 'tail' => 2} - @ts.write(DRbObject.new(hash)) - GC.start + @ts.write(DRbObject.new({'head' => 1, 'tail' => 2})) assert_equal({'head' => 1, 'tail' => 2}, @ts.take({'head' => 1, 'tail' => 2}, 0)) end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/