Litmus:mod perl

From MozillaWiki
Jump to: navigation, search

« back to Litmus main page

Introduction

As of August 2006, Litmus uses mod_perl to improve performance. Typically, normal CGI scripts must be compiled by the perl interpreter for each http request. Furthermore, every request requires that perl load and compile all the perl modules Litmus uses, connect to the database, go through the Template Toolkit's initialization routines, and all sorts of other activities before Litmus even gets started processing a particular request. mod_perl performs this initialization step only once--at web server startup time--and runs the script within the context of an already running perl interpretor.

The upside of supporting mod_perl is the performance benefit. Initial benchmarking with a mod_perl enabled version of Litmus showed performance improvements on the order of 2X-8X depending on what script is measured. mod_perl also reduces load on the web server, allowing it to process more requests.

The downside is that code needs to be written with mod_perl in mind. Below are a few notes on mod_perl support as it relates to Litmus.

See also the mod_perl porting guidelines for further details.

Apache Configuration on Rodan

Use this configuration as a model for your own server config

<VirtualHost *:80>
  ServerName litmus.mozilla.org
  DocumentRoot /opt/webtools/testrunner/litmus

  <Directory /opt/webtools/testrunner/litmus>
    PerlModule Apache::DBI
         <Perl>
           use CGI;
           CGI->compile(qw(header param cookie));
           use DBI;
           DBI->install_driver("mysql");
           use Template;
           use HTML::StripScripts;
           use Text::Markdown;
         </Perl>
        AddHandler perl-script .cgi .pl
        PerlHandler Apache::Registry

    Options Indexes FollowSymLinks ExecCGI
    DirectoryIndex index.html index.cgi
    AllowOverride All
  </Directory>

</VirtualHost>


Web Server Restarting / Module Persistence

Under mod_perl, modules are not reloaded on each http request. This means that if you update Litmus or modify a .pm file within the Litmus tree, those changes will not be picked up until the web server is restarted.

Litmus developers may prefer to use a 'touch file' in their local development environments--a special file that, when touched, causes the web server to reload modules. The use of a touch file is documented in the mod_perl documentation. Otherwise, a simple 'apachectl restart' as root will suffice.

On rodan, members of group 'litmus' may trigger a web server restart with the command 'litmus-restart'. Use with extreme caution and fix any errors immediately. Note that the 'updatelitmus' command will not restart the web server for you; you must run 'litmus-restart' as well if you want this to happen.

Global Variables

Another issue to be aware of when coding for mod_perl is global variables. Unless measures are taken, global variables will not be automatically reset between requests. See the mod_perl porting guidelines for more information.

Litmus provides a special object cache (ripped off from Bugzilla) that ensures that global variables stored in the cache will be destroyed after each request. This cache is used for global objects such as the current CGI.pm or Template.pm instance. These variables may be accessed through Litmus.pm as before. Scripts can also use the object cache to store global data if needed (although good design dictates that globals should be avoided whenever possible). Information on how to do so can be found in Litmus.pm.

Module Dependency Loops

Under mod_cgi, perl scripts could often get away with dependency loops where module A.pm used B.pm and B.pm used A.pm. However, mod_perl typically chokes on these module dependency loops and the error messages it generates are often not helpful (usually they involve "subroutine x does not exist" errors).

The current mod_perl enabled version of Litmus contains no such loops. Zach has some fancy graphing tools adapted from the Bugzilla project that map the dependency tree and highlights duplicates. If you're trying to resolve a dependency loop issue, he can get you a copy of the graphing tools.

Begin blocks and Litmus->init()

While CGI scripts will have any BEGIN{} blocks called at compile-time, mod_perl scripts have BEGIN blocks called only once: when the web server starts up. As such, initialization tasks that must be done for each request must not be done in BEGIN blocks.

Accordingly, Litmus.pm provides an init() method to handle authentication and other tasks that happen at the beginning of script execution. All CGI scripts **must** called Litmus->init(); prior to sending a content-type header or performing any other tasks for these initialization tasks to occur.