spacer

Webref WebRef   Sitemap · Experts · Tools · Services · Newsletters · About i.com

home / programming / perl / mod_perl / chap6 / 1 To page 1To page 2To page 3To page 4current pageTo page 6To page 7
[previous] [next]

Practical mod_perl: Chapter 6: Coding with mod_perl in Mind

Sr. Web Developer
mediabistro.com
US-NY-New York

Justtechjobs.com Post A Job | Post A Resume
Developer News
Microsoft Shows Off Silverlight 4, IE9 Plans
Metasploit Expands Vulnerability Test Framework
HyperCard Reborn?


The Second Mystery--Inconsistent Growth over Reloads

Let's return to our original example and proceed with the second mystery we noticed. Why have we seen inconsistent results over numerous reloads?

What happens is that each time the parent process gets a request for the page, it hands the request over to a child process. Each child process runs its own copy of the script. This means that each child process has its own copy of $counter, which will increment independently of all the others. So not only does the value of each $counter increase independently with each invocation, but because different children handle the requests at different times, the increment seems to grow inconsistently. For example, if there are 10 httpd children, the first 10 reloads might be correct (if each request went to a different child). But once reloads start reinvoking the script from the child processes, strange results will appear.

Moreover, requests can appear at random since child processes don't always run the same requests. At any given moment, one of the children could have served the same script more times than any other, while another child may never have run it.

Stas and his boss didn't discover the aforementioned problem with the user registration system before going into production because the error_log file was too crowded with warnings continuously logged by multiple child processes.

To immediately recognize the problem visually (so you can see incorrect results), you need to run the server as a single process. You can do this by invoking the server with the -X option:

panic% httpd -X

Since there are no other servers (children) running, you will get the problem report on the second reload.

Enabling the warnings mode (as explained earlier in this chapter) and monitoring the error_log file will help you detect most of the possible errors. Some warnings can become errors, as we have just seen. You should check every reported warning and eliminate it, so it won't appear in error_log again. If your error_log file is filled up with hundreds of lines on every script invocation, you will have difficulty noticing and locating real problems, and on a production server you'll soon run out of disk space if your site is popular.

Namespace Issues

If your service consists of a single script, you will probably have no namespace problems. But web services usually are built from many scripts and handlers. In the following sections, we will investigate possible namespace problems and their solutions. But first we will refresh our understanding of two special Perl variables, @INC and %INC.

The @INC Array

Perl's @INC array is like the PATH environment variable for the shell program. Whereas PATH contains a list of directories to search for executable programs, @INC contains a list of directories from which Perl modules and libraries can be loaded.

When you use( ), require( ), or do( ) a filename or a module, Perl gets a list of directories from the @INC variable and searches them for the file it was requested to load. If the file that you want to load is not located in one of the listed directories, you must tell Perl where to find the file. You can either provide a path relative to one of the directories in @INC or provide the absolute path to the file.

The %INC Hash

Perl's %INC hash is used to cache the names of the files and modules that were loaded and compiled by use( ), require( ), or do( ) statements. Every time a file or module is successfully loaded, a new key-value pair is added to %INC. The key is the name of the file or module as it was passed to one of the three functions we have just mentioned. If the file or module was found in any of the @INC directories (except "."), the filenames include the full path. Each Perl interpreter, and hence each process under mod_perl, has its own private %INC hash, which is used to store information about its compiled modules.

Before attempting to load a file or a module with use( ) or require( ), Perl checks whether it's already in the %INC hash. If it's there, the loading and compiling are not performed. Otherwise, the file is loaded into memory and an attempt is made to compile it. Note that do( ) loads the file or module unconditionally--it does not check the %INC hash. We'll look at how this works in practice in the following examples.

First, let's examine the contents of @INC on our system:

panic% perl -le 'print join "\n", @INC'
/usr/lib/perl5/5.6.1/i386-linux
/usr/lib/perl5/5.6.1
/usr/lib/perl5/site_perl/5.6.1/i386-linux
/usr/lib/perl5/site_perl/5.6.1
/usr/lib/perl5/site_perl
.

Notice . (the current directory) as the last directory in the list.

Let's load the module strict.pm and see the contents of %INC:

panic% perl -le 'use strict; print map {"$_ => $INC{$_}"} keys %INC'
strict.pm => /usr/lib/perl5/5.6.1/strict.pm

Since strict.pm was found in the /usr/lib/perl5/5.6.1/ directory and /usr/lib/perl5/5.6.1/ is a part of @INC, %INC includes the full path as the value for the key strict.pm.

Let's create the simplest possible module in /tmp/test.pm:

1;

This does absolutely nothing, but it returns a true value when loaded, which is enough to satisfy Perl that it loaded correctly. Let's load it in different ways:

panic% cd /tmp
panic% perl -e 'use test; \
       print map { "$_ => $INC{$_}\n" } keys %INC'
test.pm => test.pm

Since the file was found in . (the directory the code was executed from), the relative path is used as the value. Now let's alter @INC by appending /tmp:

panic% cd /tmp
panic% perl -e 'BEGIN { push @INC, "/tmp" } use test; \
       print map { "$_ => $INC{$_}\n" } keys %INC'
test.pm => test.pm

Here we still get the relative path, since the module was found first relative to ".". The directory /tmp was placed after . in the list. If we execute the same code from a different directory, the "." directory won't match:

panic% cd /
panic% perl -e 'BEGIN { push @INC, "/tmp" } use test; \
       print map { "$_ => $INC{$_}\n" } keys %INC'
test.pm => /tmp/test.pm

so we get the full path. We can also prepend the path with unshift( ), so that it will be used for matching before ".". We will get the full path here as well:

panic% cd /tmp
panic% perl -e 'BEGIN { unshift @INC, "/tmp" } use test; \
       print map { "$_ => $INC{$_}\n" } keys %INC'
test.pm => /tmp/test.pm

The code:

BEGIN { unshift @INC, "/tmp" }

can be replaced with the more elegant:

use lib "/tmp";

This is almost equivalent to our BEGIN block and is the recommended approach.

These approaches to modifying @INC can be labor intensive: moving the script around in the filesystem might require modifying the path.

home / programming / perl / mod_perl / chap6 / 1 To page 1To page 2To page 3To page 4current pageTo page 6To page 7
[previous] [next]

internet.commediabistro.comJusttechjobs.comGraphics.com

Search:

WebMediaBrands Corporate Info

Legal Notices, Licensing, Permissions, Privacy Policy.
Advertise | Newsletters | Shopping | E-mail Offers | Freelance Jobs

webref The latest from WebReference.com Browse >
Rolling Out Your Own HTML Application Version Control · HTML 5: Client-side Storage · Working with Ajax Server Extensions
Sitemap · Experts · Tools · Services · Email a Colleague · Contact FREE Newsletters 
 The latest from internet.com
Wi-Fi Product Watch, November 2009 · Chip Market Recovering From '08 Collapse · Low-Cost Tools to Kickstart Your New Business

Created: March 27 2003
Revised: July 23, 2003

URL: http://webreference.com/programming/perl/mod_perl/chap6/1