Greeting E2 coders and future mod_perl aficionados,

At the time of this writing (Dec 2012), I am undergoing an effort to work on mod_perl safety across the nodebase. This is going to allow for the next level of performance improvements, and in-turn, feature expansion on our current hardware set. Before we can make pages do more, we have to make them cheaper. I am working through several classes of problems that all involve mod_perl safety. The reasons for this are pretty compelling, once we are no longer eval()ing htmlcodes every time, we can avoid a huge performance hit and let mod_perl work it's magic. The downside is to get to here from there, we need to introduce a new attribute on htmlcodes called 'modperlsafe'. Once we've audited all of them, we can turn on pre-compilation

Let's back up a bit. What is mod_perl safety? In the old days of E2, htmlcodes were eval()'d every pageload and the results were taken and the code block was thrown away, even though we could pretty easily express it as a subroutine. In fact, in ecore pre-1.0, a lot of the HTML drawing subroutines did that. However, the assumptions our codebase makes about the way htmlcode functions are called is not compatible with Apache's mod_perl. In mod_perl, as long as something sticks around, even if it is in an anonymous subroutine, the value that an object last had was the value that it ended the previous execution with. This is the entire basis of our NodeCache structure, but it can be incredibly painful if used incorrectly.

Here's a trivial example of how mod_perl's caching works:

my $value;
$value = time() unless $value;

In the above example, if it stays resident in mod_perl's memory, the value will only ever be the first time() the Apache thread is launched. This is great if you are using it properly, but you can't assume that $value stars off as undef as you might expect.

As one is coding or one is auditing code, check for several classes of mod perl errors:


Conditional assignment:

my $value = 2 if($USER->{title} eq "jaybonci");
$value ||= 3;
This one is snarly. You will note that $value is being set one way which works in one instance, but the inverse may poison the cache if the condition ever happens.
The fix:
my $value = undef;
$value = 2 if($USER->{title} eq "jaybonci");
$value ||= 3;


Concatenation or push-ing onto a non-clear variable

my $str;

foreach my $user(@$userlist)
{
  $str .= "$$user{title}<br>";
}
Note that in this example, $str will grow forever, and this happens all the time as of the creation of this writeup. The fix:
my $str = undef;

foreach my $user(@$userlist)
{
  $str .= "$$user{title}<br>";
}


Even though we are using stored compilation in many areas of the codebase (we aren't for htmlcodes which require arguments), we don't know whether or not these errors are affecting us or not. Currently at any given time, about half of them in the nodecache, including most of the heavy lifting htmlcodes aren't holding onto compiled code. This will allow us to store every htmlcode in a safe way, once they have been audited and marked as mod_perl safe. We can then continue the compilation to htmlpage, and container compilation once we are aware of the issues. This should prove to be a huge speedup and will allow us some headroom to continue to innovation on the feature side of the house. This exists as a general warning for people who are porting apps to mod_perl or who are getting involved with mod_perl programming, and how it applies to ecore.

Onwards.