Suppose you find yourself stuck with self-contained Perl CGI scripts (i.e., all the code placed in the CGI script itself). You would like to preload modules to benefit from sharing the code between the children, but you can't or don't want to move most of the stuff into modules. What can you do?

Luckily, you can preload scripts as well. This time the Apache::RegistryLoader module comes to your aid. Apache::RegistryLoader compiles Apache::Registryscripts at server startup.

For example, to preload the script /perl/test.pl, which is in fact the file /home/httpd/perl/test.pl, you would do the following:

use Apache::RegistryLoader ( );
Apache::RegistryLoader->new->handler("/perl/test.pl",
                          "/home/httpd/perl/test.pl");

You should put this code either in <Perl> sections or in a startup script.

But what if you have a bunch of scripts located under the same directory and you don't want to list them one by one? Then the File::Find module will do most of the work for you.

The script shown in Example 10-9 walks the directory tree under which all Apache::Registryscripts are located. For each file with the extension .pl, it calls the Apache::RegistryLoader::handler( ) method to preload the script in the parent server. This happens before Apache pre-forks the child processes.

Example 10-9. startup_preload.pl

use File::Find qw(finddepth);
use Apache::RegistryLoader ( );
{
    my $scripts_root_dir = "/home/httpd/perl/";
    my $rl = Apache::RegistryLoader->new;
    finddepth(
        sub {
            return unless /\.pl$/;
            my $url = $File::Find::name;
            $url =~ s|$scripts_root_dir/?|/|;
            warn "pre-loading $url\n";
            # preload $url
            my $status = $rl->handler($url);
            unless($status =  = 200) {
                warn "pre-load of '$url' failed, status=$status\n";
           }
        },
        $scripts_root_dir
    );
}

Note that we didn't use the second argument to handler( ) here, as we did in the first example. To make the loader smarter about the URI-to-filename translation, you might need to provide a trans( ) function to translate the URI to a filename. URI-to-filename translation normally doesn't happen until an HTTP request is received, so the module is forced to do its own translation. If the filename is omitted and a trans( ) function is not defined, the loader will try to use the URI relative to the ServerRoot.

A simple trans( ) function can be something like this:

sub mytrans {
    my $uri = shift;
    $uri =~ s|^/perl/|/home/httpd/perl/|;
    return $uri;
}

You can easily derive the right translation by looking at the Alias directive. The above mytrans( ) function matches our Alias:

Alias /perl/ /home/httpd/perl/

After defining the URI-to-filename translation function, you should pass it during the creation of the Apache::RegistryLoader object:

my $rl = Apache::RegistryLoader->new(trans => \&mytrans);

We won't show any benchmarks here, since the effect is just like preloading modules. However, we will use this technique later in this chapter, when we will need to have a fair comparison between PerlHandler code and Apache::Registryscripts. This will require both the code and the scripts to be preloaded at server startup.