From nobody at rubyforge.org Sun Sep 30 08:36:56 2007 From: nobody at rubyforge.org (nobody at rubyforge.org) Date: Sun, 30 Sep 2007 08:36:56 -0400 (EDT) Subject: [Archipelago-submits] [325] trunk/archipelago: created a simplified queue class for disco to use. Message-ID: <20070930123657.06FB95240A22@rubyforge.org> Revision: 325 Author: zond Date: 2007-09-30 08:36:56 -0400 (Sun, 30 Sep 2007) Log Message: ----------- created a simplified queue class for disco to use. greatly improved the running of tests. Modified Paths: -------------- trunk/archipelago/lib/archipelago/current.rb trunk/archipelago/lib/archipelago/disco.rb trunk/archipelago/tests/current_test.rb Modified: trunk/archipelago/lib/archipelago/current.rb =================================================================== --- trunk/archipelago/lib/archipelago/current.rb 2007-06-06 22:33:09 UTC (rev 324) +++ trunk/archipelago/lib/archipelago/current.rb 2007-09-30 12:36:56 UTC (rev 325) @@ -222,6 +222,47 @@ attr_reader :mon_entering_queue end + class Queue + def initialize + @ary = [] + @lock = Archipelago::Current::Lock.new + @shift_semaphore = MonitorMixin::ConditionVariable.new(@lock) + @push_semaphore = MonitorMixin::ConditionVariable.new(@lock) + end + def <<(o) + @lock.synchronize do + @ary << o + @push_semaphore.broadcast + end + end + def shift + @lock.synchronize do + @ary.shift + @shift_semaphore.broadcast + end + end + def empty? + @lock.synchronize do + @ary.empty? + end + end + def wait_for_emptiness + @lock.synchronize do + while !@ary.empty? + @shift_semaphore.wait + end + end + end + def wait_for_shift + @lock.synchronize do + @push_semaphore.wait while @ary.empty? + rval = @ary.shift + @shift_semaphore.broadcast + return rval + end + end + end + end - + end Modified: trunk/archipelago/lib/archipelago/disco.rb =================================================================== --- trunk/archipelago/lib/archipelago/disco.rb 2007-06-06 22:33:09 UTC (rev 324) +++ trunk/archipelago/lib/archipelago/disco.rb 2007-09-30 12:36:56 UTC (rev 325) @@ -496,8 +496,8 @@ @local_services = ServiceLocker.new(:jockey => self) @subscribed_services = Set.new - @incoming = Queue.new - @outgoing = Queue.new + @incoming = Archipelago::Current::Queue.new + @outgoing = Archipelago::Current::Queue.new @new_service_semaphore = MonitorMixin::ConditionVariable.new(Archipelago::Current::Lock.new) @service_change_subscribers_by_event_type = {:found => {}, :lost => {}} @@ -603,14 +603,10 @@ @listener.close @unilistener.close - while !@incoming.empty? - sleep 0.1 - end + @incoming.wait_for_emptiness @picker_thread.kill - while !@outgoing.empty? - sleep 0.1 - end + @outgoing.wait_for_emptiness @shouter_thread.kill @sender.close @unisender.close @@ -745,7 +741,7 @@ @shouter_thread = Thread.new do loop do begin - recipient, data = @outgoing.shift + recipient, data = @outgoing.wait_for_shift if recipient address, port = recipient.split(/:/) @unisender.send(Marshal.dump(data), 0, address, port.to_i) @@ -808,7 +804,7 @@ @picker_thread = Thread.new do loop do begin - data = @incoming.pop + data = @incoming.wait_for_shift if Archipelago::Disco::Query === data @local_services.get_services(data).each do |service_id, service_data| if @thrifty_replying Modified: trunk/archipelago/tests/current_test.rb =================================================================== --- trunk/archipelago/tests/current_test.rb 2007-06-06 22:33:09 UTC (rev 324) +++ trunk/archipelago/tests/current_test.rb 2007-09-30 12:36:56 UTC (rev 325) @@ -58,14 +58,50 @@ end end + def test_queue + q = Archipelago::Current::Queue.new + x = false + Thread.new do + x = q.wait_for_shift + end + Thread.pass + assert(!x) + q << true + Thread.pass + sleep 0.1 + assert(x) + + q << true + Thread.new do + q.wait_for_emptiness + x = false + end + Thread.pass + assert(x) + q.shift + Thread.pass + sleep 0.1 + assert(!x) + + y = false + q << "plur" + Thread.new do + q.wait_for_emptiness + y = true + end + q.wait_for_shift + sleep 0.1 + assert(y) + end + def test_threaded_collection a = Array(10) a.extend(Archipelago::Current::ThreadedCollection) - assert_equal(a.select do |e| e == nil end, - a.t_select do |e| e == nil end) - assert_equal(a.reject do |e| e == nil end, - a.t_reject do |e| e == nil end) + assert_equal(a.select do |e| e == nil end.sort, + a.t_select do |e| e == nil end.sort) + assert_equal(a.reject do |e| e == nil end.sort, + a.t_reject do |e| e == nil end.sort) assert_equal(a.collect do |e| e == nil end, a.t_collect do |e| e == nil end) b = [] @@ -75,10 +111,10 @@ a = {1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5} a.extend(Archipelago::Current::ThreadedCollection) - assert_equal(a.select do |k,v| k == nil end, - a.t_select do |k,v| k == nil end) - assert_equal(a.to_a.reject do |k,v| k == nil end, - a.t_reject do |k,v| k == nil end) + assert_equal(a.select do |k,v| k == nil end.sort, + a.t_select do |k,v| k == nil end.sort) + assert_equal(a.to_a.reject do |k,v| k == nil end.sort, + a.t_reject do |k,v| k == nil end.sort) assert_equal(a.collect do |k,v| k == nil end, a.t_collect do |k,c| k == nil end) From nobody at rubyforge.org Sun Sep 30 14:58:52 2007 From: nobody at rubyforge.org (nobody at rubyforge.org) Date: Sun, 30 Sep 2007 14:58:52 -0400 (EDT) Subject: [Archipelago-submits] [326] trunk/archipelago/lib/archipelago: made the notify_successor! more failsafe by updating the captain before asking it for the successor. Message-ID: <20070930185852.A8C575240C28@rubyforge.org> Revision: 326 Author: zond Date: 2007-09-30 14:58:52 -0400 (Sun, 30 Sep 2007) Log Message: ----------- made the notify_successor! more failsafe by updating the captain before asking it for the successor. made monitormixin not try to wake the dead. made the notification subscribers synchronized to avoid nil problems there. Modified Paths: -------------- trunk/archipelago/lib/archipelago/client.rb trunk/archipelago/lib/archipelago/current.rb trunk/archipelago/lib/archipelago/disco.rb trunk/archipelago/lib/archipelago/treasure.rb Modified: trunk/archipelago/lib/archipelago/client.rb =================================================================== --- trunk/archipelago/lib/archipelago/client.rb 2007-09-30 12:36:56 UTC (rev 325) +++ trunk/archipelago/lib/archipelago/client.rb 2007-09-30 18:58:52 UTC (rev 326) @@ -102,6 +102,11 @@ # # Make our @jockey lookup all our services. # + # Arguments: + # :timeout => The timeout for the disco lookup + # :silent => Whether the lookup shall be silent + # :validate => Whether the result of the lookup shall be immediately validated + # def update_services!(options = {}) timeout = options[:timeout] || 0 silent = options[:silent] || false Modified: trunk/archipelago/lib/archipelago/current.rb =================================================================== --- trunk/archipelago/lib/archipelago/current.rb 2007-09-30 12:36:56 UTC (rev 325) +++ trunk/archipelago/lib/archipelago/current.rb 2007-09-30 18:58:52 UTC (rev 326) @@ -29,6 +29,15 @@ end end +module MonitorMixin + def mon_release + @mon_owner = nil + t = @mon_waiting_queue.shift + t = @mon_entering_queue.shift unless t + t.wakeup if t && t.alive? + end +end + module Archipelago module Current Modified: trunk/archipelago/lib/archipelago/disco.rb =================================================================== --- trunk/archipelago/lib/archipelago/disco.rb 2007-09-30 12:36:56 UTC (rev 325) +++ trunk/archipelago/lib/archipelago/disco.rb 2007-09-30 18:58:52 UTC (rev 326) @@ -467,7 +467,6 @@ # The main discovery class used to both publish and lookup services. # class Jockey - # # Will create a Jockey service running on :address and :port or # ADDRESS and PORT if none are given. @@ -501,6 +500,7 @@ @new_service_semaphore = MonitorMixin::ConditionVariable.new(Archipelago::Current::Lock.new) @service_change_subscribers_by_event_type = {:found => {}, :lost => {}} + @service_change_subscribers_by_event_type.extend(Archipelago::Current::Synchronized) @validation_interval = options[:validation_interval] || VALIDATION_INTERVAL @@ -519,14 +519,18 @@ # Recognized +event_types+: :found, :lost # def subscribe(event_type, match, identity, &block) - @service_change_subscribers_by_event_type[event_type][[match, identity]] = block + @service_change_subscribers_by_event_type.synchronize do + @service_change_subscribers_by_event_type[event_type][[match, identity]] = block + end end # # Will stop listening for +event_type+ and +match+ with +identity+. # def unsubscribe(event_type, match, identity) - @service_change_subscribers_by_event_type[event_type].delete([match, identity]) + @service_change_subscribers_by_event_type.synchronize do + @service_change_subscribers_by_event_type[event_type].delete([match, identity]) + end end # @@ -703,17 +707,19 @@ # Will notify all subscribers to +event_type+ looking for +record+. # def notify_subscribers(event_type, record) - @service_change_subscribers_by_event_type[event_type].clone.each do |query_and_identity, proc| - query = query_and_identity.first - Thread.new do - begin - proc.call(record) - rescue Exception => e - @service_change_subscribers_by_event_type[event_type].delete(query_and_identity) - puts e - pp e.backtrace - end - end if record.matches?(query) + @service_change_subscribers_by_event_type.synchronize do + @service_change_subscribers_by_event_type[event_type].clone.each do |query_and_identity, proc| + query = query_and_identity.first + Thread.new do + begin + proc.call(record) + rescue Exception => e + @service_change_subscribers_by_event_type[event_type].delete(query_and_identity) + puts e + pp e.backtrace + end + end if record.matches?(query) + end end end Modified: trunk/archipelago/lib/archipelago/treasure.rb =================================================================== --- trunk/archipelago/lib/archipelago/treasure.rb 2007-09-30 12:36:56 UTC (rev 325) +++ trunk/archipelago/lib/archipelago/treasure.rb 2007-09-30 18:58:52 UTC (rev 326) @@ -696,9 +696,11 @@ def around_publish(&block) notify_successor! @jockey.subscribe(:lost, @captain.service_descriptions[:chests], service_id) do |record| + @captain.chests.delete(record[:service_id]) notify_successor! end @jockey.subscribe(:found, @captain.service_descriptions[:chests], service_id) do |record| + @captain.chests[record[:service_id]] = record notify_successor! end yield