C::P::Cache doc fixing (mechanical only, not content)
[catagits/Catalyst-Plugin-Cache.git] / lib / Catalyst / Plugin / Cache.pm
CommitLineData
c28ee69c 1#!/usr/bin/perl
2
3package Catalyst::Plugin::Cache;
2e4bde89 4use base qw/Class::Data::Inheritable Class::Accessor::Fast/;
c28ee69c 5
6use strict;
7use warnings;
8
9use Scalar::Util ();
23b2d59b 10use Catalyst::Utils ();
c28ee69c 11use Carp ();
12use NEXT;
13
2e4bde89 14use Catalyst::Plugin::Cache::Curried;
15
c28ee69c 16__PACKAGE__->mk_classdata( "_cache_backends" );
2e4bde89 17__PACKAGE__->mk_accessors( "_default_curried_cache" );
c28ee69c 18
19sub setup {
20 my $app = shift;
21
22 # set it once per app, not once per plugin,
23 # and don't overwrite if some plugin was wicked
24 $app->_cache_backends({}) unless $app->_cache_backends;
25
26 my $ret = $app->NEXT::setup( @_ );
27
28 $app->setup_cache_backends;
29
30 $ret;
31}
32
23b2d59b 33sub get_default_cache_backend_config {
34 my ( $app, $name ) = @_;
35 $app->config->{cache}{backend} || $app->get_cache_backend_config("default");
36}
37
38sub get_cache_backend_config {
39 my ( $app, $name ) = @_;
40 $app->config->{cache}{backends}{$name};
41}
42
43sub setup_cache_backends {
44 my $app = shift;
45
46 # give plugins a chance to find things for themselves
47 $app->NEXT::setup_cache_backends;
48
49 foreach my $name ( keys %{ $app->config->{cache}{backends} } ) {
50 next if $app->get_cache_backend( $name );
51 $app->setup_generic_cache_backend( $name, $app->get_cache_backend_config( $name ) || {} );
52 }
53
33002c69 54 if ( !$app->get_cache_backend("default") ) {
55 local $@;
56 eval { $app->setup_generic_cache_backend( default => $app->get_default_cache_backend_config || {} ) };
85a748b9 57 }
23b2d59b 58}
59
60sub default_cache_store {
61 my $app = shift;
62 $app->config->{cache}{default_store} || $app->guess_default_cache_store;
63}
64
65sub guess_default_cache_store {
66 my $app = shift;
67
68 my @stores = map { /Cache::Store::(.*)$/ ? $1 : () } $app->registered_plugins;
69
70 if ( @stores == 1 ) {
71 return $stores[0];
72 } else {
73 Carp::croak "You must configure a default store type unless you use exactly one store plugin.";
74 }
75}
76
77sub setup_generic_cache_backend {
78 my ( $app, $name, $config ) = @_;
79 my %config = %$config;
80
81 if ( my $class = delete $config{class} ) {
82 $app->setup_cache_backend_by_class( $name, $class, %config );
83 } elsif ( my $store = delete $config->{store} || $app->default_cache_store ) {
84 my $method = lc("setup_${store}_cache_backend");
85
86 Carp::croak "You must load the $store cache store plugin (if it exists). ".
87 "Please consult the Catalyst::Plugin::Cache documentation on how to configure hetrogeneous stores."
88 unless $app->can($method);
89
90 $app->$method( $name, %config );
91 } else {
92 $app->log->warn("Couldn't setup the cache backend named '$name'");
93 }
94}
95
96sub setup_cache_backend_by_class {
97 my ( $app, $name, $class, @args ) = @_;
98 Catalyst::Utils::ensure_class_loaded( $class );
99 $app->register_cache_backend( $name => $class->new( @args ) );
100}
101
102# end of spaghetti setup DWIM
c28ee69c 103
104sub cache {
2e4bde89 105 my ( $c, @meta ) = @_;
106
107 if ( @meta == 1 ) {
108 my $name = $meta[0];
109 return ( $c->get_preset_curried($name) || $c->get_cache_backend($name) );
110 } elsif ( !@meta ) {
111 # be nice and always return the same one for the simplest case
112 return ( $c->_default_curried_cache || $c->_default_curried_cache( $c->curry_cache( @meta ) ) );
c28ee69c 113 } else {
2e4bde89 114 return $c->curry_cache( @meta );
c28ee69c 115 }
116}
117
5a00a29b 118sub construct_curried_cache {
119 my ( $c, @meta ) = @_;
120 return $c->curried_cache_class( @meta )->new( @meta );
121}
122
123sub curried_cache_class {
124 my ( $c, @meta ) = @_;
125 $c->config->{cache}{curried_class} || "Catalyst::Plugin::Cache::Curried";
126}
127
2e4bde89 128sub curry_cache {
129 my ( $c, @meta ) = @_;
5a00a29b 130 return $c->construct_curried_cache( $c, $c->_cache_caller_meta, @meta );
2e4bde89 131}
132
133sub get_preset_curried {
134 my ( $c, $name ) = @_;
135
136 if ( ref( my $preset = $c->config->{cache}{profiles}{$name} ) ) {
137 return $preset if Scalar::Util::blessed($preset);
138
139 my @meta = ( ( ref $preset eq "HASH" ) ? %$preset : @$preset );
140 return $c->curry_cache( @meta );
141 }
142
143 return;
144}
145
c28ee69c 146sub get_cache_backend {
147 my ( $c, $name ) = @_;
148 $c->_cache_backends->{$name};
149}
150
151sub register_cache_backend {
152 my ( $c, $name, $backend ) = @_;
153
154 no warnings 'uninitialized';
155 Carp::croak("$backend does not look like a cache backend - "
aed484da 156 . "it must be an object supporting get, set and remove")
157 unless eval { $backend->can("get") && $backend->can("set") && $backend->can("remove") };
c28ee69c 158
159 $c->_cache_backends->{$name} = $backend;
160}
161
162sub unregister_cache_backend {
163 my ( $c, $name ) = @_;
164 delete $c->_cache_backends->{$name};
165}
166
167sub default_cache_backend {
168 my $c = shift;
169 $c->get_cache_backend( "default" ) || $c->temporary_cache_backend;
170}
171
172sub temporary_cache_backend {
173 my $c = shift;
174 die "FIXME - make up an in memory cache backend, that hopefully works well for the current engine";
175}
176
5a00a29b 177sub _cache_caller_meta {
178 my $c = shift;
179
180 my ( $caller, $component, $controller );
181
182 for my $i ( 0 .. 15 ) { # don't look to far
183 my @info = caller(2 + $i) or last;
184
85a748b9 185 $caller ||= \@info unless $info[0] =~ /Plugin::Cache/;
5a00a29b 186 $component ||= \@info if $info[0]->isa("Catalyst::Component");
187 $controller ||= \@info if $info[0]->isa("Catalyst::Controller");
188
189 last if $caller && $component && $controller;
190 }
191
85a748b9 192 my ( $caller_pkg, $component_pkg, $controller_pkg ) =
193 map { $_ ? $_->[0] : undef } $caller, $component, $controller;
194
5a00a29b 195 return (
85a748b9 196 'caller' => $caller_pkg,
197 component => $component_pkg,
198 controller => $controller_pkg,
199 caller_frame => $caller,
200 component_frame => $component,
201 controller_frame => $controller,
5a00a29b 202 );
203}
204
c28ee69c 205# this gets a shit name so that the plugins can override a good name
206sub choose_cache_backend_wrapper {
207 my ( $c, @meta ) = @_;
208
c627df81 209 Carp::croak("metadata must be an even sized list") unless @meta % 2 == 0;
c28ee69c 210
211 my %meta = @meta;
5a00a29b 212
213 unless ( exists $meta{'caller'} ) {
214 my %caller = $c->_cache_caller_meta;
215 @meta{keys %caller} = values %caller;
216 }
c28ee69c 217
218 # allow the cache client to specify who it wants to cache with (but loeave room for a hook)
219 if ( exists $meta{backend} ) {
220 if ( Scalar::Util::blessed($meta{backend}) ) {
221 return $meta{backend};
222 } else {
223 return $c->get_cache_backend( $meta{backend} ) || $c->default_cache_backend;
224 }
225 };
226
c28ee69c 227 if ( my $chosen = $c->choose_cache_backend( %meta ) ) {
228 $chosen = $c->get_cache_backend( $chosen ) unless Scalar::Util::blessed($chosen); # if it's a name find it
229 return $chosen if Scalar::Util::blessed($chosen); # only return if it was an object or name lookup worked
230
231 # FIXME
232 # die "no such backend"?
233 # currently, we fall back to default
234 }
235
236 return $c->default_cache_backend;
237}
238
239sub choose_cache_backend { shift->NEXT::choose_cache_backend( @_ ) } # a convenient fallback
240
241sub cache_set {
242 my ( $c, $key, $value, @meta ) = @_;
243 $c->choose_cache_backend_wrapper( key => $key, value => $value, @meta )->set( $key, $value );
244}
245
246sub cache_get {
247 my ( $c, $key, @meta ) = @_;
248 $c->choose_cache_backend_wrapper( key => $key, @meta )->get( $key );
249}
250
aed484da 251sub cache_remove {
c28ee69c 252 my ( $c, $key, @meta ) = @_;
aed484da 253 $c->choose_cache_backend_wrapper( key => $key, @meta )->remove( $key );
c28ee69c 254}
255
256__PACKAGE__;
257
258__END__
259
260=pod
261
262=head1 NAME
263
85a748b9 264Catalyst::Plugin::Cache - Flexible caching support for Catalyst.
c28ee69c 265
266=head1 SYNOPSIS
267
5a00a29b 268 use Catalyst qw/
269 Cache
270 /;
271
272 # configure a backend or use a store plugin
85a748b9 273 __PACKAGE__->config->{cache}{backend} = {
274 class => "Cache::Bounded",
275 # ... params ...
276 };
5a00a29b 277
c627df81 278 # In a controller:
5a00a29b 279
280 sub foo : Local {
281 my ( $self, $c, $id ) = @_;
282
283 my $cache = $c->cache;
284
285 my $result;
286
287 unless ( $result = $cache->get( $id ) ) {
c627df81 288 # ... calculate result ...
5a00a29b 289 $c->cache->set( $id, $result );
290 }
291 };
c28ee69c 292
293=head1 DESCRIPTION
294
c627df81 295This plugin gives you access to a variety of systems for caching
296data. It allows you to use a very simple configuration API, while
297maintaining the possibility of flexibility when you need it later.
5a00a29b 298
c627df81 299Among its features are support for multiple backends, segmentation based
300on component or controller, keyspace partitioning, and so more, in
301various subsidiary plugins.
5a00a29b 302
85a748b9 303=head1 METHODS
304
305=over 4
306
307=item cache $profile_name
308
309=item cache %meta
310
c627df81 311Return a curried object with metadata from C<$profile_name> or as
312explicitly specified.
85a748b9 313
c627df81 314If a profile by the name C<$profile_name> doesn't exist, but a backend
315object by that name does exist, the backend will be returned instead,
316since the interface for curried caches and backends is almost identical.
85a748b9 317
c627df81 318This method can also be called without arguments, in which case is
319treated as though the C<%meta> hash was empty.
85a748b9 320
c627df81 321See L</METADATA> for details.
85a748b9 322
323=item curry_cache %meta
324
c627df81 325Return a L<Catalyst::Plugin::Cache::Curried> object, curried with C<%meta>.
85a748b9 326
c627df81 327See L</METADATA> for details.
85a748b9 328
329=item cache_set $key, $value, %meta
330
331=item cache_get $key, %meta
332
333=item cache_remove $key, %meta
334
c627df81 335These cache operations will call L<choose_cache_backend> with %meta, and
336then call C<set>, C<get>, or C<remove> on the resulting backend object.
85a748b9 337
338=item choose_cache_backend %meta
339
c627df81 340Select a backend object. This should return undef if no specific backend
341was selected - its caller will handle getting C<default_cache_backend>
342on its own.
85a748b9 343
344This method is typically used by plugins.
345
346=item get_cache_backend $name
347
348Get a backend object by name.
349
350=item default_cache_backend
351
352Return the default backend object.
353
354=item temporary_cache_backend
355
c627df81 356When no default cache backend is configured this method might return a
357backend known to work well with the current L<Catalyst::Engine>. This is
358a stub.
85a748b9 359
360=item
361
362=back
363
c627df81 364=head1 METADATA
85a748b9 365
366=head2 Introduction
367
c627df81 368Whenever you set or retrieve a key you may specify additional metadata
369that will be used to select a specific backend.
85a748b9 370
371This metadata is very freeform, and the only key that has any meaning by
372default is the C<backend> key which can be used to explicitly choose a backend
373by name.
374
c627df81 375The C<choose_cache_backend> method can be overridden in order to
376facilitate more intelligent backend selection. For example,
377L<Catalyst::Plugin::Cache::Choose::KeyRegexes> overrides that method to
378select a backend based on key regexes.
85a748b9 379
c627df81 380Another example is a L<Catalyst::Plugin::Cache::ControllerNamespacing>,
381which wraps backends in objects that perform key mangling, in order to
382keep caches namespaced per controller.
85a748b9 383
384However, this is generally left as a hook for larger, more complex
c627df81 385applications. Most configurations should make due XXXX
85a748b9 386
c627df81 387The simplest way to dynamically select a backend is based on the
388L</Cache Profiles> configuration.
85a748b9 389
390=head2 Meta Data Keys
391
392C<choose_cache_backend> is called with some default keys.
393
394=over 4
395
396=item key
397
c627df81 398Supplied by C<cache_get>, C<cache_set>, and C<cache_remove>.
85a748b9 399
400=item value
401
c627df81 402Supplied by C<cache_set>.
85a748b9 403
404=item caller
405
406The package name of the innermost caller that doesn't match
407C<qr/Plugin::Cache/>.
408
409=item caller_frame
410
411The entire C<caller($i)> frame of C<caller>.
412
413=item component
414
c627df81 415The package name of the innermost caller who C<isa>
416L<Catalyst::Component>.
85a748b9 417
418=item component_frame
419
420This entire C<caller($i)> frame of C<component>.
421
422=item controller
423
c627df81 424The package name of the innermost caller who C<isa>
425L<Catalyst::Controller>.
85a748b9 426
427=item controller_frame
428
429This entire C<caller($i)> frame of C<controller>.
430
431=back
432
c627df81 433=head2 Metadata Currying
85a748b9 434
c627df81 435In order to avoid specifying C<%meta> over and over again you may call
436C<cache> or C<curry_cache> with C<%meta> once, and get back a B<curried
437cache object>. This object responds to the methods C<get>, C<set>, and
438C<remove>, by appending its captured metadata and delegating them to
439C<cache_get>, C<cache_set>, and C<cache_remove>.
85a748b9 440
441This is simpler than it sounds.
442
443Here is an example using currying:
444
445 my $cache = $c->cache( %meta ); # cache is curried
446
447 $cache->set( $key, $value );
448
449 $cache->get( $key );
450
451And here is an example without using currying:
452
453 $c->cache_set( $key, $value, %meta );
454
455 $c->cache_get( $key, %meta );
456
457See L<Catalyst::Plugin::Cache::Curried> for details.
458
0f0237aa 459=head1 CONFIGURATION
460
85a748b9 461 $c->config->{cache} = {
462 ...
463 };
0f0237aa 464
c627df81 465All configuration parameters should be provided in a hash reference
466under the C<cache> key in the C<config> hash.
0f0237aa 467
85a748b9 468=head2 Backend Configuration
469
470Configuring backend objects is done by adding hash entries under the
c627df81 471C<backends> key in the main config.
85a748b9 472
c627df81 473A special case is that the hash key under the C<backend> (singular) key
474of the main config is assumed to be the backend named C<default>.
85a748b9 475
0f0237aa 476=over 4
477
478=item class
479
85a748b9 480Instantiate a backend from a L<Cache> compatible class. E.g.
0f0237aa 481
85a748b9 482 $c->config->{cache}{backends}{small_things} = {
483 class => "Cache::Bounded",
484 interval => 1000,
485 size => 10000,
486 };
487
488 $c->config->{cache}{backends}{large_things} = {
c627df81 489 class => "Cache::Memcached::Managed",
85a748b9 490 data => '1.2.3.4:1234',
491 };
0f0237aa 492
85a748b9 493The options in the hash are passed to the class's C<new> method.
0f0237aa 494
85a748b9 495The class will be C<required> as necessary during setup time.
0f0237aa 496
85a748b9 497=item store
0f0237aa 498
c627df81 499Instantiate a backend using a store plugin, e.g.
0f0237aa 500
85a748b9 501 $c->config->{cache}{backend} = {
502 store => "FastMmap",
503 };
0f0237aa 504
c627df81 505Store plugins typically require less configuration because they are
506specialized for L<Catalyst> applications. For example
85a748b9 507L<Catalyst::Plugin::Cache::Store::FastMmap> will specify a default
c627df81 508C<share_file>, and additionally use a subclass of L<Cache::FastMmap>
509that can also store non reference data.
85a748b9 510
511The store plugin must be loaded.
512
513=back
0f0237aa 514
85a748b9 515=head2 Cache Profiles
516
517=over 4
0f0237aa 518
519=item profiles
520
c627df81 521Supply your own predefined profiles for cache metadata, when using the
522C<cache> method.
85a748b9 523
524For example when you specify
525
526 $c->config->{cache}{profiles}{thumbnails} = {
527 backend => "large_things",
528 };
529
530And then get a cache object like this:
531
532 $c->cache("thumbnails");
533
534It is the same as if you had done:
535
536 $c->cache( backend => "large_things" );
537
538=back
539
c627df81 540=head2 Miscellaneous Configuration
85a748b9 541
542=over 4
543
544=item default_store
545
c627df81 546When you do not specify a C<store> parameter in the backend
547configuration this one will be used instead. This configuration
548parameter is not necessary if only one store plugin is loaded.
0f0237aa 549
550=back
551
552=head1 TERMINOLOGY
23b2d59b 553
554=over 4
555
556=item backend
557
558An object that responds to the methods detailed in
559L<Catalyst::Plugin::Cache::Backend> (or more).
560
561=item store
562
c627df81 563A plugin that provides backends of a certain type. This is a bit like a
564factory.
23b2d59b 565
0f0237aa 566=item cache
567
568Stored key/value pairs of data for easy re-access.
569
c627df81 570=item metadata
85a748b9 571
c627df81 572"Extra" information about the item being stored, which can be used to
573locate an appropriate backend.
85a748b9 574
23b2d59b 575=item curried cache
576
0f0237aa 577 my $cache = $c->cache(type => 'thumbnails');
578 $cache->set('pic01', $thumbnaildata);
579
c627df81 580A cache which has been pre-configured with a particular set of
581namespacing data. In the example the cache returned could be one
582specifically tuned for storing thumbnails.
0f0237aa 583
c627df81 584An object that responds to C<get>, C<set>, and C<remove>, and will
585automatically add metadata to calls to C<< $c->cache_get >>, etc.
23b2d59b 586
587=back
588
772299b1 589=head1 SEE ALSO
590
c627df81 591L<Cache> - the generic cache API on CPAN.
772299b1 592
593L<Catalyst::Plugin::Cache::Store> - how to write a store plugin.
594
595L<Catalyst::Plugin::Cache::Curried> - the interface for curried caches.
596
597L<Catalyst::Plugin::Cache::Choose::KeyRegexes> - choose a backend based on
598regex matching on the keys. Can be used to partition the keyspace.
599
600L<Catalyst::Plugin::Cache::ControllerNamespacing> - wrap backend objects in a
c627df81 601name mangler so that every controller gets its own keyspace.
772299b1 602
c28ee69c 603=cut
604
605