3 package Catalyst::Plugin::Cache;
4 use base qw(Class::Accessor::Fast Class::Data::Inheritable);
12 use Catalyst::Utils ();
16 use Catalyst::Plugin::Cache::Curried;
18 __PACKAGE__->mk_classdata( "_cache_backends" );
19 __PACKAGE__->mk_accessors( "_default_curried_cache" );
24 # set it once per app, not once per plugin,
25 # and don't overwrite if some plugin was wicked
26 $app->_cache_backends({}) unless $app->_cache_backends;
28 my $ret = $app->maybe::next::method( @_ );
30 $app->setup_cache_backends;
35 sub _get_cache_plugin_config {
37 return $app->config->{'Plugin::Cache'} || $app->config->{cache};
40 sub get_default_cache_backend_config {
41 my ( $app, $name ) = @_;
42 $app->_get_cache_plugin_config->{backend} || $app->get_cache_backend_config("default");
45 sub get_cache_backend_config {
46 my ( $app, $name ) = @_;
47 $app->_get_cache_plugin_config->{backends}{$name};
50 sub setup_cache_backends {
53 # give plugins a chance to find things for themselves
54 $app->maybe::next::method;
56 # FIXME - Don't know why the _get_cache_plugin_config method doesn't work here!
57 my $conf = $app->config->{'Plugin::Cache'} ? $app->config->{'Plugin::Cache'}->{backends} : $app->config->{cache}->{backends};
58 foreach my $name ( keys %$conf ) {
59 next if $app->get_cache_backend( $name );
60 $app->setup_generic_cache_backend( $name, $app->get_cache_backend_config( $name ) || {} );
63 if ( !$app->get_cache_backend("default") ) {
64 ### XXX currently we dont have a fallback scenario
65 ### so die here with the error message. Once we have
66 ### an in memory fallback, we may consider silently
67 ### logging the error and falling back to that.
68 ### If we dont die here, the app will silently start
69 ### up and then explode at the first cache->get or
70 ### cache->set request with a FIXME error
73 $app->setup_generic_cache_backend( default => $app->get_default_cache_backend_config || {} );
79 sub default_cache_store {
81 $app->_get_cache_plugin_config->{default_store} || $app->guess_default_cache_store;
84 sub guess_default_cache_store {
87 my @stores = map { /Cache::Store::(.*)$/ ? $1 : () } $app->registered_plugins;
92 Carp::croak "You must configure a default store type unless you use exactly one store plugin.";
96 sub setup_generic_cache_backend {
97 my ( $app, $name, $config ) = @_;
98 my %config = %$config;
100 if ( my $class = delete $config{class} ) {
102 ### try as list and as hashref, collect the
103 ### error if things go wrong
104 ### if all goes well, exit the loop
106 for my $aref ( [%config], [\%config] ) {
107 eval { $app->setup_cache_backend_by_class(
108 $name, $class, @$aref
110 } ? do { @errors = (); last }
111 : push @errors, "\t$@";
114 ### and die with the errors if we have any
115 die "Couldn't construct $class with either list style or hash ref style param passing:\n @errors" if @errors;
117 } elsif ( my $store = delete $config->{store} || $app->default_cache_store ) {
118 my $method = lc("setup_${store}_cache_backend");
120 Carp::croak "You must load the $store cache store plugin (if it exists). ".
121 "Please consult the Catalyst::Plugin::Cache documentation on how to configure hetrogeneous stores."
122 unless $app->can($method);
124 $app->$method( $name, \%config );
126 $app->log->warn("Couldn't setup the cache backend named '$name'");
130 sub setup_cache_backend_by_class {
131 my ( $app, $name, $class, @args ) = @_;
132 Catalyst::Utils::ensure_class_loaded( $class );
133 $app->register_cache_backend( $name => $class->new( @args ) );
136 # end of spaghetti setup DWIM
139 my ( $c, @meta ) = @_;
143 return ( $c->get_preset_curried($name) || $c->get_cache_backend($name) );
145 # be nice and always return the same one for the simplest case
146 return ( $c->_default_curried_cache || $c->_default_curried_cache( $c->curry_cache( @meta ) ) );
148 return $c->curry_cache( @meta );
152 sub construct_curried_cache {
153 my ( $c, @meta ) = @_;
154 return $c->curried_cache_class( @meta )->new( @meta );
157 sub curried_cache_class {
158 my ( $c, @meta ) = @_;
159 $c->_get_cache_plugin_config->{curried_class} || "Catalyst::Plugin::Cache::Curried";
163 my ( $c, @meta ) = @_;
164 return $c->construct_curried_cache( $c, $c->_cache_caller_meta, @meta );
167 sub get_preset_curried {
168 my ( $c, $name ) = @_;
170 if ( ref( my $preset = $c->_get_cache_plugin_config->{profiles}{$name} ) ) {
171 return $preset if Scalar::Util::blessed($preset);
173 my @meta = ( ( ref $preset eq "HASH" ) ? %$preset : @$preset );
174 return $c->curry_cache( @meta );
180 sub get_cache_backend {
181 my ( $c, $name ) = @_;
182 $c->_cache_backends->{$name};
185 sub register_cache_backend {
186 my ( $c, $name, $backend ) = @_;
188 no warnings 'uninitialized';
189 Carp::croak("$backend does not look like a cache backend - "
190 . "it must be an object supporting get, set and remove")
191 unless eval { $backend->can("get") && $backend->can("set") && $backend->can("remove") };
193 $c->_cache_backends->{$name} = $backend;
196 sub unregister_cache_backend {
197 my ( $c, $name ) = @_;
198 delete $c->_cache_backends->{$name};
201 sub default_cache_backend {
203 $c->get_cache_backend( "default" ) || $c->temporary_cache_backend;
206 sub temporary_cache_backend {
208 die "FIXME - make up an in memory cache backend, that hopefully works well for the current engine";
211 sub _cache_caller_meta {
214 my ( $caller, $component, $controller );
216 for my $i ( 0 .. 15 ) { # don't look to far
217 my @info = caller(2 + $i) or last;
219 $caller ||= \@info unless $info[0] =~ /Plugin::Cache/;
220 $component ||= \@info if $info[0]->isa("Catalyst::Component");
221 $controller ||= \@info if $info[0]->isa("Catalyst::Controller");
223 last if $caller && $component && $controller;
226 my ( $caller_pkg, $component_pkg, $controller_pkg ) =
227 map { $_ ? $_->[0] : undef } $caller, $component, $controller;
230 'caller' => $caller_pkg,
231 component => $component_pkg,
232 controller => $controller_pkg,
233 caller_frame => $caller,
234 component_frame => $component,
235 controller_frame => $controller,
239 # this gets a shit name so that the plugins can override a good name
240 sub choose_cache_backend_wrapper {
241 my ( $c, @meta ) = @_;
243 Carp::croak("metadata must be an even sized list") unless @meta % 2 == 0;
247 unless ( exists $meta{'caller'} ) {
248 my %caller = $c->_cache_caller_meta;
249 @meta{keys %caller} = values %caller;
252 # allow the cache client to specify who it wants to cache with (but loeave room for a hook)
253 if ( exists $meta{backend} ) {
254 if ( Scalar::Util::blessed($meta{backend}) ) {
255 return $meta{backend};
257 return $c->get_cache_backend( $meta{backend} ) || $c->default_cache_backend;
261 if ( my $chosen = $c->choose_cache_backend( %meta ) ) {
262 $chosen = $c->get_cache_backend( $chosen ) unless Scalar::Util::blessed($chosen); # if it's a name find it
263 return $chosen if Scalar::Util::blessed($chosen); # only return if it was an object or name lookup worked
266 # die "no such backend"?
267 # currently, we fall back to default
270 return $c->default_cache_backend;
273 sub choose_cache_backend { shift->maybe::next::method( @_ ) } # a convenient fallback
276 my ( $c, $key, $value, %meta ) = @_;
277 $c->choose_cache_backend_wrapper( key => $key, value => $value, %meta )
278 ->set( $key, $value, exists $meta{expires} ? $meta{expires} : () );
282 my ( $c, $key, @meta ) = @_;
283 $c->choose_cache_backend_wrapper( key => $key, @meta )->get( $key );
287 my ( $c, $key, @meta ) = @_;
288 $c->choose_cache_backend_wrapper( key => $key, @meta )->remove( $key );
299 Catalyst::Plugin::Cache - Flexible caching support for Catalyst.
307 # configure a backend or use a store plugin
308 __PACKAGE__->config->{'Plugin::Cache'}{backend} = {
309 class => "Cache::Bounded",
310 # ... params for Cache::Bounded...
313 # typical example for Cache::Memcached::libmemcached
314 __PACKAGE__->config->{'Plugin::Cache'}{backend} = {
315 class => "Cache::Memcached::libmemcached",
316 servers => ['127.0.0.1:11211'],
324 my ( $self, $c, $id ) = @_;
326 my $cache = $c->cache;
330 unless ( $result = $cache->get( $id ) ) {
331 # ... calculate result ...
332 $c->cache->set( $id, $result );
338 This plugin gives you access to a variety of systems for caching
339 data. It allows you to use a very simple configuration API, while
340 maintaining the possibility of flexibility when you need it later.
342 Among its features are support for multiple backends, segmentation based
343 on component or controller, keyspace partitioning, and so more, in
344 various subsidiary plugins.
350 =item cache $profile_name
354 Return a curried object with metadata from C<$profile_name> or as
355 explicitly specified.
357 If a profile by the name C<$profile_name> doesn't exist, but a backend
358 object by that name does exist, the backend will be returned instead,
359 since the interface for curried caches and backends is almost identical.
361 This method can also be called without arguments, in which case is
362 treated as though the C<%meta> hash was empty.
364 See L</METADATA> for details.
366 =item curry_cache %meta
368 Return a L<Catalyst::Plugin::Cache::Curried> object, curried with C<%meta>.
370 See L</METADATA> for details.
372 =item cache_set $key, $value, %meta
374 =item cache_get $key, %meta
376 =item cache_remove $key, %meta
378 These cache operations will call L<choose_cache_backend> with %meta, and
379 then call C<set>, C<get>, or C<remove> on the resulting backend object.
381 =item choose_cache_backend %meta
383 Select a backend object. This should return undef if no specific backend
384 was selected - its caller will handle getting C<default_cache_backend>
387 This method is typically used by plugins.
389 =item get_cache_backend $name
391 Get a backend object by name.
393 =item default_cache_backend
395 Return the default backend object.
397 =item temporary_cache_backend
399 When no default cache backend is configured this method might return a
400 backend known to work well with the current L<Catalyst::Engine>. This is
411 Whenever you set or retrieve a key you may specify additional metadata
412 that will be used to select a specific backend.
414 This metadata is very freeform, and the only key that has any meaning by
415 default is the C<backend> key which can be used to explicitly choose a backend
418 The C<choose_cache_backend> method can be overridden in order to
419 facilitate more intelligent backend selection. For example,
420 L<Catalyst::Plugin::Cache::Choose::KeyRegexes> overrides that method to
421 select a backend based on key regexes.
423 Another example is a L<Catalyst::Plugin::Cache::ControllerNamespacing>,
424 which wraps backends in objects that perform key mangling, in order to
425 keep caches namespaced per controller.
427 However, this is generally left as a hook for larger, more complex
428 applications. Most configurations should make due XXXX
430 The simplest way to dynamically select a backend is based on the
431 L</Cache Profiles> configuration.
433 =head2 Meta Data Keys
435 C<choose_cache_backend> is called with some default keys.
441 Supplied by C<cache_get>, C<cache_set>, and C<cache_remove>.
445 Supplied by C<cache_set>.
449 The package name of the innermost caller that doesn't match
450 C<qr/Plugin::Cache/>.
454 The entire C<caller($i)> frame of C<caller>.
458 The package name of the innermost caller who C<isa>
459 L<Catalyst::Component>.
461 =item component_frame
463 This entire C<caller($i)> frame of C<component>.
467 The package name of the innermost caller who C<isa>
468 L<Catalyst::Controller>.
470 =item controller_frame
472 This entire C<caller($i)> frame of C<controller>.
476 =head2 Metadata Currying
478 In order to avoid specifying C<%meta> over and over again you may call
479 C<cache> or C<curry_cache> with C<%meta> once, and get back a B<curried
480 cache object>. This object responds to the methods C<get>, C<set>, and
481 C<remove>, by appending its captured metadata and delegating them to
482 C<cache_get>, C<cache_set>, and C<cache_remove>.
484 This is simpler than it sounds.
486 Here is an example using currying:
488 my $cache = $c->cache( %meta ); # cache is curried
490 $cache->set( $key, $value );
494 And here is an example without using currying:
496 $c->cache_set( $key, $value, %meta );
498 $c->cache_get( $key, %meta );
500 See L<Catalyst::Plugin::Cache::Curried> for details.
504 $c->config->{'Plugin::Cache'} = {
508 All configuration parameters should be provided in a hash reference
509 under the C<Plugin::Cache> key in the C<config> hash.
511 =head2 Backend Configuration
513 Configuring backend objects is done by adding hash entries under the
514 C<backends> key in the main config.
516 A special case is that the hash key under the C<backend> (singular) key
517 of the main config is assumed to be the backend named C<default>.
523 Instantiate a backend from a L<Cache> compatible class. E.g.
525 $c->config->{'Plugin::Cache'}{backends}{small_things} = {
526 class => "Cache::Bounded",
531 $c->config->{'Plugin::Cache'}{backends}{large_things} = {
532 class => "Cache::Memcached",
533 data => '1.2.3.4:1234',
536 The options in the hash are passed to the class's C<new> method.
538 The class will be C<required> as necessary during setup time.
542 Instantiate a backend using a store plugin, e.g.
544 $c->config->{'Plugin::Cache'}{backend} = {
548 Store plugins typically require less configuration because they are
549 specialized for L<Catalyst> applications. For example
550 L<Catalyst::Plugin::Cache::Store::FastMmap> will specify a default
551 C<share_file>, and additionally use a subclass of L<Cache::FastMmap>
552 that can also store non reference data.
554 The store plugin must be loaded.
558 =head2 Cache Profiles
564 Supply your own predefined profiles for cache metadata, when using the
567 For example when you specify
569 $c->config->{'Plugin::Cache'}{profiles}{thumbnails} = {
570 backend => "large_things",
573 And then get a cache object like this:
575 $c->cache("thumbnails");
577 It is the same as if you had done:
579 $c->cache( backend => "large_things" );
583 =head2 Miscellaneous Configuration
589 When you do not specify a C<store> parameter in the backend
590 configuration this one will be used instead. This configuration
591 parameter is not necessary if only one store plugin is loaded.
601 An object that responds to the methods detailed in
602 L<Catalyst::Plugin::Cache::Backend> (or more).
606 A plugin that provides backends of a certain type. This is a bit like a
611 Stored key/value pairs of data for easy re-access.
615 "Extra" information about the item being stored, which can be used to
616 locate an appropriate backend.
620 my $cache = $c->cache(type => 'thumbnails');
621 $cache->set('pic01', $thumbnaildata);
623 A cache which has been pre-configured with a particular set of
624 namespacing data. In the example the cache returned could be one
625 specifically tuned for storing thumbnails.
627 An object that responds to C<get>, C<set>, and C<remove>, and will
628 automatically add metadata to calls to C<< $c->cache_get >>, etc.
634 L<Cache> - the generic cache API on CPAN.
636 L<Catalyst::Plugin::Cache::Store> - how to write a store plugin.
638 L<Catalyst::Plugin::Cache::Curried> - the interface for curried caches.
640 L<Catalyst::Plugin::Cache::Choose::KeyRegexes> - choose a backend based on
641 regex matching on the keys. Can be used to partition the keyspace.
643 L<Catalyst::Plugin::Cache::ControllerNamespacing> - wrap backend objects in a
644 name mangler so that every controller gets its own keyspace.
648 Yuval Kogman, C<nothingmuch@woobling.org>
650 Jos Boumans, C<kane@cpan.org>
652 =head1 COPYRIGHT & LICENSE
654 Copyright (c) Yuval Kogman, 2006. All rights reserved.
656 This library is free software, you can redistribute it and/or modify it under
657 the same terms as Perl itself, as well as under the terms of the MIT license.