dRuby連鎖

dRuby遊びのメモ。いや、遊びじゃないんだけど、いずれにしても「もう一度dRubyによる分散オブジェクトプログラミングdRuby本[rakuten]を読んできなさいよ」という話なのだと思う。というわけで、はい、落ち着いたらもう一度読み返します。

require 'etc'
require 'drb/unix'
$name = File.basename($0)
 
class Foo
  include DRbUndumped
  def initialize(name)
    @name = name
    @peer = peer
    @remote = nil
  end
 
  def ping(obj)
    puts "#{@name}: ping: #{obj.inspect}"
    if @peer
      @remote = obj
      @peer.ping(self)
    else
      obj.pong
    end
  end
 
  def pong
    @remote.pong if @remote
  end
 
  attr_accessor :peer
end
 
def ls_l(patt)
  Dir.glob(patt) do |f|
    stat = File.stat(f)
    printf("%04o\t%8s %8s\t%s\n", 
      stat.mode, Etc.getpwuid(stat.uid).name, 
      Etc.getgrgid(stat.gid).name, f)
  end
end
 
proc_a = fork do
  Process.gid = Process.egid = Etc.getgrnam("grp_ab").gid
  Process.uid = Process.euid = Etc.getpwnam("usr_a").uid
 
  obj = Foo.new("a")
  DRb.start_service(
      "drbunix:/tmp/#{$name}_a", obj, {:UNIXFileMode => 0660})
 
  puts
  puts "[process a]"
  ls_l("/tmp/drb*")
 
  begin
    sleep
  rescue SignalException
  ensure
    DRb.stop_service
  end
end
sleep 1
 
proc_b = fork do
  obj = Foo.new("b")
 
  sv_a = DRb.start_service("drbunix:/tmp/#{$name}_b_a", nil, 
      {:UNIXFileMode => 0660, 
    :UNIXFileOwner => "usr_b", :UNIXFileGroup => "grp_ab"})
  sv_c = DRb.start_service("drbunix:/tmp/#{$name}_b_c", obj, 
      {:UNIXFileMode => 0660, 
    :UNIXFileOwner => "usr_b", :UNIXFileGroup => "grp_bc"})
  DRb.primary_server = sv_a
 
  puts
  puts "[process b]"
  ls_l("/tmp/drb*")
 
  Process.gid = Process.egid = Etc.getgrnam("grp_ab").gid
  Process.uid = Process.euid = Etc.getpwnam("usr_b").uid
 
  robj = DRbObject.new_with_uri("drbunix:/tmp/#{$name}_a")
  obj.peer = robj
 
  obj.ping(nil)
 
  begin
    sleep
  rescue SignalException
  ensure
    DRb.stop_service
  end
end
sleep 2
 
proc_c = fork do
  Process.gid = Process.egid = Etc.getgrnam("grp_bc").gid
  Process.uid = Process.euid = Etc.getpwnam("usr_c").uid
 
  robj = DRbObject.new_with_uri("drbunix:/tmp/#{$name}_b_c")
  DRb.start_service("drbunix:/tmp/#{$name}_c", nil, 
      {:UNIXFileMode => 0660})
 
  puts
  puts "[process c]"
  ls_l("/tmp/#{$name}_*")
 
  robj.ping(nil)
end
 
Process.wait(proc_c)
 
 
Process.kill('HUP', proc_a, proc_b)
Process.wait(proc_a)
Process.wait(proc_b)
このスクリプトを以下の準備作業を行った上で実行する。
# groupadd grp_ab
# groupadd grp_bc
# useradd -g grp_ab usr_a
# useradd -g grp_bc usr_c
# useradd -g users -G grp_ab,grp_bc usr_b
すると104行目をきっかけに次のようなエラーになる。
(drbunix:/tmp/drbtest2.rb_b_c) (drbunix:/tmp/drbtest2.rb_a) /usr/lib/ruby/1.8/drb/drb.rb:724:in `open': drbunix:/tmp/drbtest2.rb_b_c - #<Errno::EACCES: Permission denied - /tmp/drbtest2.rb_b_c> (DRb::DRbConnError)
で、こうする。
--- drbtest2.rb    2005-01-24 21:24:40.000000000 +0900
+++ drbtest3.rb 2005-01-24 21:24:55.000000000 +0900
@@ -16,3 +16,3 @@
       @remote = obj
-      @peer.ping(self)
+      Thread.new {@peer.ping(self)}.join
     else

するとエラーが出なくなる。