Apache::AxKit::Language::XSPCaching - eXtensible Server Pages with AxKit caching |
Apache::AxKit::Language::XSPCaching - eXtensible Server Pages with AxKit caching
<Files page.xsp> AxAddStyleMap application/x-xsp +Apache::AxKit::Language::XSPCaching </Files>
This module allows the existing AxKit caching mechanism to function for XSP-generated content.
Note that there is a separate AxKit caching mechanism for
XSP-generated content which can be enabled by defining methods for
has_changed
and cache_params
in your XSP script. However, that
mechanism only caches the direct output of the XSP. If your output is
processed further, by XSLT for example, the final output is not
cached. This module enables caching even for XSP output that is
further processed through an AxKit pipeline.
It is very important to understand that you must do more work beyond simply enabling this module for caching to work properly. You must inform AxKit of the dependencies in your XSP script, and you must inform AxKit whether the output of your XSP script varies depending on various parameters such as the query string, a cookie, HTTP request header, etc.
If you do not take care of these details, then your page will not be updated when its content changes. Even worse, if your page is customized for a specific user, then one user would see a different user's page!
You can inform AxKit of the dependencies in your XSP script by using
the function AxKit::add_depends
. For example, if your XSP script
reads in a configuration file /etc/axkit/xsp.conf and generates
different output depending on the content of that file, then you
should place this function call in your XSP script:
AxKit::add_depends( '{content}' . '/etc/axkit/xsp.conf' );
AxKit will record this dependency in its cache. If the timestamp of this file is later than the timestamp of the cached output, then AxKit will call your XSP script to regenerate the output.
Suggestion: If your XSP script depends on some content from a database or some other source that cannot be tracked by a timestamp on a file, then create an AxKit plugin that will determine the last-modified-time of that content and then stamp a file with that time. For example:
package My::AxKit::Plugin::LastModifiedTimestamp; use Apache (); use Apache::Constants (); sub handler { my $r = shift; my $time = last_modified(); # determine last-modified-time of content my $file = '/var/cache/axkit/myscript.timestamp'; if ( not -e $file ) { my $fh = Apache->gensym(); open( $fh, ">$file" ) or die "Could not open $file: $!"; print $fh "The timestamp of this file is updated when\n"; print $fh "the dependencies of myscript.xsp have changed.\n"; close( $fh ) or die "Could not close $file: $!"; } utime( $time, $time, $file ) or die "Could not timestamp $file: $!"; return Apache::Constants::OK; }
Enable your plugin like this:
<Files myscript.xsp> AxAddPlugin +My::AxKit::Plugin::LastModifiedTimestamp </Files>
You can inform AxKit whether the output of your XSP script varies by query string using the QueryStringCache plugin:
<Files myscript.xsp> AxAddPlugin +Apache::AxKit::Plugin::QueryStringCache </Files>
AxKit will then create a separate cache file for different values of your query string. Also see QueryStringCacheRegexp.
If your output varies depending on other parameters, such as a cookie or HTTP request header, then create your own plugin and set the "axkit_cache_extra" Apache notes variable. For example:
package My::AxKit::Plugin::CacheParams; use Apache::Cookie (); use Apache::Constants (); sub handler { my $r = shift; my $extra = $r->notes( 'axkit_cache_extra' ); my %cookies = Apache::Cookie->fetch; my $cookie = $cookies{COOKIENAME}; $extra .= ":COOKIENAME=" . join( '&', $cookie->value ) if $cookie; # (I chose a colon prefix because that's what AxKit uses to separate extras) $r->notes( axkit_cache_extra => $extra ); return Apache::Constants::OK; }
<Files script.xsp> AxAddPlugin +My::AxKit::Plugin::CacheParams </Files>
For improved performance, AxKit uses memory to cache a list of
stylesheets for each document. However, when extra cache parameters
are set using any of the above methods, AxKit uses separate cache
entries for each different setting of "axkit_cache_extra", even though
the list of stylesheets is probably the same for these different
settings. This use of separate cache entries can lead to wasted
memory, especially when caching personalized pages for thousands of
users. To avoid the extra memory usage, patch AxKit so that it uses a
cache entry independent of "axkit_cache_extra". Replace the following
line in the get_styles
subroutine of AxKit.pm
:
my $key = $cache->key();
with this line:
my $key = join(':', $provider->key(), $style, $media);
Note well: only replace this one line. Do not replace any other instances of "$cache->key()".
The above patch can wreak havoc if you dynamically define the list of stylesheets using AxAddDynamicProcessor based either directly or indirectly on information contained in "axkit_cache_extra". In this case you can either comment out the caching of stylesheet lists entirely, or make sure that you define a different "preferred_style" for each different dynamic list of stylesheets so that the $key will be different for each one.
If your XSP script performs some tasks such as authentication or
setting HTTP response headers, then you need to move these tasks into
a plugin so that they will run even when AxKit serves your XSP output
from its cache. Remember: AxKit will never run your XSP script again
once the output becomes cached! Except, of course, when a dependency
was updated (AxKit::add_depends
) or the cache parameters change
(axkit_cache_extra
).
The AxKit cache is not automatically cleaned. If space is an issue, such as when you are caching pages that are customized for individual users, then you need to run a cron job or something similar to delete stale files from the cache. For example, see Apache::AxKit::CacheCleaner.
This module overrides the $r->no_cache method which gets called from Apache::AxKit::Language::XSP so that caching remains on.
You can turn caching back off in your XSP script by calling AxKit::Apache::no_cache($r,1). You may wish to do this for error pages for example. This will invoke the following methods for you:
Apache::no_cache($r,1); # send "no-cache" headers to browser $AxKit::Cache->no_cache(1). # do not store in AxKit cache
If you want AxKit caching turned off but you do not want the
"no-cache" headers sent to the browser, then just invoke
$AxKit::Cache->no_cache(1)
.
Alternatively, if you want to send the "no-cache" headers to the browser but keep AxKit caching turned on, then just call Apache::no_cache($r,1);
AxKit, Apache::AxKit::Plugin::QueryStringCache, Apache::AxKit::Plugin::QueryStringCacheRegexp, Apache::AxKit::CacheCleaner
Ken Neighbors <ken@nsds.com>
Copyright (c) 2005-2006 Ken Neighbors. All rights reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Apache::AxKit::Language::XSPCaching - eXtensible Server Pages with AxKit caching |