File Coverage

blib/lib/Class/DBI/ObjectCache.pm
Criterion Covered Total %
statement 15 76 19.7
branch 0 38 0.0
condition 0 11 0.0
subroutine 5 14 35.7
pod 8 8 100.0
total 28 147 19.0


line stmt bran cond sub pod time code
1             package Class::DBI::ObjectCache;
2              
3 1     1   4 use strict;
  1         2  
  1         26  
4 1     1   3 use warnings;
  1         1  
  1         21  
5 1     1   705 use Cache::Cache qw( $EXPIRES_NOW $EXPIRES_NEVER );
  1         294  
  1         100  
6 1     1   764 use Cache::FileCache;
  1         64873  
  1         59  
7 1     1   943 use CLASS;
  1         329  
  1         5  
8              
9             our $VERSION = 0.03;
10             our %CACHE_OBJ = ();
11              
12             =head1 NAME
13              
14             Class::DBI::ObjectCache - Object cache used by Class::DBI::Cacheable
15              
16             =head1 SYNOPSIS
17              
18             package YourClass::Name;
19             use base "Class::DBI::ObjectCache";
20              
21             sub get {
22             my $self = shift;
23             if ($self->can('getCache')) {
24             my $obj = $self->getCache(@_);
25             return $obj if (defined($obj));
26             }
27             # Do your magic to construct your object
28             }
29              
30             sub set {
31             my $self = shift;
32             $self->setCache();
33             }
34              
35             =head1 DESCRIPTION
36              
37             This method is a generic base-class used for storing and retrieving objects
38             to and from a L framework. This is extended by L
39             to provide transparent L caching support, though it can be used
40             for other types of objects as well.
41              
42             =head1 Method Reference
43              
44             =cut
45              
46             =head2 CLASS->getCacheKey( [$data] )
47              
48             This method composes a unique key to represent this cache with. This
49             is used when storing the object in the cache, and for later retrieving
50             it.
51              
52             =cut
53              
54             sub getCacheKey {
55 0     0 1   my $class = shift;
56 0           my $data = undef;
57 0 0         if (ref($class)) {
58 0           $data = $class;
59 0           $class = ref($class);
60             } else {
61 0           $data = shift;
62             }
63              
64 0           my @index_fields = ();
65             # Attempt to pull the indexable fields from the class' index method
66 0 0         if ($class->can('CACHE_INDEX')) {
    0          
67 0           @index_fields = $class->CACHE_INDEX();
68 0 0         @index_fields = @{$index_fields[0]} if (ref($index_fields[0]) eq 'ARRAY');
  0            
69             }
70            
71             # Since that didn't work, check to see if this object is a Class::DBI
72             # object, and retrieve the primary key columns from there.
73             elsif ($class->isa('Class::DBI')) {
74 0           @index_fields = sort $class->primary_columns;
75 0 0         if (ref($data) eq 'ARRAY') {
76 0           my @data_ary = @{$data};
  0            
77 0           $data = {};
78 0           foreach ($class->primary_columns) {
79 0           $data->{$_} = shift @data_ary;
80             }
81             }
82             }
83            
84             # None of that worked. This seems to be a generic object that hasn't been
85             # tuned for this framework. Assume all the keys are primary keys, and index
86             # based on that.
87             else {
88 0           @index_fields = sort keys %{$data};
  0            
89             }
90              
91             # Derive the key values to use as the index, and compose a unique string
92             # representing this object's state.
93 0           my @key_values = ();
94 0           foreach (@index_fields) {
95 0 0         return undef unless (exists $data->{$_});
96 0           push @key_values, $data->{$_};
97             }
98 0           my $key_str = join(':', @key_values);
99              
100             # Return a new cache key for this data
101 0           my $key = new Class::DBI::Cachable::IndexKey(key => $key_str);
102 0           return $key;
103             }
104              
105              
106             =head2 CLASS->getCache( $key )
107              
108             This method attempts to retrieve an object with the given
109             key from the cache. Returns undef if no valid value exists,
110             or if the supplied key is invalid.
111              
112             =cut
113              
114             sub getCache {
115 0     0 1   my $class = shift;
116 0           my $key = shift;
117 0 0         $class = ref($class) if (ref($class));
118              
119             # If the supplied key is not a valid IndexKey object, retrieve
120             # the cache key for it.
121 0 0         unless (UNIVERSAL::isa($key, 'Class::DBI::Cachable::IndexKey')) {
122 0           $key = $class->getCacheKey($key);
123             }
124              
125             # If the key is valid, pull the value out of the local cache
126             # and return what, if anything, it gives us.
127 0 0         if (defined($key->{key})) {
128 0 0         return unless defined($class->CACHE);
129 0           return $class->CACHE->get($key->{key});
130             }
131 0           return undef;
132             }
133              
134             =head2 $obj->setCache( [$key] )
135              
136             Store this object in the cache with the optionally supplied key.
137             If no key is supplied, one is computed automatically.
138              
139             =cut
140              
141             sub setCache {
142 0     0 1   my $self = shift;
143 0   0       my $key = shift || $self->getCacheKey;
144              
145 0 0         return unless defined($self->CACHE);
146              
147             # Remove the old key first, since the contents may have changed.
148 0           $self->CACHE->remove($key->{key});
149              
150             # Set the new key with the current object
151 0           $self->CACHE->set($self->getCacheKey->{key}, $self, $self->EXPIRES());
152             }
153              
154             =head2 $obj->removeCache( [$key] )
155              
156             Remove this object from the cache with the optionally supplied key.
157             If no key is supplied, one is computed automatically.
158              
159             =cut
160              
161             sub removeCache {
162 0     0 1   my $self = shift;
163 0   0       my $key = shift || $self->getCacheKey;
164              
165 0 0         return unless defined($self->CACHE);
166              
167             # Remove the old key first, since the contents may have changed.
168 0           $self->CACHE->remove($key->{key});
169             }
170              
171             =head2 CACHE()
172              
173             Class method that stores and returns L objects.
174              
175             Note: This implementation
176             uses L to store objects in the cache framework. If you want to use
177             some other back-end cache store, like a database or shared memory, subclass this
178             class and override this method.
179              
180             =cut
181              
182             sub CACHE {
183 0     0 1   my $self = shift;
184 0   0       my $class = ref($self) || $self;
185              
186             # To save time and effort, return a cache object that
187             # had previously been constructed if one is available.
188 0 0         return $CACHE_OBJ{$class} if (exists ($CACHE_OBJ{$class}));
189              
190             # Since no pre-defined cache object is available, construct
191             # one using the class methods that define the root, etc.
192 0           eval {
193 0 0         $CACHE_OBJ{$class} = new Cache::FileCache({
    0          
    0          
    0          
    0          
194             cache_root => $class->can('CACHE_ROOT')
195             ? $class->CACHE_ROOT()
196             : '/tmp/' . $CLASS,
197             cache_depth => $class->can('CACHE_DEPTH')
198             ? $class->CACHE_DEPTH()
199             : 0,
200             namespace => $class,
201             default_expires_in => $class->can('EXPIRES')
202             ? $class->EXPIRES()
203             : $EXPIRES_NEVER,
204             auto_purge_interval => $class->can('CACHE_PURGE_INTERVAL')
205             ? $class->CACHE_PURGE_INTERVAL()
206             : 600,
207             #max_size => $class->can('CACHE_SIZE')
208             # ? $class->CACHE_SIZE()
209             # : 20000,
210             }) or return undef;
211             };
212 0 0         if ($@) {
213 0           return undef;
214             }
215              
216             # Return the cache object
217 0           return $CACHE_OBJ{$class};
218             }
219              
220             =head2 EXPIRES()
221              
222             Indicates the default expire time for any object stored in the cache. Override this in
223             your subclass to indicate specific expirey times.
224              
225             Since this method is invoked every time an object is added to the datastore, you can return
226             different expire durations on a per-object basis, simply by implementing some logic in this
227             method.
228              
229             Default: 600 seconds
230              
231             =cut
232              
233             sub EXPIRES {
234 0     0 1   return 600;
235             }
236              
237             =head2 CACHE_ROOT()
238              
239             Indicates the directory where objects will be stored on disk. Override this if you wish
240             different applications, classes or sets of classes to be stored in their own cache directory.
241              
242             Default: /tmp/Object-Cache
243              
244             =cut
245              
246             sub CACHE_ROOT {
247 0     0 1   return '/tmp/Object-Cache';
248             }
249              
250             =head2 CACHE_DEPTH()
251              
252             Indicates the directory depth that will be created for storing cached files.
253              
254             Default: 4
255              
256             =cut
257              
258             sub CACHE_DEPTH {
259 0     0 1   return 4;
260             }
261              
262             package Class::DBI::Cachable::IndexKey;
263             sub new {
264 0     0     my $pkg = shift;
265 0   0       my $class = ref($pkg) || $pkg || __PACKAGE__;
266 0           my %args = @_;
267 0           my $self = {
268             key => $args{key},
269             };
270              
271 0           return bless $self, $class;
272             }
273              
274             =head1 SEE ALSO
275              
276             L, L, L
277              
278             =head1 AUTHOR
279              
280             Michael A Nachbaur, Emike@nachbaur.comE
281              
282             =head1 COPYRIGHT AND LICENSE
283              
284             This library is free software; you can redistribute it and/or modify
285             it under the same terms as Perl itself.
286              
287             =cut
288             1;