Blame lib/prefork.pm

Packit 549706
package prefork;
Packit 549706
Packit 549706
=pod
Packit 549706
Packit 549706
=head1 NAME
Packit 549706
Packit 549706
prefork - Optimized module loading for forking or non-forking processes
Packit 549706
Packit 549706
=head1 SYNOPSIS
Packit 549706
Packit 549706
In a module that normally delays module loading with require
Packit 549706
Packit 549706
  # Module Foo::Bar only uses This::That 25% of the time.
Packit 549706
  # We want to preload in in forking scenarios (like mod_perl), but
Packit 549706
  # we want to delay loading in non-forking scenarios (like CGI)
Packit 549706
  use prefork 'This::That';
Packit 549706
  
Packit 549706
  sub do_something {
Packit 549706
      my $arg = shift;
Packit 549706
  
Packit 549706
      # Load the module at run-time as normal
Packit 549706
      if ( $special_case ) {
Packit 549706
          require This::That;
Packit 549706
          This::That::blah(@_);
Packit 549706
      }
Packit 549706
  }
Packit 549706
  
Packit 549706
  # Register a module to be loaded before forking directly
Packit 549706
  prefork::prefork('Module::Name');
Packit 549706
Packit 549706
In a script or module that is going to be forking.
Packit 549706
Packit 549706
  package Module::Forker;
Packit 549706
  
Packit 549706
  # Enable forking mode
Packit 549706
  use prefork ':enable';
Packit 549706
  
Packit 549706
  # Or call it directly
Packit 549706
  prefork::enable();
Packit 549706
Packit 549706
In a third-party run-time loader
Packit 549706
Packit 549706
  package Runtime::Loader;
Packit 549706
  
Packit 549706
  use prefork ();
Packit 549706
  prefork::notify( \&load_everything );
Packit 549706
  
Packit 549706
  ...
Packit 549706
  
Packit 549706
  sub load_everything { ... }
Packit 549706
  
Packit 549706
  1;
Packit 549706
  
Packit 549706
=head1 INTRODUCTION
Packit 549706
Packit 549706
The task of optimizing module loading in Perl tends to move in two different
Packit 549706
directions, depending on the context.
Packit 549706
Packit 549706
In a procedural context, such as scripts and CGI-type situations, you can
Packit 549706
improve the load times and memory usage by loading a module at run-time,
Packit 549706
only once you are sure you will need it.
Packit 549706
Packit 549706
In the other common load profile for perl applications, the application
Packit 549706
will start up and then fork off various worker processes. To take full
Packit 549706
advantage of memory copy-on-write features, the application should load
Packit 549706
as many modules as possible before forking to prevent them consuming memory
Packit 549706
in multiple worker processes.
Packit 549706
Packit 549706
Unfortunately, the strategies used to optimise for these two load profiles
Packit 549706
are diametrically opposed. What improves a situation for one tends to
Packit 549706
make life worse for the other.
Packit 549706
Packit 549706
=head1 DESCRIPTION
Packit 549706
Packit 549706
The C<prefork> pragma is intended to allow module writers to optimise
Packit 549706
module loading for B<both> scenarios with as little additional code as
Packit 549706
possible.
Packit 549706
Packit 549706
prefork.pm is intended to serve as a central and optional marshalling
Packit 549706
point for state detection (are we running in compile-time or run-time
Packit 549706
mode) and to act as a relatively light-weight module loader.
Packit 549706
Packit 549706
=head2 Loaders and Forkers
Packit 549706
Packit 549706
C<prefork> is intended to be used in two different ways.
Packit 549706
Packit 549706
The first is by a module that wants to indicate that another module should
Packit 549706
be loaded before forking. This is known as a "Loader".
Packit 549706
Packit 549706
The other is a script or module that will be initiating the forking. It
Packit 549706
will tell prefork.pm that it is either going to fork, or is about to fork,
Packit 549706
or for some other reason all modules previously mentioned by the Loaders
Packit 549706
should be loaded immediately.
Packit 549706
Packit 549706
=head2 Usage as a Pragma
Packit 549706
Packit 549706
A Loader can register a module to be loaded using the following
Packit 549706
Packit 549706
  use prefork 'My::Module';
Packit 549706
Packit 549706
The same thing can be done in such a way as to not require prefork
Packit 549706
being installed, but taking advantage of it if it is.
Packit 549706
Packit 549706
  eval "use prefork 'My::Module';";
Packit 549706
Packit 549706
A Forker can indicate that it will be forking with the following
Packit 549706
Packit 549706
  use prefork ':enable';
Packit 549706
Packit 549706
In any use of C<prefork> as a pragma, you can only pass a single value
Packit 549706
as argument. Any additional arguments will be ignored. (This may throw
Packit 549706
an error in future versions).
Packit 549706
Packit 549706
=head2 Compatbility with mod_perl and others
Packit 549706
Packit 549706
Part of the design of C<prefork>, and its minimalistic nature, is that it
Packit 549706
is intended to work easily with existing modules, needing only small
Packit 549706
changes.
Packit 549706
Packit 549706
For example, C<prefork> itself will detect the C<$ENV{MOD_PERL}>
Packit 549706
environment variable and automatically start in forking mode.
Packit 549706
Packit 549706
prefork has support for integrating with third-party modules, such as
Packit 549706
L<Class::Autouse>. The C<notify> function allows these run-time loaders
Packit 549706
to register callbacks, to be called once prefork enters forking mode.
Packit 549706
Packit 549706
The synopsis entry above describes adding support for prefork.pm as a
Packit 549706
dependency. To allow your third-party module loader without a dependency
Packit 549706
and only if it is installed use the following:
Packit 549706
Packit 549706
  eval { require prefork; }
Packit 549706
  prefork::notify( \&function ) unless $@;
Packit 549706
Packit 549706
=head2 Using prefork.pm
Packit 549706
Packit 549706
From the Loader side, it is fairly simple. prefork becomes a dependency
Packit 549706
for your module, and you use it as a pragma as documented above.
Packit 549706
Packit 549706
For the Forker, you have two options. Use as a dependency or optional use.
Packit 549706
Packit 549706
In the dependency case, you add prefork as a dependency and use it as a
Packit 549706
pragma with the ':enable' option.
Packit 549706
Packit 549706
To add only optional support for prefork, without requiring it to be
Packit 549706
installed, you should wait until the moment just before you fork and then
Packit 549706
call C<prefork::enable> directly ONLY if it is loaded.
Packit 549706
Packit 549706
  # Load modules if any use the prefork pragma.
Packit 549706
  prefork::enable() if $INC{prefork.pm};
Packit 549706
Packit 549706
This will cause the modules to be loaded ONLY if there are any modules that
Packit 549706
need to be loaded. The main advantage of the dependency version is that you
Packit 549706
only need to enable the module once, and not before each fork.
Packit 549706
Packit 549706
If you wish to have your own module leverage off the forking-detection that
Packit 549706
prefork provides, you can also do the following.
Packit 549706
Packit 549706
  use prefork;
Packit 549706
  if ( $prefork::FORKING ) {
Packit 549706
      # Complete some preparation task
Packit 549706
  }
Packit 549706
Packit 549706
=head2 Modules that are prefork-aware
Packit 549706
Packit 549706
=over 4
Packit 549706
Packit 549706
=item mod_perl/mod_perl2
Packit 549706
Packit 549706
=item Class::Autouse
Packit 549706
Packit 549706
=back
Packit 549706
Packit 549706
=head1 FUNCTIONS
Packit 549706
Packit 549706
=cut
Packit 549706
Packit 549706
use 5.005;
Packit 549706
use strict;
Packit 549706
use Carp              ();
Packit 549706
use List::Util   0.18 ();
Packit 549706
use Scalar::Util 0.18 ();
Packit 549706
Packit 549706
use vars qw{$VERSION $FORKING %MODULES @NOTIFY};
Packit 549706
BEGIN {
Packit 549706
	$VERSION = '1.04';
Packit 549706
Packit 549706
	# The main state variable for this package.
Packit 549706
	# Are we in preforking mode.
Packit 549706
	$FORKING = '';
Packit 549706
Packit 549706
	# The queue of modules to load
Packit 549706
	%MODULES = ();
Packit 549706
Packit 549706
	# The queue of notification callbacks
Packit 549706
	@NOTIFY = (
Packit 549706
		sub {
Packit 549706
			# Do a hash copy of Config to get everything
Packit 549706
			# inside of it preloaded.
Packit 549706
			require Config;
Packit 549706
			eval {
Packit 549706
				# Sometimes there is no Config_heavy.pl
Packit 549706
				require 'Config_heavy.pl';
Packit 549706
			};
Packit 549706
			my $copy = { %Config::Config };
Packit 549706
			return 1;
Packit 549706
		},
Packit 549706
	);
Packit 549706
Packit 549706
	# Look for situations that need us to start in forking mode
Packit 549706
	$FORKING = 1 if $ENV{MOD_PERL};
Packit 549706
}
Packit 549706
Packit 549706
sub import {
Packit 549706
	return 1 unless $_[1];
Packit 549706
	($_[1] eq ':enable') ? enable() : prefork($_[1]);
Packit 549706
}
Packit 549706
Packit 549706
=pod
Packit 549706
Packit 549706
=head2 prefork $module
Packit 549706
Packit 549706
The 'prefork' function indicates that a module should be loaded before
Packit 549706
the process will fork. If already in forking mode the module will be
Packit 549706
loaded immediately.
Packit 549706
Packit 549706
Otherwise it will be added to a queue to be loaded later if it recieves
Packit 549706
instructions that it is going to be forking.
Packit 549706
Packit 549706
Returns true on success, or dies on error.
Packit 549706
Packit 549706
=cut
Packit 549706
Packit 549706
sub prefork ($) {
Packit 549706
	# Just hand straight to require if enabled
Packit 549706
	my $module = defined $_[0] ? "$_[0]" : ''
Packit 549706
		or Carp::croak('You did not pass a module name to prefork');
Packit 549706
	$module =~ /^[^\W\d]\w*(?:(?:\'|::)[^\W\d]\w*)*$/
Packit 549706
		or Carp::croak("'$module' is not a module name");
Packit 549706
	my $file = join( '/', split /(?:\'|::)/, $module ) . '.pm';
Packit 549706
Packit 549706
	# Is it already loaded or queued
Packit 549706
	return 1 if $INC{$file};
Packit 549706
	return 1 if $MODULES{$module};
Packit 549706
Packit 549706
	# Load now if enabled, or add to the module list
Packit 549706
	return require $file if $FORKING;
Packit 549706
	$MODULES{$module} = $file;
Packit 549706
Packit 549706
	1;
Packit 549706
}
Packit 549706
Packit 549706
=pod
Packit 549706
Packit 549706
=head2 enable
Packit 549706
Packit 549706
The C<enable> function indicates to the prefork module that the process is
Packit 549706
going to fork, possibly immediately.
Packit 549706
Packit 549706
When called, prefork.pm will immediately load all outstanding modules, and
Packit 549706
will set a flag so that any further 'prefork' calls will load the module
Packit 549706
at that time.
Packit 549706
Packit 549706
Returns true, dieing as normal is there is a problem loading a module.
Packit 549706
Packit 549706
=cut
Packit 549706
Packit 549706
sub enable () {
Packit 549706
	# Turn on the PREFORK flag, so any additional
Packit 549706
	# 'use prefork ...' calls made during loading
Packit 549706
	# will load immediately.
Packit 549706
	return 1 if $FORKING;
Packit 549706
	$FORKING = 1;
Packit 549706
Packit 549706
	# Load all of the modules not yet loaded
Packit 549706
	foreach my $module ( sort keys %MODULES ) {
Packit 549706
		my $file = $MODULES{$module};
Packit 549706
Packit 549706
		# Has it been loaded since we were told about it
Packit 549706
		next if $INC{$file};
Packit 549706
Packit 549706
		# Load the module.
Packit 549706
		require $file;
Packit 549706
	}
Packit 549706
Packit 549706
	# Clear the modules list
Packit 549706
	%MODULES = ();
Packit 549706
Packit 549706
	# Execute the third-party callbacks
Packit 549706
	while ( my $callback = shift @NOTIFY ) {
Packit 549706
		$callback->();
Packit 549706
	}
Packit 549706
Packit 549706
	1;
Packit 549706
}
Packit 549706
Packit 549706
=pod
Packit 549706
Packit 549706
=head2 notify &function
Packit 549706
Packit 549706
The C<notify> function is used to integrate support for modules other than
Packit 549706
prefork.pm itself.
Packit 549706
Packit 549706
A module loader calls the notify function, passing it a reference to a
Packit 549706
C reference (either anon or a function reference). C<prefork> will
Packit 549706
store this CODE reference, and execute it immediately as soon as it knows
Packit 549706
it is in forking-mode, but after it loads its own modules.
Packit 549706
Packit 549706
Callbacks are called in the order they are registered.
Packit 549706
Packit 549706
Normally, this will happen as soon as the C<enable> function is called.
Packit 549706
Packit 549706
However, you should be aware that if prefork is B<already> in preforking
Packit 549706
mode at the time that the notify function is called, prefork.pm will
Packit 549706
execute the function immediately.
Packit 549706
Packit 549706
This means that any third party module loader should be fully loaded and
Packit 549706
initialised B<before> the callback is provided to C<notify>.
Packit 549706
Packit 549706
Returns true if the function is stored, or dies if not passed a C
Packit 549706
reference, or the callback is already set in the notify queue.
Packit 549706
Packit 549706
=cut
Packit 549706
Packit 549706
sub notify ($) {
Packit 549706
	# Get the CODE ref callback param
Packit 549706
	my $function = shift;
Packit 549706
	my $reftype  = Scalar::Util::reftype($function);
Packit 549706
	unless ( $reftype and $reftype eq 'CODE' ) {
Packit 549706
		Carp::croak("prefork::notify was not passed a CODE reference");
Packit 549706
	}
Packit 549706
Packit 549706
	# Call it immediately is already in forking mode
Packit 549706
	if ( $FORKING ) {
Packit 549706
		$function->();
Packit 549706
		return 1;
Packit 549706
	}
Packit 549706
Packit 549706
	# Is it already defined?
Packit 549706
	if ( List::Util::first { Scalar::Util::refaddr($function) == Scalar::Util::refaddr($_) } @NOTIFY ) {
Packit 549706
		Carp::croak("Callback function already registered");
Packit 549706
	}
Packit 549706
Packit 549706
	# Add to the queue
Packit 549706
	push @NOTIFY, $function;
Packit 549706
Packit 549706
	1;
Packit 549706
}
Packit 549706
Packit 549706
Packit 549706
Packit 549706
Packit 549706
Packit 549706
#####################################################################
Packit 549706
# Built-in Notifications
Packit 549706
Packit 549706
# Compile CGI functions automatically
Packit 549706
prefork::notify( sub {
Packit 549706
	CGI->compile() if $INC{'CGI.pm'};
Packit 549706
} );
Packit 549706
Packit 549706
1;
Packit 549706
Packit 549706
=pod
Packit 549706
Packit 549706
=head1 TO DO
Packit 549706
Packit 549706
- Add checks for more pre-forking situations
Packit 549706
Packit 549706
=head1 SUPPORT
Packit 549706
Packit 549706
Bugs should be always submitted via the CPAN bug tracker, located at
Packit 549706
Packit 549706
L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=prefork>
Packit 549706
Packit 549706
For other issues, or commercial enhancement or support, contact the author.
Packit 549706
Packit 549706
=head1 AUTHOR
Packit 549706
Packit 549706
Adam Kennedy <adamk@cpan.org>
Packit 549706
Packit 549706
=head1 COPYRIGHT
Packit 549706
Packit 549706
Thank you to Phase N Australia (L<http://phase-n.com/>) for
Packit 549706
permitting the open sourcing and release of this distribution.
Packit 549706
Packit 549706
Copyright 2004 - 2009 Adam Kennedy.
Packit 549706
Packit 549706
This program is free software; you can redistribute
Packit 549706
it and/or modify it under the same terms as Perl itself.
Packit 549706
Packit 549706
The full text of the license can be found in the
Packit 549706
LICENSE file included with this module.
Packit 549706
Packit 549706
=cut