File Coverage

blib/lib/CHI/CacheObject.pm
Criterion Covered Total %
statement 116 116 100.0
branch 23 24 95.8
condition 7 9 77.7
subroutine 32 32 100.0
pod 5 13 38.4
total 183 194 94.3


line stmt bran cond sub pod time code
1             package CHI::CacheObject;
2             $CHI::CacheObject::VERSION = '0.60';
3 20     20   116 use CHI::Constants qw(CHI_Max_Time);
  20         29  
  20         898  
4 20     20   11233 use Encode;
  20         163068  
  20         1608  
5 20     20   144 use strict;
  20         29  
  20         514  
6 20     20   83 use warnings;
  20         32  
  20         479  
7              
8 20     20   81 use constant f_key => 0;
  20         29  
  20         1130  
9 20     20   85 use constant f_raw_value => 1;
  20         28  
  20         762  
10 20     20   81 use constant f_serializer => 2;
  20         28  
  20         704  
11 20     20   85 use constant f_created_at => 3;
  20         35  
  20         767  
12 20     20   85 use constant f_early_expires_at => 4;
  20         27  
  20         782  
13 20     20   88 use constant f_expires_at => 5;
  20         859  
  20         928  
14 20     20   89 use constant f_is_transformed => 6;
  20         67  
  20         818  
15 20     20   80 use constant f_cache_version => 7;
  20         56  
  20         885  
16 20     20   98 use constant f_value => 8;
  20         34  
  20         806  
17 20     20   98 use constant f_packed_data => 9;
  20         40  
  20         836  
18 20     20   82 use constant f_size => 10;
  20         22  
  20         1040  
19              
20 20     20   86 use constant T_SERIALIZED => 1;
  20         35  
  20         767  
21 20     20   77 use constant T_UTF8_ENCODED => 2;
  20         23  
  20         796  
22 20     20   110 use constant T_COMPRESSED => 4;
  20         24  
  20         18920  
23              
24             my $Metadata_Format = "LLLCC";
25             my $Metadata_Length = 14;
26              
27             # Eschewing Moose and hash-based objects for this class to get the extra speed.
28             # Eventually will probably write in C anyway.
29              
30 3591     3591 1 13357 sub key { $_[0]->[f_key] }
31 288     288 1 1332 sub created_at { $_[0]->[f_created_at] }
32 204     204 0 1281 sub early_expires_at { $_[0]->[f_early_expires_at] }
33 4108     4108 1 14353 sub expires_at { $_[0]->[f_expires_at] }
34 3859     3859 0 11370 sub serializer { $_[0]->[f_serializer] }
35 52     52   282 sub _is_transformed { $_[0]->[f_is_transformed] }
36 5563     5563 0 95110 sub size { $_[0]->[f_size] }
37              
38             sub set_early_expires_at {
39 176     176 0 342 $_[0]->[f_early_expires_at] = $_[1];
40 176         373 undef $_[0]->[f_packed_data];
41             }
42              
43             sub set_expires_at {
44 176     176 0 255 $_[0]->[f_expires_at] = $_[1];
45 176         293 undef $_[0]->[f_packed_data];
46             }
47              
48             ## no critic (ProhibitManyArgs)
49             sub new {
50 3540     3540 0 6461 my ( $class, $key, $value, $created_at, $early_expires_at, $expires_at,
51             $serializer, $compress_threshold )
52             = @_;
53              
54             # Serialize/encode value if necessary - does this belong here, or in
55             # Driver.pm?
56             #
57 3540         3873 my $is_transformed = 0;
58 3540         4043 my $raw_value = $value;
59 3540         3572 my $size;
60 3540 100       6000 if ($serializer) {
61 3281 100       10418 if ( ref($raw_value) ) {
    100          
62 154         671 $raw_value = $serializer->serialize($raw_value);
63 154         7696 $is_transformed |= T_SERIALIZED;
64             }
65             elsif ( Encode::is_utf8($raw_value) ) {
66 73         293 $raw_value = Encode::encode( utf8 => $raw_value );
67 73         1679 $is_transformed |= T_UTF8_ENCODED;
68             }
69 3281 100 100     7942 if ( defined($compress_threshold)
70             && length($raw_value) > $compress_threshold )
71             {
72 6         4440 require Compress::Zlib;
73 6         310998 $raw_value = Compress::Zlib::memGzip($raw_value);
74 6         2129 $is_transformed |= T_COMPRESSED;
75             }
76 3281         5288 $size = length($raw_value) + $Metadata_Length;
77             }
78             else {
79 259         332 $size = 1;
80             }
81              
82             # Not sure where this should be set and checked
83             #
84 3540         3929 my $cache_version = 1;
85              
86 3540         18440 return bless [
87             $key, $raw_value, $serializer, $created_at,
88             $early_expires_at, $expires_at, $is_transformed, $cache_version,
89             $value, undef, $size
90             ], $class;
91             }
92              
93             sub unpack_from_data {
94 10039     10039 0 13860 my ( $class, $key, $data, $serializer ) = @_;
95              
96 10039 100       20800 return $data if !$serializer;
97 8810         14635 my $metadata = substr( $data, 0, $Metadata_Length );
98 8810         9931 my $raw_value = substr( $data, $Metadata_Length );
99 8810         56889 my $obj = bless [
100             $key, $raw_value,
101             $serializer, unpack( $Metadata_Format, $metadata )
102             ],
103             $class;
104 8810         20351 $obj->[f_packed_data] = $data;
105 8810         11656 $obj->[f_size] = length($data);
106 8810         21118 return $obj;
107             }
108              
109             sub pack_to_data {
110 3716     3716 0 4079 my ($self) = @_;
111              
112 3716 100       7430 return $self if !$self->serializer;
113 3439 50       7724 if ( !defined( $self->[f_packed_data] ) ) {
114 3439         17718 my $data = pack( $Metadata_Format,
115 3439         4597 ( @{$self} )[ f_created_at .. f_cache_version ] )
116             . $self->[f_raw_value];
117 3439         6471 $self->[f_packed_data] = $data;
118             }
119 3439         7485 return $self->[f_packed_data];
120             }
121              
122             sub is_expired {
123 8748     8748 1 8687 my ($self) = @_;
124              
125 8748         11309 my $expires_at = $self->[f_expires_at];
126 8748 100       20273 return undef if $expires_at == CHI_Max_Time;
127              
128 7169   66     12762 my $time = $CHI::Driver::Test_Time || time();
129 7169         7106 my $early_expires_at = $self->[f_early_expires_at];
130              
131 7169   66     48959 return $time >= $early_expires_at
132             && (
133             $time >= $expires_at
134             || (
135             rand() < (
136             ( $time - $early_expires_at ) /
137             ( $expires_at - $early_expires_at )
138             )
139             )
140             );
141             }
142              
143             sub value {
144 5373     5373 1 6025 my ($self) = @_;
145              
146 5373 100       12081 if ( !defined $self->[f_value] ) {
147 4445         5783 my $value = $self->[f_raw_value];
148 4445         4514 my $is_transformed = $self->[f_is_transformed];
149 4445 100       8113 if ( $is_transformed & T_COMPRESSED ) {
150 5         30 require Compress::Zlib;
151 5         21 $value = Compress::Zlib::memGunzip($value);
152             }
153 4445 100       10767 if ( $is_transformed & T_SERIALIZED ) {
    100          
154 143         352 $value = $self->serializer->deserialize($value);
155             }
156             elsif ( $is_transformed & T_UTF8_ENCODED ) {
157 50         221 $value = Encode::decode( utf8 => $value );
158             }
159 4445         11673 $self->[f_value] = $value;
160             }
161 5373         32429 return $self->[f_value];
162             }
163              
164             # get_* aliases for backward compatibility with Cache::Cache
165             #
166             *get_created_at = \&created_at;
167             *get_expires_at = \&expires_at;
168              
169             1;
170              
171             __END__