The dRuby Book

7.2 Adding Notifications for New Events

Rinda has some additional features that don’t exist in Linda. notify is a function to send a notification event when a tuple you’re interested in is deleted or added. You can use it to monitor when some tuples are deleted, or you can use it for debugging purposes. There are three different events: write, take, and delete.

write

Sends an event when a tuple is added to the tuplespace via a writeoperation

take

Sends an event when a tuple is deleted from the tuplespace via a take operation

delete

Sends an event when a tuple is deleted from the tuplespace, either when the tuple is deleted on expiration or by a cancel operation

Events are represented as a tuple in combination with the event name and the tuple itself. When the following tuple is written...

  ​ts.write(["Hello", "World"])​

then the following event gets notified:

  ​["write", ["Hello", "World"]]​

When the following tuple is taken...

  ​ts.take(["Hello", nil])​

then the following event gets notified:

  ​["take", ["Hello", "World"]]​

So, how do you write a script to actually receive these events? Use a notify event for this purpose. notify is a method to request event notifications, and you can specify an event name and tuple pattern.

notify(event, pattern, sec=nil)

Requests to receive events in the tuplespace and receives events about tuples that match the pattern you specified. event is the type of event you are interested in. The element of a tuple is the same as normal tuple matching rules, so it notifies all tuples if nil is specified. The notify object returns a NotifyTemplateEntry object. When the time period specified in sec has passed, then the event notification terminates. When the termination happens, it generates a close event as the last event.

NotifyTemplateEntry is an object to retrieve the event you received from notify methods. Here are the major methods NotifyTemplateEntry provides:

each

Calls a block when an event happens. The event tuples are passed to the block as follows:

["write", ["foo", "bar"]]

pop

Takes out one event. Blocks if an event hasn’t arrived yet.

cancel

Cancels event notification requests. Once this is called, new events stop arriving.

If you call cancel after certain events have arrived, you can access them via pop. Once all events have arrived, it sends a close event to indicate the end of events.

The following is the code sequence to handle events:

  # Request an event notification
  ​notifier = ts.notify(nil, ['test', nil])​
  ​​
  # Retrieve events
  ​notifier.each do |event, tuple|​
  ​ ...​
  end

A NotifyTemplateEntry object is generated for each tuple pattern that the notify method requests. This means that multiple streams of event notifications are separated into their own queues and there is no way to guarantee the order among different queues. For example, if there are events for the [’test’, nil] pattern and the [’name’, ’rwiki’,nil] pattern, they belong to different queues, and there are no methods to observe them at the same time. You could combine multiple queues to make them look like one by using a Queue object, but it doesn’t guarantee the order in which they arrive. Here is a class to combine two notify events into one:

multiplenotify.rb
  ​require 'drb/drb'
  ​require 'rinda/rinda'
  ​require 'rinda/tuplespace'
  class MultipleNotify​
  def initialize(ts, event, ary)​
  ​ @queue = Queue.new​
  ​ @entry = []​
  ​ ary.each do |pattern|​
  ​ make_listener(ts, event, pattern)​
  end
  end
  def pop​
  ​ @queue.pop​
  end
  def make_listener(ts, event, pattern)​
  ​ entry = ts.notify(event, pattern)​
  ​ @entry.push(entry)​
  ​ Thread.new do
  ​ entry.each do |ev|​
  ​ @queue.push(ev)​
  end
  end
  end
  end

To use this class, try the following:

  ​mn = MultipleNotify.new(ts, nil, [['test', nil], ['name', 'rwiki', nil]])​
  while true​
  ​ p mn.pop​
  end

The preceding example listens to two events and displays the tuples when notified.