--n8g4imXOkfNTN/H1 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Fri, Mar 21, 2003 at 02:41:23AM +0900, Chris Pine wrote: > In DRb (or drb, or druby, or... what should I call it?), I'm starting a > server and my Apache/mod_ruby scripts are connecting to it when they need > to. > > My question: If two (or more) people connect to my webserver at roughly the > same time, on two different Apache/mod_ruby processes, are their requests > all sent to the same DRb object, one at a time? They are sent to the same DRb object, and may be processed at the *same* time. DRb starts a new thread for handling each incoming request. You have to serialise the requests yourself, or build your own pool of objects if that's how you want them handled. A sample is attached below, if it's any use. Cheers, Brian. --n8g4imXOkfNTN/H1 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="simplepool.rb" in ynopsis require 'pool' class Foo def doit(x) puts "Doing #{x}, I am #{id}" sleep 2 puts "Done #{x} by #{id}" end end pool ool::SimplePool.new(5) { Foo.new } obj ool::Facade.new(pool, :doit) require 'drb' DRb.start_service('druby://0.0.0.0:9001', obj) escription A SimplePool is a thread-safe pool of objects. You can 'get' an item from the pool, and it is not available again until it has been 'put' back in (or the block associated with 'get' has been run) A Facade is an object which relays method calls to an arbitrary object in the pool. lass Methods --- SimplePool.new( start [max, check, exception] ) { factoryblock } Constructs a pool of objects, calling the factoryblock to create each one. Whenever the pool is empty it may create additional objects, up to the limit of 'max' objects active at any one time. Use max l for unlimited instances. nstance Methods --- SimplePool#get { block } Retrieve an item from the pool, execute the associated block passing the item as a parameter, and then put it back into the pool. When the pool is created, it can be given two extra parameters: 'check' is a method name, and 'exception' is an exception class (defaulting to StandardError) If the execution of the block raises an error, then the object's 'check' method is called. If it returns false/nil, or raises an exception, then the object is considered dead and is not returned to the pool. The original exception is still returned to the caller. Example: class Foo initialize @db BI::connect('dbi:mysql:whatever') end alive? @db.select_one("select 4+5")[0] 9 # connection sanity check end end pool ool::SimplePool(5, 5, :alive?) { Foo.new } You can force objects to be destroyed after every exception by giving 'true' as the method name (or any non-symbol), e.g. pool ool::SimplePool(1, 10, true, Exception) --- SimplePool#get returns obj --- SimplePool#put( obj ) Methods to remove an item from the pool, and return it to the pool. put nil if you want to permanently discard it rather than return it (this allows a subsequent 'get' to create a new instance) lass Methods --- Facade.new( pool, [methodnames] ) Constructs a new facade object for the given pool. If methnames are given, then explicit methods are added to the facade for those methods. This is necessary for DRb where method_missing does not work. nstance Methods --- Facade#<somemethod>( <args> ) Pick an item from the pool and send it the given method/args, after which it is returned to the pool. ίΕ require 'thread' module Pool class SimplePool def initialize(initial max itial, checkmeth l, err andardError, &factory) @max ax @checkmeth heckmeth @err rr @factory actory @poolaccess utex.new @poolnotempty onditionVariable.new @createobj utex.new @pool 1..initial).collect { @factory.call } @numobjs nitial end def get item il @poolaccess.synchronize do if @pool.size > 0 item pool.shift elsif !@max || @numobjs < @max @numobjs + # we will create it outside of this mutex else @poolnotempty.wait(@poolaccess) item pool.shift end end # Don't create object under the poolaccess mutex, as that would block # out other fetch/put operations. But do serialise it under a separate # mutex, as it may not be thread-safe (e.g. if it uses class variables) unless item @createobj.synchronize do item factory.call end end return item unless block_given? begin result ield item rescue @err boom if @checkmeth begin item il unless item.send(@checkmeth) rescue Exception item il end end raise boom ensure put item end result end def put(item) @poolaccess.synchronize do if item @pool.push item @poolnotempty.signal else @numobjs - end end nil end def totalsize @numobjs # approx (changes asynchronously) end def freesize @pool.size # approx (changes asynchronously) end end class Facade def initialize(pool, *methodlist) @pool ool methodlist.each do |m| eval "class <<self; def #{m}(*a,&b); method_missing(:#{m},*a,&b); end; end" end end def method_missing(meth, *argary, &block) @pool.get do |obj| obj.__send__(meth, *argary, &block) end end end end # module Pool --n8g4imXOkfNTN/H1--