File Coverage

blib/lib/Cache/CacheFactory.pm
Criterion Covered Total %
statement 213 346 61.5
branch 73 144 50.6
condition 8 32 25.0
subroutine 46 72 63.8
pod 54 54 100.0
total 394 648 60.8


line stmt bran cond sub pod time code
1             ###############################################################################
2             # Purpose : Generic Cache Factory with various policy factories.
3             # Author : Sam Graham
4             # Created : 23 Jun 2008
5             # CVS : $Id: CacheFactory.pm,v 1.25 2010-02-16 12:25:40 illusori Exp $
6             ###############################################################################
7              
8             package Cache::CacheFactory;
9              
10 10     10   266156 use warnings;
  10         25  
  10         333  
11 10     10   56 use strict;
  10         16  
  10         324  
12              
13 10     10   50 use Carp;
  10         24  
  10         689  
14              
15 10     10   8783 use Cache::Cache;
  10         3614  
  10         402  
16              
17 10     10   5518 use Cache::CacheFactory::Storage;
  10         27  
  10         655  
18 10     10   5863 use Cache::CacheFactory::Expiry;
  10         24  
  10         234  
19 10     10   5007 use Cache::CacheFactory::Object;
  10         30  
  10         341  
20              
21 10     10   78 use base qw/Cache::Cache/;
  10         23  
  10         39403  
22              
23             $Cache::CacheFactory::VERSION = '1.10';
24              
25             $Cache::CacheFactory::NO_MAX_SIZE = -1;
26              
27             @Cache::CacheFactory::EXPORT = qw();
28             @Cache::CacheFactory::EXPORT_OK = qw(
29             best_available_storage_policy
30             best_available_pruning_policy
31             best_available_validity_policy
32             $NO_MAX_SIZE
33             );
34             %Cache::CacheFactory::EXPORT_TAGS = (
35             best_available => [ qw(
36             best_available_storage_policy
37             best_available_pruning_policy
38             best_available_validity_policy
39             ) ],
40             );
41              
42              
43             sub new
44             {
45 11     11 1 1228723 my $class = shift;
46 11         28 my ( $self, %options );
47              
48 11 50       91 %options = ref( $_[ 0 ] ) ? %{$_[ 0 ]} : @_;
  0         0  
49              
50 11         59 $self = { policies => {}, compat => {}, };
51 11   33     102 bless $self, ( ref( $class ) || $class );
52              
53             #
54             # Compat options with Cache::Cache subclasses.
55 11   100     120 $self->{ namespace } = $options{ namespace } || 'Default';
56              
57             #
58             # Compat with Cache::Cache.
59             $self->{ compat }->{ default_expires_in } = $options{ default_expires_in }
60 11 50       71 if exists $options{ default_expires_in };
61              
62             #
63             # Cache-wide settings.
64             $self->set_positional_set( $options{ positional_set } )
65 11 50       46 if exists $options{ positional_set };
66              
67             # Control first-run eligibility for auto-purging.
68             $self->set_last_auto_purge( $options{ last_auto_purge } )
69 11 50       45 if defined( $options{ last_auto_purge } );
70              
71             # Auto-purge intervals.
72             $self->set_auto_purge_interval( $options{ auto_purge_interval } )
73 11 50       47 if exists $options{ auto_purge_interval };
74             $self->set_auto_purge_on_set_interval(
75             $options{ auto_purge_on_set_interval } )
76 11 50       44 if exists $options{ auto_purge_on_set_interval };
77             $self->set_auto_purge_on_get_interval(
78             $options{ auto_purge_on_get_interval } )
79 11 50       44 if exists $options{ auto_purge_on_get_interval };
80              
81             # Auto-purge toggles.
82             $self->set_auto_purge_on_set( $options{ auto_purge_on_set } )
83 11 50       42 if exists $options{ auto_purge_on_set };
84             $self->set_auto_purge_on_get( $options{ auto_purge_on_get } )
85 11 50       41 if exists $options{ auto_purge_on_get };
86              
87             # Do we quietly (or silently) fail on missing policies?
88             $self->{ nonfatal_missing_policies } = 1
89 11 50       42 if $options{ nonfatal_missing_policies };
90             $self->{ nonwarning_missing_policies } = 1
91 11 50       40 if $options{ nonwarning_missing_policies };
92              
93             # Do we deeply clone our data when setting it?
94             $self->{ no_deep_clone } = 1
95 11 100       41 if $options{ no_deep_clone };
96              
97             #
98             # Grab our policies from the options.
99 11         60 $self->set_storage_policies( $options{ storage } );
100             $self->set_pruning_policies( $options{ pruning } )
101 11 100       50 if $options{ pruning };
102             $self->set_validity_policies( $options{ validity } )
103 11 100       50 if $options{ validity };
104              
105 11 50       25 if( $#{$self->{ policies }->{ storage }->{ order }} == -1 )
  11         58  
106             {
107             # OK, we've got no storage policies, we only get this
108             # far if nonfatal_missing_policies has been set.
109             # Either way it's a fatal error for a cache, so we
110             # return an undef.
111             $self->warning( "No valid storage policies supplied" )
112 0 0       0 unless $self->{ nonwarning_missing_policies };
113 0         0 return( undef );
114             }
115              
116 11         105 return( $self );
117             }
118              
119             sub new_cache_entry_object
120             {
121             # my ( $self ) = @_;
122 79     79 1 372 return( Cache::CacheFactory::Object->new() );
123             }
124              
125             sub set
126             {
127 103     103 1 3421 my $self = shift;
128 103         117 my ( $param, $object, $key, $data, $mode );
129              
130             # Aiii, backwards-compat with Cache::Cache->set().
131 103 50 0     366 if( $self->{ compat }->{ positional_set } and
      33        
132             ( ( $self->{ compat }->{ positional_set } ne 'auto' ) or
133             ( $_[ 0 ] ne 'key' ) ) )
134             {
135 0         0 my ( $next_arg, $expires_in );
136              
137 0         0 $key = shift;
138 0         0 $data = shift;
139 0         0 $expires_in = shift;
140 0         0 $param = {};
141 0 0       0 if( defined( $next_arg = shift ) )
142             {
143             # Hackery to support mode from add()/replace().
144 0 0       0 if( $next_arg eq 'mode' )
145             {
146 0         0 $mode = shift;
147             }
148             else
149             {
150 0         0 $param->{ expires_in } = $expires_in;
151             # TODO: warn if expires set and not time policy?
152             }
153             }
154 0 0 0     0 $mode = shift if defined( $next_arg = shift ) and $next_arg eq 'mode';
155             }
156             else
157             {
158 103 50       486 $param = ref( $_[ 0 ] ) ? { %{$_[ 0 ]} } : { @_ };
  0         0  
159 103 50       235 if( exists( $param->{ key } ) )
160             {
161 103         148 $key = $param->{ key };
162 103         182 delete $param->{ key };
163             }
164             else
165             {
166 0         0 warn "No key supplied to ${self}->set(), are you calling it " .
167             "with compat-style positional parameters but haven't set " .
168             "the positional_set option?";
169 0         0 return;
170             }
171 103 50       204 if( exists( $param->{ data } ) )
172             {
173 103         132 $data = $param->{ data };
174 103         154 delete $param->{ data };
175             }
176             else
177             {
178 0         0 warn "No data supplied to ${self}->set(), are you calling it " .
179             "with compat-style positional parameters but haven't set " .
180             "the positional_set option?";
181 0         0 return;
182             }
183 103 100       255 if( exists( $param->{ mode } ) )
184             {
185 48         69 $mode = $param->{ mode };
186 48         76 delete $param->{ mode };
187             }
188             }
189              
190 103 100       192 if( $mode )
191             {
192 48 100       90 if( $self->exists( $key ) )
193             {
194 18 100       61 return if $mode eq 'add';
195             }
196             else
197             {
198 30 100       93 return if $mode eq 'replace';
199             }
200             }
201              
202 79 50       256 $param->{ created_at } = time() unless $param->{ created_at };
203 79 100       181 $param->{ no_deep_clone } = 1 if $self->{ no_deep_clone };
204              
205             # Create Cache::CacheFactory::Object instance.
206 79         177 $object = $self->new_cache_entry_object();
207              
208             # Initialize it from the param.
209 79         892 $object->initialize( $key, $data, $param );
210              
211 79         212 $self->foreach_driver( 'validity', 'set_object_validity',
212             $key, $object, $param );
213 79         180 $self->foreach_driver( 'pruning', 'set_object_pruning',
214             $key, $object, $param );
215 79 100       161 if( $param->{ no_deep_clone } )
216             {
217             # Since most Cache::Cache's do their own deep cloning
218             # we try a bit of a hack to try to bypass that.
219             $self->foreach_policy( 'storage',
220             sub
221             {
222 4     4   7 my ( $self, $policy, $storage ) = @_;
223              
224             # Only try this hack on things that subclass behaviour
225             # we understand.
226 4 50       23 if( $storage->isa( 'Cache::BaseCache' ) )
227             {
228 4         5 my ( $backend );
229              
230 4 50       13 if( $backend = $storage->_get_backend() )
231             {
232 4         32 $object->set_size( undef );
233 4         24 $object->set_key( undef );
234              
235 4         21 $backend->store( $storage->get_namespace(),
236             $key, $object );
237 4         53 return;
238             }
239             }
240              
241             # Ok, we couldn't figure out how to do our dirty hack...
242 0         0 $storage->set_object( $key, $object, $param );
243 4         27 } );
244             }
245             else
246             {
247 75         150 $self->foreach_driver( 'storage', 'set_object',
248             $key, $object, $param );
249             }
250              
251 79         258 $self->auto_purge( 'set' );
252             }
253              
254             sub get
255             {
256 145     145 1 3012800 my ( $self, $key ) = @_;
257 145         152 my ( $object );
258              
259 145         271 my $storage_policies = $self->{ policies }->{ storage };
260 145         214 my $validity_policies = $self->{ policies }->{ validity };
261 145         164 foreach my $storage_policy ( @{$storage_policies->{ order }} )
  145         300  
262             {
263 145         218 my $storage = $storage_policies->{ drivers }->{ $storage_policy };
264 145 100       436 next unless defined( $object = $storage->get_object( $key ) );
265              
266 79         11075 foreach my $validity_policy ( @{$validity_policies->{ order }} )
  79         246  
267             {
268 11 100       64 next if $validity_policies->{ drivers }->{ $validity_policy }->is_valid( $self, $storage, $object );
269             # TODO: should remove from this storage. optionally?
270 4         12 undef $object;
271 4         24 last;
272             }
273 79 100       252 last if defined $object;
274             }
275              
276             # Check of auto_purge_on_get isn't strictly neccessary but
277             # it saves the cost of a method call in the failure case.
278 145 50       2357 $self->auto_purge( 'get' ) if $self->{ auto_purge_on_get };
279              
280 145 100       492 return( $object->get_data() ) if defined $object;
281 70         371 return( undef );
282             }
283              
284             sub get_object
285             {
286 0     0 1 0 my ( $self, $key ) = @_;
287 0         0 my ( $object );
288              
289             $self->foreach_policy( 'storage',
290             sub
291             {
292 0     0   0 my ( $self, $policy, $storage ) = @_;
293              
294 0         0 $object = $storage->get_object( $key );
295 0 0       0 $self->last() if defined $object;
296 0         0 } );
297              
298 0         0 return( $object );
299             }
300              
301             sub set_object
302             {
303 0     0 1 0 my ( $self, $key, $object ) = @_;
304              
305             # Backwards compat with Cache::Object objects.
306 0 0       0 unless( $object->isa( 'Cache::CacheFactory::Object' ) )
307             {
308 0         0 my ( $param );
309              
310 0         0 $param = {};
311 0 0       0 $param->{ no_deep_clone } = 1 if $self->{ no_deep_clone };
312 0         0 $object = Cache::CacheFactory::Object->new_from_old( $object, $param );
313             # TODO: compat with expires_at
314             }
315              
316 0         0 $self->foreach_driver( 'storage', 'set_object', $key, $object );
317             }
318              
319             sub remove
320             {
321 42     42 1 13419 my ( $self, $key ) = @_;
322              
323 42         101 $self->foreach_driver( 'storage', 'remove', $key );
324             }
325              
326             #
327             # CacheFactory extensions.
328             sub exists
329             {
330 60     60 1 5682 my ( $self, $key ) = @_;
331 60         63 my ( $exists );
332              
333             $self->foreach_policy( 'storage',
334             sub
335             {
336 60     60   78 my ( $self, $policy, $storage ) = @_;
337              
338             # If they've implemented an exists method, use it,
339             # otherwise just do it the slow way.
340 60 50       228 if( $storage->can( 'exists' ) )
341             {
342 0         0 $exists = $storage->exists( $key );
343             }
344             else
345             {
346 60         162 $exists = defined( $storage->get_object( $key ) );
347             }
348              
349 60 100       6292 return $self->last() if $exists;
350 60         308 } );
351              
352 60 100       378 return( $exists ? 1 : 0 );
353             }
354              
355              
356             #
357             # These following provide Cache::Memcached style interface.
358             # get_multi(), incr() and decr() cannot be "properly" implemented
359             # to use underlying functions because our object wrapper prevents
360             # the operations being single calls to the storage policy's
361             # implementation (if they have one), this then directly negates
362             # the purpose of these methods existing in the first place.
363             sub delete
364             {
365 12     12 1 6689 my ( $self, $key ) = @_;
366              
367 12         32 $self->remove( $key );
368             }
369              
370             sub add
371             {
372 24     24 1 4870 my $self = shift;
373              
374 24         56 $self->set( @_, mode => 'add' );
375             }
376              
377             sub replace
378             {
379 24     24 1 6694 my $self = shift;
380              
381 24         58 $self->set( @_, mode => 'replace' );
382             }
383              
384             #
385             #sub get_multi
386             #{
387             # my ( $self, @keys ) = @_;
388             #}
389              
390             #sub incr
391             #{
392             # my ( $self, $key, $value ) = @_;
393             #}
394              
395             #sub decr
396             #{
397             # my ( $self, $key, $value ) = @_;
398             #}
399              
400             sub Clear
401             {
402 0     0 1 0 my ( $self, @args ) = @_;
403              
404 0         0 $self->foreach_driver( 'storage', 'Clear', @args );
405             }
406              
407             sub clear
408             {
409 8     8 1 8653 my ( $self, @args ) = @_;
410              
411 8         50 $self->foreach_driver( 'storage', 'clear', @args );
412             }
413              
414             sub Purge
415             {
416 0     0 1 0 my ( $self, @args ) = @_;
417              
418 0         0 $self->purge( @args );
419             }
420              
421             sub purge
422             {
423 8     8 1 4775 my ( $self, @args ) = @_;
424              
425 8         35 $self->foreach_driver( 'pruning', 'purge', $self, @args );
426             }
427              
428             sub auto_purge
429             {
430 79     79 1 119 my ( $self, $set_or_get ) = @_;
431              
432 79 50       499 return unless $self->{ "auto_purge_on_${set_or_get}" };
433              
434             return if $self->{ last_auto_purge } >=
435 0 0       0 time() - $self->{ "auto_purge_${set_or_get}_interval" };
436              
437             # Set timestamp before purge in case we bomb out.
438             # Ideally we should do some manner of locking to prevent
439             # concurrent purges.
440             # Maybe that's the application's business instead.
441 0         0 $self->{ last_auto_purge } = time();
442              
443 0         0 $self->purge();
444              
445             # Update timestamp after purge so we don't spinlock if the purge
446             # takes longer than the interval.
447 0         0 $self->{ last_auto_purge } = time();
448             }
449              
450             sub Size
451             {
452 4     4 1 1629 my ( $self, @args ) = @_;
453 4         6 my ( $size );
454              
455 4         5 $size = 0;
456             $self->foreach_policy( 'storage',
457             sub
458             {
459 4     4   5 my ( $self, $policy, $driver ) = @_;
460              
461             # Cache::FastMemoryCache 0.01 dies on Size(), workaround.
462 4 100       32 return if $driver->isa( 'Cache::FastMemoryCache' );
463 3         18 $size += $driver->Size( @args );
464 4         24 } );
465              
466 4         20 return( $size );
467             }
468              
469             sub size
470             {
471 4     4 1 1682 my ( $self ) = @_;
472 4         8 my ( $size );
473              
474 4         7 $size = 0;
475             $self->foreach_policy( 'storage',
476             sub
477             {
478 4     4   7 my ( $self, $policy, $driver ) = @_;
479              
480 4         29 $size += $driver->size();
481 4         26 } );
482              
483 4         19 return( $size );
484             }
485              
486             sub get_namespaces
487             {
488 4     4 1 9 my ( $self ) = @_;
489 4         6 my ( %namespaces );
490              
491 4         8 %namespaces = ();
492             $self->foreach_policy( 'storage',
493             sub
494             {
495 4     4   6 my ( $self, $policy, $driver ) = @_;
496              
497             # Cache::NullCache->get_namespaces() dies, workaround it.
498 4 100       61 return $self->last() if $driver->isa( 'Cache::NullCache' );
499 3         23 foreach my $namespace ( $driver->get_namespaces() )
500             {
501 4         301 $namespaces{ $namespace }++;
502             }
503 4         27 } );
504              
505 4         26 return( keys( %namespaces ) );
506             }
507              
508             sub get_keys
509             {
510 8     8 1 38 my ( $self ) = @_;
511 8         9 my ( %keys );
512              
513 8         14 %keys = ();
514             $self->foreach_policy( 'storage',
515             sub
516             {
517 8     8   13 my ( $self, $policy, $driver ) = @_;
518              
519 8         42 foreach my $key ( $driver->get_keys() )
520             {
521 18         4664 $keys{ $key }++;
522             }
523 8         48 } );
524              
525 8         90 return( keys( %keys ) );
526             }
527              
528             sub get_identifiers
529             {
530 4     4 1 9 my ( $self ) = @_;
531              
532 4         10 return( $self->get_keys() );
533             }
534              
535              
536              
537             sub set_positional_set
538             {
539 0     0 1 0 my ( $self, $positional_set ) = @_;
540              
541 0         0 $self->{ compat }->{ positional_set } = $positional_set;
542             }
543              
544             sub get_positional_set
545             {
546 0     0 1 0 my ( $self ) = @_;
547              
548 0         0 return( $self->{ compat }->{ positional_set } );
549             }
550              
551             sub set_default_expires_in
552             {
553 0     0 1 0 my ( $self, $default_expires_in ) = @_;
554 0         0 my ( $time_pruning, $time_validity );
555              
556 0         0 $time_pruning = $self->get_policy_driver( 'pruning', 'time' );
557 0         0 $time_validity = $self->get_policy_driver( 'validity', 'time' );
558              
559 0 0 0     0 unless( $time_pruning or $time_validity )
560             {
561 0         0 carp "Cannot set_default_expires_in() when neither a pruning nor " .
562             "a validity policy of 'time' is set.";
563 0         0 return;
564             }
565              
566 0 0       0 $time_pruning->set_default_expires_in( $default_expires_in )
567             if $time_pruning;
568 0 0       0 $time_validity->set_default_expires_in( $default_expires_in )
569             if $time_validity;
570             }
571              
572             sub get_default_expires_in
573             {
574 0     0 1 0 my ( $self ) = @_;
575 0         0 my ( $time_pruning, $time_validity );
576              
577 0         0 $time_pruning = $self->get_policy_driver( 'pruning', 'time' );
578 0         0 $time_validity = $self->get_policy_driver( 'validity', 'time' );
579              
580 0 0 0     0 unless( $time_pruning or $time_validity )
581             {
582 0         0 carp "Cannot get_default_expires_in() when neither a pruning nor " .
583             "a validity policy of 'time' is set.";
584 0         0 return( undef );
585             }
586              
587             # If they have both set, we go with the validity one since that's
588             # generally the one that has more immediate effect.
589             # If they're setting it via default_expires_in then both should
590             # be the same anyway...
591 0 0       0 return( $time_validity->get_default_expires_in() ) if $time_validity;
592 0 0       0 return( $time_pruning->get_default_expires_in() ) if $time_pruning;
593             }
594              
595             sub limit_size
596             {
597 0     0 1 0 my ( $self, $size ) = @_;
598 0         0 my ( $size_policy );
599              
600 0         0 $size_policy = $self->get_policy_driver( 'pruning', 'size' );
601              
602 0 0       0 unless( $size_policy )
603             {
604 0         0 carp "Cannot limit_size() when no 'size' pruning policy is set.";
605 0         0 return;
606             }
607              
608 0         0 $size_policy->limit_size( $self, $size );
609             }
610              
611             sub set_last_auto_purge
612             {
613 0     0 1 0 my ( $self, $last_auto_purge ) = @_;
614              
615             $self->{ last_auto_purge } =
616 0 0       0 ( $last_auto_purge eq 'now' ) ? time() : $last_auto_purge;
617             }
618              
619             sub get_last_auto_purge
620             {
621 0     0 1 0 my ( $self ) = @_;
622              
623 0         0 return( $self->{ last_auto_purge } );
624             }
625              
626             sub set_auto_purge_on_set
627             {
628 0     0 1 0 my ( $self, $auto_purge_on_set ) = @_;
629              
630 0         0 $self->{ auto_purge_on_set } = $auto_purge_on_set;
631             }
632              
633             sub get_auto_purge_on_set
634             {
635 0     0 1 0 my ( $self ) = @_;
636              
637 0         0 return( $self->{ auto_purge_on_set } );
638             }
639              
640             sub set_auto_purge_on_get
641             {
642 0     0 1 0 my ( $self, $auto_purge_on_get ) = @_;
643              
644 0         0 $self->{ auto_purge_on_get } = $auto_purge_on_get;
645             }
646              
647             sub get_auto_purge_on_get
648             {
649 0     0 1 0 my ( $self ) = @_;
650              
651 0         0 return( $self->{ auto_purge_on_get } );
652             }
653              
654             sub set_auto_purge_interval
655             {
656 0     0 1 0 my ( $self, $auto_purge_interval ) = @_;
657              
658 0         0 $self->set_auto_purge_on_set_interval( $auto_purge_interval );
659 0         0 $self->set_auto_purge_on_get_interval( $auto_purge_interval );
660             }
661              
662             sub get_auto_purge_interval
663             {
664 0     0 1 0 my ( $self ) = @_;
665              
666 0   0     0 return( $self->get_auto_purge_on_get_interval() ||
667             $self->get_auto_purge_on_set_interval() );
668             }
669              
670             sub set_auto_purge_on_set_interval
671             {
672 0     0 1 0 my ( $self, $auto_purge_interval ) = @_;
673              
674 0         0 $self->{ auto_purge_on_set_interval } = $auto_purge_interval;
675             }
676              
677             sub get_auto_purge_on_set_interval
678             {
679 0     0 1 0 my ( $self ) = @_;
680              
681 0         0 return( $self->{ auto_purge_on_set_interval } );
682             }
683              
684             sub set_auto_purge_on_get_interval
685             {
686 0     0 1 0 my ( $self, $auto_purge_interval ) = @_;
687              
688 0         0 $self->{ auto_purge_on_get_interval } = $auto_purge_interval;
689             }
690              
691             sub get_auto_purge_on_get_interval
692             {
693 0     0 1 0 my ( $self ) = @_;
694              
695 0         0 return( $self->{ auto_purge_on_get_interval } );
696             }
697              
698             sub set_namespace
699             {
700 8     8 1 479 my ( $self, $namespace ) = @_;
701              
702 8         12 $self->{ namespace } = $namespace;
703 8         17 $self->foreach_driver( 'storage', 'set_namespace', $namespace );
704             }
705              
706             sub get_namespace
707             {
708 2     2 1 3 my ( $self ) = @_;
709              
710 2         10 return( $self->{ namespace } );
711             }
712              
713             # Coerce the policy arg into a hashref and ordered param list.
714             sub _normalize_policies
715             {
716 16     16   28 my ( $self, $policies ) = @_;
717              
718             return( {
719 16 100       112 order => [ $policies ],
720             param => { $policies => {} },
721             } )
722             unless ref( $policies );
723             return( {
724 2 50       7 order => [ keys( %{$policies} ) ],
  2         27  
725             param => $policies,
726             } )
727             if ref( $policies ) eq 'HASH';
728 0 0       0 if( ref( $policies ) eq 'ARRAY' )
729             {
730 0         0 my ( $ret );
731              
732 0         0 $self->error( "Policy arg wasn't even-sized arrayref" )
733 0 0       0 unless $#{$policies} % 2;
734              
735 0         0 $ret = { order => [], param => {} };
736 0         0 for( my $i = 0; $i <= $#{$policies}; $i += 2 )
  0         0  
737             {
738 0         0 push @{$ret->{ order }}, $policies->[ $i ];
  0         0  
739 0         0 $ret->{ param }->{ $policies->[ $i ] } = $policies->[ $i + 1 ];
740             }
741              
742 0         0 return( $ret );
743             }
744 0         0 $self->error( "Unknown policy format: " . ref( $policies ) );
745             }
746              
747             sub set_policy
748             {
749 16     16 1 35 my ( $self, $policytype, $policies ) = @_;
750 16         30 my ( $factoryclass );
751              
752 16 50       45 $self->error( "No $policytype policy set" ) unless $policies;
753              
754 16         59 $policies = $self->_normalize_policies( $policies );
755 16         66 $self->{ policies }->{ $policytype } = $policies;
756              
757 16 100       73 $factoryclass = 'Cache::CacheFactory::' .
758             ( $policytype eq 'storage' ? 'Storage' : 'Expiry' );
759              
760             # Handle compat param.
761             $policies->{ param }->{ time }->{ default_expires_in } =
762             $self->{ compat }->{ default_expires_in }
763             if exists $self->{ compat }->{ default_expires_in } and
764             $policies->{ param }->{ time } and
765 16 0 33     90 not exists $policies->{ param }->{ time }->{ default_expires_in };
      33        
766              
767 16         52 $policies->{ drivers } = {};
768 16         30 foreach my $policy ( @{$policies->{ order }} )
  16         51  
769             {
770 16         30 my ( $driver, $param );
771              
772 16         36 $param = $policies->{ param }->{ $policy };
773 16         78 delete $policies->{ param }->{ $policy };
774              
775             # Ensure we set the namespace if one isn't set explicitly.
776             $param->{ namespace } = $self->{ namespace }
777 16 100 66     120 if $policytype eq 'storage' and not exists $param->{ namespace };
778              
779 16         146 $driver = $factoryclass->new( $policy, $param );
780 16 50       1879 if( $driver )
781             {
782 16         109 $policies->{ drivers }->{ $policy } = $driver;
783             }
784             else
785             {
786 0         0 my ( $driver_module, $error );
787              
788 0         0 $driver_module = $factoryclass->get_registered_class( $policy );
789 0         0 $error = "Unable to load driver for $policytype policy: $policy";
790 0 0       0 if( $driver_module )
791             {
792 0         0 $error .= "; is $driver_module installed?";
793             }
794             else
795             {
796 0         0 $error .= "; is '$policy' a typo, or a custom policy that " .
797             "hasn't been registered with $factoryclass?";
798             }
799 0 0       0 if( $self->{ nonfatal_missing_policies } )
800             {
801             $self->warning( $error )
802 0 0       0 unless $self->{ nonwarning_missing_policies };
803             }
804             else
805             {
806 0         0 $self->error( $error );
807             }
808             # Prune it from the policy run order.
809             $policies->{ order } =
810 0         0 [ grep { $_ ne $policy } @{$policies->{ order }} ];
  0         0  
  0         0  
811             }
812              
813             }
814             }
815              
816             sub get_policy_driver
817             {
818 1     1 1 4 my ( $self, $policytype, $policy ) = @_;
819              
820 1         7 return( $self->{ policies }->{ $policytype }->{ drivers }->{ $policy } );
821             }
822             sub get_policy_drivers
823             {
824 0     0 1 0 my ( $self, $policytype ) = @_;
825              
826 0         0 return( $self->{ policies }->{ $policytype }->{ drivers } );
827             }
828              
829             #
830             #
831             # Next few methods run a closure against each policy or invoke a
832             # method against each policy's driver. It's a bit inefficient but
833             # saves on duplicating the same ordering and looping code everywhere
834             # and keeps me sane(ish). Oh for a native ordered-hashref.
835             sub last
836             {
837             # my ( $self ) = @_;
838 28     28 1 83 $_[ 0 ]->{ _last } = 1;
839             }
840              
841             sub foreach_policy
842             {
843 90     90 1 134 my ( $self, $policytype, $closure ) = @_;
844              
845 90         153 my $policies = $self->{ policies }->{ $policytype };
846 90         96 foreach my $policy ( @{$policies->{ order }} )
  90         180  
847             {
848 90         234 $closure->( $self, $policy, $policies->{ drivers }->{ $policy } );
849 90 100       9498 next unless $self->{ _last };
850 28         45 delete $self->{ _last };
851 28         46 return;
852             }
853             }
854              
855             sub foreach_driver
856             {
857 299     299 1 574 my ( $self, $policytype, $method, @args ) = @_;
858              
859 299         481 my $policies = $self->{ policies }->{ $policytype };
860 299         310 foreach my $policy ( @{$policies->{ order }} )
  299         911  
861             {
862 148         671 $policies->{ drivers }->{ $policy }->$method( @args );
863 148 50       24196 next unless $self->{ _last };
864 0         0 delete $self->{ _last };
865 0         0 return;
866             }
867             }
868              
869             sub set_storage_policies
870             {
871 11     11 1 25 my ( $self, $policies ) = @_;
872              
873 11         53 $self->set_policy( 'storage', $policies );
874             }
875              
876             sub set_pruning_policies
877             {
878 3     3 1 7 my ( $self, $policies ) = @_;
879              
880 3         8 $self->set_policy( 'pruning', $policies );
881             }
882              
883             sub set_validity_policies
884             {
885 2     2 1 7 my ( $self, $policies ) = @_;
886              
887 2         7 $self->set_policy( 'validity', $policies );
888             }
889              
890             sub _error_message
891             {
892 0     0   0 my $self = shift;
893 0         0 my ( $error );
894              
895 0         0 $error = join( '', @_ );
896 0         0 return( "Cache error: $error" );
897             }
898              
899             sub error
900             {
901 0     0 1 0 my $self = shift;
902 0         0 die( $self->_error_message( @_ ) );
903             }
904              
905             sub warning
906             {
907 0     0 1 0 my $self = shift;
908 0         0 warn( $self->_error_message( @_ ) );
909             }
910              
911             #
912             #
913             # Non-OO functions.
914             #
915              
916             sub _best_available_policy
917             {
918 3     3   9 my ( $policytype, @policies ) = @_;
919 3         5 my ( $factoryclass );
920              
921 3 100       11 $factoryclass = 'Cache::CacheFactory::' .
922             ( $policytype eq 'storage' ? 'Storage' : 'Expiry' );
923 3         10 while( my $policy = shift( @policies ) )
924             {
925 3 50       33 return( $policy ) if $factoryclass->get_registered_class( $policy );
926             }
927 0         0 return( undef );
928             }
929              
930             sub best_available_storage_policy
931             {
932 1     1 1 236 return( _best_available_policy( 'storage', @_ ) );
933             }
934              
935             sub best_available_pruning_policy
936             {
937 1     1 1 3 return( _best_available_policy( 'pruning', @_ ) );
938             }
939              
940             sub best_available_validity_policy
941             {
942 1     1 1 4 return( _best_available_policy( 'validity', @_ ) );
943             }
944              
945              
946             1;
947              
948             __END__