[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]