eric and stas already let the cat out of the bag, but i was planning to
give a summary of what's in progress for mod_perl-2.0 anyhow :)
i've included a summary of the pieces i'm currently working on, there's a
great deal left to do, but it's looking good and moving along fast.
i'll be putting these design notes into cvs soon, along with a
bigger-picture plan, which should make it easy to see where folks can help
out if you're interested...

interpreter pool
----------------

this logic is only enabled if Perl is built with -Dusethreads
otherwise, mod_perl will behave just as 1.xx, using a single
interpreter, which is only useful if you're using the prefork mpm.

when the server is started, a Perl interpreter is constructed, parsing 
any code specified in the configuration, just as 1.xx does.  this
interpreter is refered to as the "parent" interpreter.  then, for 
the number of PerlInterpStart configured, a (thread-safe) clone of the
parent interpreter is made (via perl_clone()) and added to a pool of
interpreters.  this clone copies any writeable data (e.g. the symbol
table) and shares the compiled syntax tree.  from my measurements of a 
startup.pl including a few random modules:

 use CGI ();
 use POSIX ();
 use IO ();
 use SelfLoader ();
 use AutoLoader ();
 use B::Deparse ();
 use B::Terse ();
 use B ();
 use B::C ();

the parent adds 6M size to the process, each clone adds less than half 
that size, ~2.3M, thanks to the shared syntax tree.  at request time,
if any Perl*Handlers are configured, an available interpreter is
selected from the pool.  as there is a request_rec per thread, a
pointer is saved in r->per_request_config, which will be used for the
lifetime of that request.
for handlers that are called when threads are not running
(PerlChild{Init,Exit}Handler), the parent interpreter is used.
several configuration parameters control the interpreter pool management:

PerlInterpStart - happens at startup time, the number of intepreters
                  to clone
PerlInterpMax   - if all running interpreters are in use, mod_perl
                  will clone new interpreters to handle the request,
                  up until this number of interpreters is reached.

                  when Max is reached, mod_perl will block
                  (via COND_WAIT()) until one becomes available
                  (signaled via COND_SIGNAL())

PerlInterpMinSpare - the minimum number of available interpreters
                     this parameter will clone interpreters up to Max,
                     before a request comes in

PerlInterpMaxSpare - mod_perl will throttle down the number of
                     interpreters to this number as those in use
                     become available

PerlInterpMaxRequests - the maximum number of requests an interpreter
                        should serve, the interpreter is destroyed
                        when the number is reached and replaced with a
                        fresh one

at the moment, the interpreter pool is just a proof-of-concept
implementation, to test that requests can be handled concurrently.
the link-list implementation will certainly be optimized.  and, some
of the interpreter pool management might be moved into it's own thread.
but the concept of mapping an interpreter clone to a thread will
likely remain.

i'm also interested in shane's "garbage collector", which could also
run in it's own thread, examining the padlists of idle interpreters
and deciding to release and/or report large strings, array/hash sizes,
etc., that Perl is keeping around as an optimization.

glue code and callbacks
-----------------------

the code for hooking mod_perl in the various phases, including
Perl*Handler directives is generated by the ModPerl::Code module,
rather than using the mis-mash of #ifdefs in 1.xx.

when a mod_perl hook is called for a given phase, the glue code has an 
index into the array of handlers, so it knows to return DECLINED right 
away if no handlers are configured, without entering the Perl runtime
as 1.xx did.  the handlers are also now stored in an
ap_array_header_t, which is might lighter and faster than using a Perl 
AV, as 1.xx did.  and again, keeps us out of the Perl runtime until
we're sure we need to be there.

Perl*Handlers are now "compiled", that is, the various forms of:

PerlHandler MyModule (defaults to MyModule::handler or MyModule->handler)
PerlHandler MyModule->handler
PerlHandler $MyObject->handler
PerlHandler 'sub { print "foo\n" }'

are only parsed once, unlike 1.xx which parsed everytime the handler
was used.  there will also be an option to parse the handlers at
startup time.

a "method handler" is now specifed using the `method' sub attribute,
e.g.

 sub handler : method {};

instead of 1.xx's

 sub handler ($$) {}

build system
------------

the biggest mess in 1.xx is mod_perl's Makefile.PL, the majority of
logic has been broken down and moved to the Apache::Build module.
the Makefile.PL will construct an Apache::Build object which will have 
all the info it needs to generate scripts and Makefiles that
apache-2.0 needs.  regardless of what that scheme may be or change to, 
it will be easy to adapt to with build logic/variables/etc divorced
from the actual Makefiles and configure scripts.

the current state of the build system is far from complete, but just
enough to build a libmodperl.a

see 00README_FIRST if you're interested in giving it a whirl.

Reply via email to