On Wed, 29 Nov 2006, Daniel Berger wrote:

> Tim Pease wrote:
>
> <snip>
>
>>> I don't know much about slave, but one question I have right off the
>>> bat is why you would want one drb server per object, instead of just
>>> one drb server that stored objects in a hash table that you could push
>>> and pop at will.  Maybe I need to go back and see Ara's use case for
>>> this...
>>>
>>
>> Slave forks off a ruby object in a separate process and then uses DRb
>> for communication between the processes.  Each forked process has its
>> own DRb server.
>>
>> TwP
>
> Yes, but why?  I assume the purpose is IPC.  If so, again I ask why you
> would need 1 drb server per object instead of one drb server with lots
> of objects.  If its purspose isn't IPC, what is it?

the purpose is two-fold:

   1) easy ipc
   2) scalling expensive operations across multiple processors easily

you certainly could setup a hashtable of objects.  but a few things to
consider

   1) drop-in scalibility

     object = ExpensiveCalcuation.new

     # 1000 lines of code

   change to

     object = Slave.new{ ExpensiveCalcuation.new }

     # exact same 1000 lines of code

   and, whammo.  you scale to multi-processor machines.


   2) DRbUndumped nuances

     let's say you build a table of objects like this:


       harp:~ > cat a.rb
       require "slave"
       require "yaml"

       slave = Slave.new{ Hash.new }
       table = slave.object

       array = []

       table["array"] = array

       table["array"] << Process.pid

       y "slave.pid" => slave.pid
       y "array" => array
       y "table['array']" => table["array"]


     what will happen?


       harp:~ > ruby a.rb
       slave.pid: 5258
       array: []
       table['array']: []


     yikes!!!  what went wrong?  well, consider:

       array = []                          # array is in parent

       table["array"] = array              # array is marshaled across to child as a copy

       table["array"] << Process.pid       # array is marshaled back across to parent and this __local_copy__ is appended too

       p "array" => array                  # local copy empty

       p "table['hash']" => table["hash"]  # remote copy empty


     here is a fix

       array = []
       array.extend DRbUndumped            # the important part


     now, running again


       harp:~ > ruby a.rb
       slave.pid: 5302

       array:
       - 5301

       table['array']:
       - 5301


     but look carefully  this example is even __more__ fubar: the array lives in
     the parent!  we setup a table and sent only the proxy (DRbUndumped) across
     to the child!  we've completely negated the entire benefit of running
     objects in another process - all we have is a lookup table for objects in
     our own address space.


     ok.  take two.  this time we'll try this:

       harp:~ > cat a.rb
       require "slave"
       require "yaml"

       slave = Slave.new{     # build table in child
         table = Hash.new
         array = []
         table["array"] = array
         table
       }

       table = slave.object

       table["array"] << Process.pid

       y "slave.pid" => slave.pid
       y "table['array']" => table["array"]


     we give a whirl:


       harp:~ > ruby a.rb
       slave.pid: 5358
       table['array']: []


     sigh.  now our table exists only in the child, and so does all it's
     elements.  why doesn't it work.  DRbUndumped is screwing us again.  here's
     why:


       table["array"] << Process.pid         # here the child marshals a copy back to
                                             # parent.  we append to the copy

       y "table['array']" => table["array"]  # and here we get a fresh __empty__ copy


     dang.  we know the fix though, in the child we do:

       array.extend DRbUndumped


     trying again

       harp:~ > ruby a.rb
       slave.pid: 5405
       table['array']: !ruby/object:DRb::DRbObject
         ref: -609755446
         uri: drbunix:///tmp/hash_-609755436_5404_5405_0

     wtf?  well, since our object now lives in the child and we only get a drb
     proxy back some things work, like '<<', but other methods, like 'to_yaml', and
     'inspect' are handled locally by drb.  to get around this 'to_yaml' bug we have
     to force a copy


       harp:~ > cat a.rb
       require "slave"
       require "yaml"

       slave = Slave.new{     # build table in child
         table = Hash.new
         array = []
         array.extend DRbUndumped
         table["array"] = array
         table
       }

       table = slave.object

       table["array"] << Process.pid

       y "slave.pid" => slave.pid
       y "table['array']" => table["array"].map          # force local copy, neither dup nor clone will cut it!



       harp:~ > ruby a.rb
       slave.pid: 5465
       table['array']:
       - 5464


     ah, finally.


so, you see, managing a hierarchy of object across drb is tricky.  not that it
can't be done - i just happen to think that managing __one__ object and it's
DRbUndumped nuances is about all most hackers can manage - thus that's the
default usage.  nothing will stop you from making your server object a factory
or table though - it just gets confusing fast.


kind regards.

-a
-- 
if you want others to be happy, practice compassion.
if you want to be happy, practice compassion.  -- the dalai lama