From def653cd80e55d9e760e3803f815cc9dcdc1131e Mon Sep 17 00:00:00 2001 From: seki Date: Mon, 24 Oct 2005 15:38:47 +0000 Subject: RDoc documentation from Eric Hodel added. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9459 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/rinda/tuplespace.rb | 249 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 199 insertions(+), 50 deletions(-) (limited to 'lib/rinda/tuplespace.rb') diff --git a/lib/rinda/tuplespace.rb b/lib/rinda/tuplespace.rb index 67917f99ea..73e79bb401 100644 --- a/lib/rinda/tuplespace.rb +++ b/lib/rinda/tuplespace.rb @@ -1,47 +1,66 @@ -# -# = tuplespace: ??? -# -# Overview of rinda/tuplespace.rb -# -# Example(s) -# - require 'monitor' require 'thread' require 'drb/drb' require 'rinda/rinda' module Rinda - # + + ## # A TupleEntry is a Tuple (i.e. a possible entry in some Tuplespace) # together with expiry and cancellation data. - # + class TupleEntry + include DRbUndumped + attr_accessor :expires + + ## + # Creates a TupleEntry based on +ary+ with an optional renewer or expiry + # time +sec+. + # + # A renewer must implement the +renew+ method which returns a Numeric, + # nil, or true to indicate when the tuple has expired. + def initialize(ary, sec=nil) @cancel = false + @expires = nil @tuple = make_tuple(ary) @renewer = nil renew(sec) end - attr_accessor :expires + + ## + # Marks this TupleEntry as canceled. def cancel @cancel = true end + ## + # A TupleEntry is dead when it is canceled or expired. + def alive? !canceled? && !expired? end + ## # Return the object which makes up the tuple itself: the Array # or Hash. + def value; @tuple.value; end + ## + # Returns the canceled status. + def canceled?; @cancel; end + ## # Has this tuple expired? (true/false). + # + # A tuple has expired when its expiry timer based on the +sec+ argument to + # #initialize runs out. + def expired? return true unless @expires return false if @expires > Time.now @@ -51,8 +70,8 @@ module Rinda return @expires < Time.now end - # Reset the expiry data according to the supplied argument. If - # the argument is: + ## + # Reset the expiry time according to +sec_or_renewer+. # # +nil+:: it is set to expire in the far future. # +false+:: it has expired. @@ -60,19 +79,19 @@ module Rinda # # Otherwise the argument refers to some kind of renewer object # which will reset its expiry time. + def renew(sec_or_renewer) sec, @renewer = get_renewer(sec_or_renewer) @expires = make_expires(sec) end - # Create an expiry time. Called with: - # - # +true+:: the expiry time is the start of 1970 (i.e. expired). - # +nil+:: it is Tue Jan 19 03:14:07 GMT Standard Time 2038 (i.e. when - # UNIX clocks will die) - # - # otherwise it is +sec+ seconds into the - # future. + ## + # Returns an expiry Time based on +sec+ which can be one of: + # Numeric:: +sec+ seconds into the future + # +true+:: the expiry time is the start of 1970 (i.e. expired) + # +nil+:: it is Tue Jan 19 03:14:07 GMT Standard Time 2038 (i.e. when + # UNIX clocks will die) + def make_expires(sec=nil) case sec when Numeric @@ -84,29 +103,43 @@ module Rinda end end - # Accessor method for the tuple. + ## + # Retrieves +key+ from the tuple. + def [](key) @tuple[key] end + ## + # Fetches +key+ from the tuple. + def fetch(key) @tuple.fetch(key) end + ## # The size of the tuple. + def size @tuple.size end - # Create a new tuple from the supplied object (array-like). + ## + # Creates a Rinda::Tuple for +ary+. + def make_tuple(ary) Rinda::Tuple.new(ary) end private - # Given +true+, +nil+, or +Numeric+, returns that (suitable input to - # make_expires) and +nil+ (no actual +renewer+), else it return the - # time data from the supplied +renewer+. + + ## + # Returns a valid argument to make_expires and the renewer or nil. + # + # Given +true+, +nil+, or Numeric, returns that value and +nil+ (no actual + # renewer). Otherwise it returns an expiry value from calling +it.renew+ + # and the renewer. + def get_renewer(it) case it when Numeric, true, nil @@ -119,35 +152,42 @@ module Rinda end end end + end - # - # The same as a TupleEntry but with methods to do matching. - # + ## + # A TemplateEntry is a Template together with expiry and cancellation data. + class TemplateEntry < TupleEntry + ## + # Matches this TemplateEntry against +tuple+. See Template#match for + # details on how a Template matches a Tuple. + def match(tuple) @tuple.match(tuple) end alias === match - # Create a new Template from the supplied object. - def make_tuple(ary) + def make_tuple(ary) # :nodoc: Rinda::Template.new(ary) end + end - # + ## # Documentation? - # + class WaitTemplateEntry < TemplateEntry + + attr_reader :found + def initialize(place, ary, expires=nil) super(ary, expires) @place = place @cond = place.new_cond @found = nil end - attr_reader :found def cancel super @@ -168,12 +208,39 @@ module Rinda @cond.signal end end + end + ## + # A NotifyTemplateEntry is returned by TupleSpace#notify and is notified of + # TupleSpace changes. You may receive either your subscribed event or the + # 'close' event when iterating over notifications. # - # Documentation? + # See TupleSpace#notify_event for valid notification types. + # + # == Example + # + # ts = Rinda::TupleSpace.new + # observer = ts.notify 'write', [nil] + # + # Thread.start do + # observer.each { |t| p t } + # end + # + # 3.times { |i| ts.write [i] } # + # Outputs: + # + # ['write', [0]] + # ['write', [1]] + # ['write', [2]] + class NotifyTemplateEntry < TemplateEntry + + ## + # Creates a new NotifyTemplateEntry that watches +place+ for +event+s that + # match +tuple+. + def initialize(place, event, tuple, expires=nil) ary = [event, Rinda::Template.new(tuple)] super(ary, expires) @@ -181,10 +248,17 @@ module Rinda @done = false end + ## + # Called by TupleSpace to notify this NotifyTemplateEntry of a new event. + def notify(ev) @queue.push(ev) end + ## + # Retrieves a notification. Raises RequestExpiredError when this + # NotifyTemplateEntry expires. + def pop raise RequestExpiredError if @done it = @queue.pop @@ -192,7 +266,10 @@ module Rinda return it end - def each + ## + # Yields event/tuple pairs until this NotifyTemplateEntry expires. + + def each # :yields: event, tuple while !@done it = pop yield(it) @@ -201,17 +278,22 @@ module Rinda ensure cancel end + end - # + ## # TupleBag is an unordered collection of tuples. It is the basis # of Tuplespace. - # + class TupleBag - def initialize + + def initialize # :nodoc: @hash = {} 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| @@ -221,43 +303,55 @@ module Rinda false end - # Add the object to the TupleBag. + ## + # Add +ary+ to the TupleBag. + def push(ary) size = ary.size @hash[size] ||= [] @hash[size].push(ary) end - # Remove the object from the TupleBag. + ## + # Removes +ary+ from the TupleBag. + def delete(ary) size = ary.size @hash.fetch(size, []).delete(ary) end - # Finds all tuples that match the template and are alive. + ## + # Finds all live tuples that match +template+. + def find_all(template) @hash.fetch(template.size, []).find_all do |tuple| tuple.alive? && template.match(tuple) end end - # Finds a template that matches and is alive. + ## + # Finds a live tuple that matches +template+. + def find(template) @hash.fetch(template.size, []).find do |tuple| tuple.alive? && template.match(tuple) end end - # Finds all tuples in the TupleBag which when treated as - # templates, match the supplied tuple and are alive. + ## + # Finds all tuples in the TupleBag which when treated as templates, match + # +tuple+ and are alive. + def find_all_template(tuple) @hash.fetch(tuple.size, []).find_all do |template| template.alive? && template.match(tuple) end end - # Delete tuples which are not alive from the TupleBag. Returns - # the list of tuples so deleted. + ## + # Delete tuples which dead tuples from the TupleBag, returning the deleted + # tuples. + def delete_unless_alive deleted = [] @hash.keys.each do |size| @@ -273,15 +367,28 @@ module Rinda end deleted end + end - # + ## # The Tuplespace manages access to the tuples it contains, # ensuring mutual exclusion requirements are met. # + # The +sec+ option for the write, take, move, read and notify methods may + # either be a number of seconds or a Renewer object. + class TupleSpace + include DRbUndumped include MonitorMixin + + ## + # Creates a new TupleSpace. +period+ is used to control how often to look + # for dead tuples after modifications to the TupleSpace. + # + # If no dead tuples are found +period+ seconds after the last + # modification, the TupleSpace will stop looking for dead tuples. + def initialize(period=60) super() @bag = TupleBag.new @@ -292,7 +399,9 @@ module Rinda @keeper = nil end - # Put a tuple into the tuplespace. + ## + # Adds +tuple+ + def write(tuple, sec=nil) entry = TupleEntry.new(tuple, sec) start_keeper @@ -317,11 +426,16 @@ module Rinda entry end - # Remove an entry from the Tuplespace. + ## + # Removes +tuple+ + def take(tuple, sec=nil, &block) move(nil, tuple, sec, &block) end + ## + # Moves +tuple+ to +port+. + def move(port, tuple, sec=nil) template = WaitTemplateEntry.new(self, tuple, sec) yield(template) if block_given? @@ -356,6 +470,9 @@ module Rinda end end + ## + # Reads +tuple+, but does not remove it. + def read(tuple, sec=nil) template = WaitTemplateEntry.new(self, tuple, sec) yield(template) if block_given? @@ -377,6 +494,9 @@ module Rinda end end + ## + # Returns all tuples matching +tuple+. Does not remove the found tuples. + def read_all(tuple) template = WaitTemplateEntry.new(self, tuple, nil) synchronize do @@ -387,6 +507,18 @@ module Rinda end end + ## + # Registers for notifications of +event+. Returns a NotifyTemplateEntry. + # See NotifyTemplateEntry for examples of how to listen for notifications. + # + # +event+ can be: + # 'write':: A tuple was added + # 'take':: A tuple was taken or moved + # 'delete':: A tuple was lost after being overwritten or expiring + # + # The TupleSpace will also notify you of the 'close' event when the + # NotifyTemplateEntry has expired. + def notify(event, tuple, sec=nil) template = NotifyTemplateEntry.new(self, event, tuple, sec) synchronize do @@ -396,6 +528,10 @@ module Rinda end private + + ## + # Removes dead tuples. + def keep_clean synchronize do @read_waiter.delete_unless_alive.each do |e| @@ -413,6 +549,10 @@ module Rinda end end + ## + # Notifies all registered listeners for +event+ of a status change of + # +tuple+. + def notify_event(event, tuple) ev = [event, tuple] @notify_waiter.find_all_template(ev).each do |template| @@ -420,6 +560,9 @@ module Rinda end end + ## + # Creates a thread that scans the tuplespace for expired tuples. + def start_keeper return if @keeper && @keeper.alive? @keeper = Thread.new do @@ -430,11 +573,17 @@ module Rinda end end + ## + # Checks the tuplespace to see if it needs cleaning. + def need_keeper? return true if @bag.has_expires? return true if @read_waiter.has_expires? return true if @take_waiter.has_expires? return true if @notify_waiter.has_expires? end + end + end + -- cgit v1.2.3