Ezra (and everyone else
Ok, here’s how I am using Linda (cleaned up as best I can to make things
more clear). Basically, put all of these files into one directory to get
started, and then after things are working then you can start moving
different pieces to different servers.
First of all, the background that you should read (or, the background
that I
read that was helpful):
Linda (coordination language) - Wikipedia (good
background on Linda (and why you’d want to use it), which Rinda
implements)
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/15023
http://segment7.net/projects/ruby/drb/rinda/ringserver.html
http://www.ruby-doc.org/stdlib/libdoc/rinda/rdoc/classes/Rinda/TupleSpace.ht
ml
http://www.ntecs.de/blog/Tech/ComputerScience
and, of course, the pickax has a page on Rinda.
And finally, my code (not very well documented, since it assumes that
you’ve
read all of the other URLs I pasted above and that now you just want an
example of how it works all together as well as an example of several
things
that I couldn’t really find easily in the documentation).
(there are 4 files below)
— the port where everyone talks to each other needs to be defined —
In file, rinda_port_uri.rb
RINDA_PORT_URI = “druby://your.hostname.com:12345”
#(you can also use “localhost” if you are all running on the same
machine, but as soon as you put ANY process on a different server, then
they
have to all have the exact same druby:// line (as far as I can tell…
Ruby -rsocket -e ‘p Socket.gethostname’
# this command was helpful for me to find out what ruby thinks my
server was named.
File: rinda_blackboard.rb # this is the main “server” that enables
agents
to get/send messages for things they want someone to do.
require ‘drb/drb’
require ‘drb/acl’
require ‘rinda/tuplespace’
require ‘rinda_port_uri’ # defines the constant used for the Port
acl = ACL.new(%w(deny all # block out other servers from accessing
your
Linda blackboard
allow
10.0.0.7
allow
10.0.0.4
allow
60.59.145.219 #the documentation says that you can put wildcards
‘60.59.145.*’ but that didn’t work for me…)
allow
60.59.145.220
allow
localhost))
DRb.install_acl(acl)
Ruby -rsocket -e ‘p Socket.gethostname’
DRb.start_service(RINDA_PORT_URI, Rinda::TupleSpace.new(10))
#puts DRb.uri
#(0…5).each {|x| # this block will start up 5 agents
puts “Starting agent #{x}”
IO.popen(“ruby rinda_agent.rb”)
#}
puts “blackboard is open on #{RINDA_PORT_URI}”
DRb.thread.join
#puts ‘[return] to exit’
#gets
File: rinda_agent.rb # this is where you do the work… you can have
multiple agents running, and on different servers all pointing to the
same
rinda_blackboard
this is a “example wrapper” thing… If I want an agent to do some
work
for me, then I (personally) want to pass:
- a message,
- a hash containing variables and stuff
- a reference ID that uniquely identifies this message request
- the “return message” I will be looking for that I’d like the agent
to
reply using (so that I know what to look for)
- a return hash containing results from the agent
(that’s just me, what I want…)
require ‘drb/drb’
require ‘rinda/tuplespace’
require ‘rinda_port_uri’ # defines the constant used for the Port
require ‘json/lexer’
require ‘json/objects’
# I like using JSON to tranfer info between agents, but you can use
a simple hash if you wish.
DRb.start_service
ts = Rinda::TupleSpaceProxy.new(DRbObject.new(nil,RINDA_PORT_URI))
class Gen
def worker1(var_in, ref_id, msg_out)
... do something here
an_amazing_result = ...
#return the results of the work
[msg_out,an_amazing_result]
end
end
loop do
puts
puts
puts
puts
puts “waiting…(for PPT stuff)”
# Read the next command
op, var_in, ref_id,msg_out,var_out = ts.take(
[%r{^(msg_1_I_listen_for|msg_2_I_listen_for)$},nil,nil,nil,nil],55) #
time
out after 55 seconds if no activity… good for debugging initially (can
be
omitted in production)
puts "Received! #{op} #{ref_id} #{var_in}"
gen = Gen.new
msg_out,var_out = gen.send(op, var_in, ref_id)
#— DONE --------------------
ts.write([msg_out,ref_id, var_out]) unless (msg_out.nil? or
msg_out.length == 0)
puts “done! #{msg_out} #{ref_id} #{var_out}”
end
file: rinda_watcher.rb
#finally, once you’ve got your blackboard where you can post messages to
get
work done, I wanted to be able to SEE what the heck was being put on
there
so this file is a easy to implement, hacky, fast way of doing
that…
require ‘drb/drb’
require ‘rinda/tuplespace’
require ‘rinda_port_uri’ # defines the constant used for the Port
require ‘pp’
DRb.start_service
puts “trying to connect to #{RINDA_PORT_URI}…”
ts = Rinda::TupleSpaceProxy.new(DRbObject.new(nil,RINDA_PORT_URI))
puts “---------------------Watching”
option = 1
case option
when 1
result = ts.read_all([nil,nil])
pp result unless result.nil?
result = ts.read_all([nil,nil,nil])
pp result unless result.nil?
result = ts.read_all([nil,nil,nil,nil])
pp result unless result.nil?
result = ts.read_all([nil,nil,nil,nil,nil])
pp result unless result.nil?
result = ts.read_all([nil,nil,nil,nil,nil,nil])
pp result unless result.nil?
puts
when 2
result =
ts.read_all([%r{prepare_to_generate_ppt_.*},
nil, #session[:username],
nil, #@current_ppt_name,
nil, #@new_ppt_name,
nil, #@path_to_template,
nil, #json_msg
nil, #user password
])
pp result unless result.nil?
when 3
0.upto(10) {|ignore|
hit = 0
result = ts.read_all([nil,nil])
unless result.nil? or result.size ==0
pp result
ts.take([nil,nil])
hit +=1
end
result = ts.read_all([nil,nil,nil])
unless result.nil? or result.size ==0
pp result
ts.take([nil,nil,nil])
hit +=1
end
result = ts.read_all([nil,nil,nil,nil])
unless result.nil? or result.size ==0
pp result
ts.take([nil,nil,nil,nil])
hit +=1
end
result = ts.read_all([nil,nil,nil,nil,nil])
unless result.nil? or result.size ==0
pp result
ts.take([nil,nil,nil,nil,nil])
hit +=1
end
result =
ts.read_all([nil,nil,nil,nil,nil,nil])
unless result.nil? or result.size ==0
pp result
ts.take([nil,nil,nil,nil,nil,nil])
hit +=1
end
result =
ts.read_all([nil,nil,nil,nil,nil,nil,nil])
unless result.nil? or result.size ==0
pp result
ts.take([nil,nil,nil,nil,nil,nil,nil])
hit +=1
end
if hit > 0
puts '----------------------------'
puts
end
}
End
-Greg
[email protected]
916 792 4538