line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package CHI::t::Driver; |
2
|
|
|
|
|
|
|
$CHI::t::Driver::VERSION = '0.61'; |
3
|
9
|
|
|
9
|
|
78
|
use strict; |
|
9
|
|
|
|
|
24
|
|
|
9
|
|
|
|
|
284
|
|
4
|
9
|
|
|
9
|
|
65
|
use warnings; |
|
9
|
|
|
|
|
20
|
|
|
9
|
|
|
|
|
271
|
|
5
|
9
|
|
|
9
|
|
48
|
use CHI::Test; |
|
9
|
|
|
|
|
20
|
|
|
9
|
|
|
|
|
61
|
|
6
|
|
|
|
|
|
|
use CHI::Test::Util |
7
|
9
|
|
|
9
|
|
66
|
qw(activate_test_logger cmp_bool is_between random_string skip_until); |
|
9
|
|
|
|
|
33
|
|
|
9
|
|
|
|
|
722
|
|
8
|
9
|
|
|
9
|
|
68
|
use CHI::Util qw(can_load dump_one_line write_file); |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
543
|
|
9
|
9
|
|
|
9
|
|
60
|
use Encode; |
|
9
|
|
|
|
|
67
|
|
|
9
|
|
|
|
|
842
|
|
10
|
9
|
|
|
9
|
|
71
|
use File::Spec::Functions qw(tmpdir); |
|
9
|
|
|
|
|
31
|
|
|
9
|
|
|
|
|
529
|
|
11
|
9
|
|
|
9
|
|
2410
|
use File::Temp qw(tempdir); |
|
9
|
|
|
|
|
57312
|
|
|
9
|
|
|
|
|
512
|
|
12
|
9
|
|
|
9
|
|
78
|
use List::Util qw(shuffle); |
|
9
|
|
|
|
|
20
|
|
|
9
|
|
|
|
|
537
|
|
13
|
9
|
|
|
9
|
|
58
|
use Scalar::Util qw(weaken); |
|
9
|
|
|
|
|
43
|
|
|
9
|
|
|
|
|
444
|
|
14
|
9
|
|
|
9
|
|
61
|
use Storable qw(dclone); |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
525
|
|
15
|
9
|
|
|
9
|
|
3420
|
use Test::Warn; |
|
9
|
|
|
|
|
15281
|
|
|
9
|
|
|
|
|
580
|
|
16
|
9
|
|
|
9
|
|
64
|
use Time::HiRes qw(usleep); |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
85
|
|
17
|
9
|
|
|
9
|
|
1317
|
use base qw(CHI::Test::Class); |
|
9
|
|
|
|
|
20
|
|
|
9
|
|
|
|
|
4609
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# Flags indicating what each test driver supports |
20
|
435
|
|
|
435
|
0
|
3465
|
sub supports_clear { 1 } |
21
|
7
|
|
|
7
|
0
|
42
|
sub supports_expires_on_backend { 0 } |
22
|
8
|
|
|
8
|
0
|
43
|
sub supports_get_namespaces { 1 } |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
sub standard_keys_and_values : Test(startup) { |
25
|
8
|
|
|
8
|
0
|
19168
|
my ($self) = @_; |
26
|
|
|
|
|
|
|
|
27
|
8
|
|
|
|
|
60
|
my ( $keys_ref, $values_ref ) = $self->set_standard_keys_and_values(); |
28
|
8
|
|
|
|
|
31
|
$self->{keys} = $keys_ref; |
29
|
8
|
|
|
|
|
23
|
$self->{values} = $values_ref; |
30
|
8
|
|
|
|
|
19
|
$self->{keynames} = [ keys( %{$keys_ref} ) ]; |
|
8
|
|
|
|
|
48
|
|
31
|
8
|
|
|
|
|
22
|
$self->{key_count} = scalar( @{ $self->{keynames} } ); |
|
8
|
|
|
|
|
25
|
|
32
|
8
|
|
|
|
|
86
|
$self->{all_test_keys} = [ values(%$keys_ref), $self->extra_test_keys() ]; |
33
|
8
|
|
|
|
|
65
|
my $cache = $self->new_cache(); |
34
|
|
|
|
|
|
|
push( |
35
|
8
|
|
|
|
|
32
|
@{ $self->{all_test_keys} }, |
36
|
8
|
|
|
|
|
26
|
$self->process_keys( $cache, @{ $self->{all_test_keys} } ) |
|
8
|
|
|
|
|
109
|
|
37
|
|
|
|
|
|
|
); |
38
|
|
|
|
|
|
|
$self->{all_test_keys_hash} = |
39
|
8
|
|
|
|
|
35
|
{ map { ( $_, 1 ) } @{ $self->{all_test_keys} } }; |
|
736
|
|
|
|
|
1707
|
|
|
8
|
|
|
|
|
27
|
|
40
|
9
|
|
|
9
|
|
97
|
} |
|
9
|
|
|
|
|
22
|
|
|
9
|
|
|
|
|
52
|
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub kvpair { |
43
|
175
|
|
|
175
|
0
|
413
|
my $self = shift; |
44
|
175
|
|
100
|
|
|
905
|
my $count = shift || 1; |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
return map { |
47
|
175
|
|
|
|
|
602
|
( |
48
|
|
|
|
|
|
|
$self->{keys}->{medium} . ( $_ == 1 ? '' : $_ ), |
49
|
205
|
100
|
|
|
|
2020
|
$self->{values}->{medium} . ( $_ == 1 ? '' : $_ ) |
|
|
100
|
|
|
|
|
|
50
|
|
|
|
|
|
|
) |
51
|
|
|
|
|
|
|
} ( 1 .. $count ); |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
sub setup : Test(setup) { |
55
|
415
|
|
|
415
|
0
|
977463
|
my $self = shift; |
56
|
|
|
|
|
|
|
|
57
|
415
|
|
|
|
|
1889
|
$self->{cache} = $self->new_cache(); |
58
|
415
|
50
|
|
|
|
1827
|
$self->{cache}->clear() if $self->supports_clear(); |
59
|
9
|
|
|
9
|
|
4568
|
} |
|
9
|
|
|
|
|
22
|
|
|
9
|
|
|
|
|
50
|
|
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub testing_driver_class { |
62
|
383
|
|
|
383
|
0
|
688
|
my $self = shift; |
63
|
383
|
|
|
|
|
861
|
my $class = ref($self); |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
# By default, take the last part of the classname and use it as driver |
66
|
383
|
|
|
|
|
2142
|
my $driver_class = 'CHI::Driver::' . ( split( '::', $class ) )[-1]; |
67
|
383
|
|
|
|
|
3629
|
return $driver_class; |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
sub testing_chi_root_class { |
71
|
446
|
|
|
446
|
0
|
2053
|
return 'CHI'; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub new_cache { |
75
|
433
|
|
|
433
|
0
|
885
|
my $self = shift; |
76
|
|
|
|
|
|
|
|
77
|
433
|
|
|
|
|
1325
|
return $self->testing_chi_root_class->new( $self->new_cache_options(), @_ ); |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
sub new_cleared_cache { |
81
|
94
|
|
|
94
|
0
|
1211
|
my $self = shift; |
82
|
|
|
|
|
|
|
|
83
|
94
|
|
|
|
|
424
|
my $cache = $self->new_cache(@_); |
84
|
94
|
|
|
|
|
2026
|
$cache->clear(); |
85
|
94
|
|
|
|
|
9936
|
return $cache; |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub new_cache_options { |
89
|
720
|
|
|
720
|
0
|
1504
|
my $self = shift; |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
return ( |
92
|
720
|
|
|
|
|
2568
|
driver => '+' . $self->testing_driver_class(), |
93
|
|
|
|
|
|
|
on_get_error => 'die', |
94
|
|
|
|
|
|
|
on_set_error => 'die' |
95
|
|
|
|
|
|
|
); |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub set_standard_keys_and_values { |
99
|
8
|
|
|
8
|
0
|
22
|
my $self = shift; |
100
|
|
|
|
|
|
|
|
101
|
8
|
|
|
|
|
20
|
my ( %keys, %values ); |
102
|
8
|
|
|
|
|
51
|
my @mixed_chars = ( 32 .. 48, 57 .. 65, 90 .. 97, 122 .. 126, 240 ); |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
%keys = ( |
105
|
|
|
|
|
|
|
'space' => ' ', |
106
|
|
|
|
|
|
|
'newline' => "\n", |
107
|
|
|
|
|
|
|
'char' => 'a', |
108
|
|
|
|
|
|
|
'zero' => 0, |
109
|
|
|
|
|
|
|
'one' => 1, |
110
|
|
|
|
|
|
|
'medium' => 'medium', |
111
|
320
|
|
|
|
|
558
|
'mixed' => join( "", map { chr($_) } @mixed_chars ), |
112
|
8
|
|
|
|
|
87
|
'binary' => join( "", map { chr($_) } ( 129 .. 255 ) ), |
|
1016
|
|
|
|
|
1663
|
|
113
|
|
|
|
|
|
|
'large' => scalar( 'ab' x 256 ), |
114
|
|
|
|
|
|
|
'empty' => 'empty', |
115
|
|
|
|
|
|
|
'arrayref' => [ 1, 2 ], |
116
|
|
|
|
|
|
|
'hashref' => { foo => [ 'bar', 'baz' ] }, |
117
|
|
|
|
|
|
|
'utf8' => "Have \x{263a} a nice day", |
118
|
|
|
|
|
|
|
); |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
%values = map { |
121
|
8
|
100
|
|
|
|
107
|
( $_, ref( $keys{$_} ) ? $keys{$_} : scalar( reverse( $keys{$_} ) ) ) |
|
104
|
|
|
|
|
327
|
|
122
|
|
|
|
|
|
|
} keys(%keys); |
123
|
8
|
|
|
|
|
37
|
$values{empty} = ''; |
124
|
|
|
|
|
|
|
|
125
|
8
|
|
|
|
|
41
|
return ( \%keys, \%values ); |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# Extra keys (beyond the standard keys above) that we may use in these |
129
|
|
|
|
|
|
|
# tests. We need to adhere to this for the benefit of drivers that don't |
130
|
|
|
|
|
|
|
# support get_keys (like memcached) - they simulate get_keys(), clear(), |
131
|
|
|
|
|
|
|
# etc. by using this fixed list of keys. |
132
|
|
|
|
|
|
|
# |
133
|
|
|
|
|
|
|
sub extra_test_keys { |
134
|
8
|
|
|
8
|
0
|
64
|
my ($class) = @_; |
135
|
|
|
|
|
|
|
return ( |
136
|
|
|
|
|
|
|
'', '2', |
137
|
|
|
|
|
|
|
'medium2', 'foo', |
138
|
|
|
|
|
|
|
'hashref', 'test_namespace_types', |
139
|
|
|
|
|
|
|
"utf8", "encoded", |
140
|
24
|
|
|
|
|
83
|
"binary", ( map { "done$_" } ( 0 .. 2 ) ), |
141
|
8
|
|
|
|
|
38
|
( map { "key$_" } ( 0 .. 20 ) ) |
|
168
|
|
|
|
|
469
|
|
142
|
|
|
|
|
|
|
); |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub set_some_keys { |
146
|
58
|
|
|
58
|
0
|
182
|
my ( $self, $c ) = @_; |
147
|
|
|
|
|
|
|
|
148
|
58
|
|
|
|
|
137
|
foreach my $keyname ( @{ $self->{keynames} } ) { |
|
58
|
|
|
|
|
227
|
|
149
|
754
|
|
|
|
|
8652
|
$c->set( $self->{keys}->{$keyname}, $self->{values}->{$keyname} ); |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub test_encode : Tests { |
154
|
8
|
|
|
8
|
0
|
6013
|
my $self = shift; |
155
|
8
|
|
|
|
|
40
|
my $cache = $self->new_cleared_cache(); |
156
|
|
|
|
|
|
|
|
157
|
8
|
|
|
|
|
43
|
my $utf8 = $self->{keys}->{utf8}; |
158
|
8
|
|
|
|
|
57
|
my $encoded = encode( utf8 => $utf8 ); |
159
|
8
|
|
|
|
|
439
|
my $binary_off = $self->{keys}->{binary}; |
160
|
8
|
|
|
|
|
88
|
my $binary_on = substr( $binary_off . $utf8, 0, length($binary_off) ); |
161
|
|
|
|
|
|
|
|
162
|
8
|
|
|
|
|
71
|
ok( $binary_off eq $binary_on, "binary_off eq binary_on" ); |
163
|
8
|
|
|
|
|
3816
|
ok( !Encode::is_utf8($binary_off), "!is_utf8(binary_off)" ); |
164
|
8
|
|
|
|
|
2824
|
ok( Encode::is_utf8($binary_on), "is_utf8(binary_on)" ); |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# Key maps to same thing whether encoded or non-encoded |
167
|
|
|
|
|
|
|
# |
168
|
8
|
|
|
|
|
2778
|
my $value = time; |
169
|
8
|
|
|
|
|
156
|
$cache->set( $utf8, $value ); |
170
|
8
|
|
|
|
|
110
|
is( $cache->get($utf8), $value, "get" ); |
171
|
8
|
|
|
|
|
4006
|
is( $cache->get($encoded), |
172
|
|
|
|
|
|
|
$value, "encoded and non-encoded map to same value" ); |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# Key maps to same thing whether utf8 flag is off or on |
175
|
|
|
|
|
|
|
# |
176
|
|
|
|
|
|
|
# Commenting out for now - this is broken on FastMmap and |
177
|
|
|
|
|
|
|
# DBI drivers (at least), and not entirely sure whether or |
178
|
|
|
|
|
|
|
# with what priority we should demand this behavior. |
179
|
|
|
|
|
|
|
# |
180
|
8
|
|
|
|
|
3242
|
if (0) { |
181
|
|
|
|
|
|
|
$cache->set( $binary_off, $value ); |
182
|
|
|
|
|
|
|
is( $cache->get($binary_off), $value, "get binary_off" ); |
183
|
|
|
|
|
|
|
is( $cache->get($binary_on), |
184
|
|
|
|
|
|
|
$value, "binary_off and binary_on map to same value" ); |
185
|
|
|
|
|
|
|
$cache->clear($binary_on); |
186
|
|
|
|
|
|
|
ok( !$cache->get($binary_off), "cleared binary_off" ); # |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# Value is maintained as a utf8 or binary string, in scalar or in arrayref |
190
|
8
|
|
|
|
|
122
|
$cache->set( "utf8", $utf8 ); |
191
|
8
|
|
|
|
|
97
|
is( $cache->get("utf8"), $utf8, "utf8 in scalar" ); |
192
|
8
|
|
|
|
|
3748
|
$cache->set( "utf8", [$utf8] ); |
193
|
8
|
|
|
|
|
99
|
is( $cache->get("utf8")->[0], $utf8, "utf8 in arrayref" ); |
194
|
|
|
|
|
|
|
|
195
|
8
|
|
|
|
|
3560
|
$cache->set( "encoded", $encoded ); |
196
|
8
|
|
|
|
|
98
|
is( $cache->get("encoded"), $encoded, "encoded in scalar" ); |
197
|
8
|
|
|
|
|
3550
|
$cache->set( "encoded", [$encoded] ); |
198
|
8
|
|
|
|
|
101
|
is( $cache->get("encoded")->[0], $encoded, "encoded in arrayref" ); |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# Value retrieves as same thing whether stored with utf8 flag off or on |
201
|
|
|
|
|
|
|
# |
202
|
8
|
|
|
|
|
3574
|
$cache->set( "binary", $binary_off ); |
203
|
8
|
|
|
|
|
95
|
is( $cache->get("binary"), $binary_on, "stored binary_off = binary_on" ); |
204
|
8
|
|
|
|
|
3525
|
$cache->set( "binary", $binary_on ); |
205
|
8
|
|
|
|
|
97
|
is( $cache->get("binary"), $binary_off, "stored binary_on = binary_off" ); |
206
|
9
|
|
|
9
|
|
11838
|
} |
|
9
|
|
|
|
|
29
|
|
|
9
|
|
|
|
|
45
|
|
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
sub test_simple : Tests { |
209
|
12
|
|
|
12
|
0
|
6130
|
my $self = shift; |
210
|
12
|
|
33
|
|
|
86
|
my $cache = shift || $self->{cache}; |
211
|
|
|
|
|
|
|
|
212
|
12
|
|
|
|
|
182
|
ok( $cache->set( $self->{keys}->{medium}, $self->{values}->{medium} ) ); |
213
|
10
|
|
|
|
|
5128
|
is( $cache->get( $self->{keys}->{medium} ), $self->{values}->{medium} ); |
214
|
9
|
|
|
9
|
|
3508
|
} |
|
9
|
|
|
|
|
20
|
|
|
9
|
|
|
|
|
49
|
|
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub test_driver_class : Tests { |
217
|
8
|
|
|
8
|
0
|
6208
|
my $self = shift; |
218
|
8
|
|
|
|
|
30
|
my $cache = $self->{cache}; |
219
|
|
|
|
|
|
|
|
220
|
8
|
|
|
|
|
60
|
isa_ok( $cache, 'CHI::Driver' ); |
221
|
8
|
|
|
|
|
4613
|
isa_ok( $cache, $cache->driver_class ); |
222
|
8
|
|
|
|
|
3341
|
can_ok( $cache, 'get', 'set', 'remove', 'clear', 'expire' ); |
223
|
9
|
|
|
9
|
|
3105
|
} |
|
9
|
|
|
|
|
24
|
|
|
9
|
|
|
|
|
38
|
|
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub test_key_types : Tests { |
226
|
8
|
|
|
8
|
0
|
7480
|
my $self = shift; |
227
|
8
|
|
|
|
|
31
|
my $cache = $self->{cache}; |
228
|
8
|
|
|
|
|
107
|
$self->num_tests( $self->{key_count} * 9 + 1 ); |
229
|
|
|
|
|
|
|
|
230
|
8
|
|
|
|
|
1117
|
my @keys_set; |
231
|
|
|
|
|
|
|
my $check_keys_set = sub { |
232
|
216
|
|
|
216
|
|
459
|
my $desc = shift; |
233
|
216
|
|
|
|
|
885
|
cmp_set( [ $cache->get_keys ], \@keys_set, "checking keys $desc" ); |
234
|
8
|
|
|
|
|
60
|
}; |
235
|
|
|
|
|
|
|
|
236
|
8
|
|
|
|
|
34
|
$check_keys_set->("before sets"); |
237
|
8
|
|
|
|
|
6211
|
foreach my $keyname ( @{ $self->{keynames} } ) { |
|
8
|
|
|
|
|
43
|
|
238
|
104
|
|
|
|
|
64218
|
my $key = $self->{keys}->{$keyname}; |
239
|
104
|
|
|
|
|
503
|
my $value = $self->{values}->{$keyname}; |
240
|
104
|
|
|
|
|
1428
|
ok( !defined $cache->get($key), "miss for key '$keyname'" ); |
241
|
104
|
|
|
|
|
39841
|
is( $cache->set( $key, $value ), $value, "set for key '$keyname'" ); |
242
|
104
|
|
|
|
|
41666
|
push( @keys_set, $self->process_keys( $cache, $key ) ); |
243
|
104
|
|
|
|
|
527
|
$check_keys_set->("after set of key '$keyname'"); |
244
|
104
|
|
|
|
|
884115
|
cmp_deeply( $cache->get($key), $value, "hit for key '$keyname'" ); |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
|
247
|
8
|
|
|
|
|
6690
|
foreach my $keyname ( reverse @{ $self->{keynames} } ) { |
|
8
|
|
|
|
|
38
|
|
248
|
104
|
|
|
|
|
738119
|
my $key = $self->{keys}->{$keyname}; |
249
|
104
|
|
|
|
|
4102
|
$cache->remove($key); |
250
|
104
|
|
|
|
|
4390
|
ok( !defined $cache->get($key), |
251
|
|
|
|
|
|
|
"miss after remove for key '$keyname'" ); |
252
|
104
|
|
|
|
|
40145
|
pop(@keys_set); |
253
|
104
|
|
|
|
|
448
|
$check_keys_set->("after removal of key '$keyname'"); |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
# Confirm that transform_key is idempotent |
257
|
|
|
|
|
|
|
# |
258
|
8
|
|
|
|
|
9752
|
foreach my $keyname ( @{ $self->{keynames} } ) { |
|
8
|
|
|
|
|
40
|
|
259
|
104
|
|
|
|
|
63945
|
my $key = $self->{keys}->{$keyname}; |
260
|
104
|
|
|
|
|
294
|
my $value = $self->{values}->{$keyname}; |
261
|
104
|
|
|
|
|
443
|
is( |
262
|
|
|
|
|
|
|
$cache->transform_key( $cache->transform_key($key) ), |
263
|
|
|
|
|
|
|
$cache->transform_key($key), |
264
|
|
|
|
|
|
|
"transform_key is idempotent for '$keyname'" |
265
|
|
|
|
|
|
|
); |
266
|
104
|
|
|
|
|
40031
|
$cache->clear(); |
267
|
104
|
|
|
|
|
23205
|
$cache->set( $key, $value ); |
268
|
104
|
|
|
|
|
480
|
is( scalar( $cache->get_keys() ), 1, "exactly one key" ); |
269
|
104
|
|
|
|
|
41365
|
cmp_deeply( $cache->get( ( $cache->get_keys )[0] ), |
270
|
|
|
|
|
|
|
$value, "get with get_keys[0] got same value" ); |
271
|
|
|
|
|
|
|
} |
272
|
9
|
|
|
9
|
|
6758
|
} |
|
9
|
|
|
|
|
26
|
|
|
9
|
|
|
|
|
55
|
|
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
sub test_deep_copy : Tests { |
275
|
7
|
|
|
7
|
0
|
13207
|
my $self = shift; |
276
|
7
|
|
|
|
|
21
|
my $cache = $self->{cache}; |
277
|
|
|
|
|
|
|
|
278
|
7
|
|
|
|
|
41
|
$self->set_some_keys($cache); |
279
|
7
|
|
|
|
|
36
|
foreach my $keyname (qw(arrayref hashref)) { |
280
|
14
|
|
|
|
|
2810
|
my $key = $self->{keys}->{$keyname}; |
281
|
14
|
|
|
|
|
45
|
my $value = $self->{values}->{$keyname}; |
282
|
14
|
|
|
|
|
190
|
cmp_deeply( $cache->get($key), $value, |
283
|
|
|
|
|
|
|
"get($key) returns original data structure" ); |
284
|
14
|
|
|
|
|
77137
|
cmp_deeply( $cache->get($key), $cache->get($key), |
285
|
|
|
|
|
|
|
"multiple get($key) return same data structure" ); |
286
|
14
|
|
|
|
|
29945
|
isnt( $cache->get($key), $value, |
287
|
|
|
|
|
|
|
"get($key) does not return original reference" ); |
288
|
14
|
|
|
|
|
5913
|
isnt( $cache->get($key), $cache->get($key), |
289
|
|
|
|
|
|
|
"multiple get($key) do not return same reference" ); |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
|
292
|
7
|
|
|
|
|
3237
|
my $struct = { a => [ 1, 2 ], b => [ 4, 5 ] }; |
293
|
7
|
|
|
|
|
579
|
my $struct2 = dclone($struct); |
294
|
7
|
|
|
|
|
145
|
$cache->set( 'hashref', $struct ); |
295
|
7
|
|
|
|
|
24
|
push( @{ $struct->{a} }, 3 ); |
|
7
|
|
|
|
|
31
|
|
296
|
7
|
|
|
|
|
27
|
delete( $struct->{b} ); |
297
|
7
|
|
|
|
|
92
|
cmp_deeply( $cache->get('hashref'), |
298
|
|
|
|
|
|
|
$struct2, |
299
|
|
|
|
|
|
|
"altering original set structure does not affect cached copy" ); |
300
|
9
|
|
|
9
|
|
4447
|
} |
|
9
|
|
|
|
|
25
|
|
|
9
|
|
|
|
|
46
|
|
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
sub test_expires_immediately : Tests { |
303
|
8
|
|
|
8
|
0
|
6221
|
my $self = shift; |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
return 'author testing only - timing is unreliable' |
306
|
8
|
50
|
|
|
|
58
|
unless ( $ENV{AUTHOR_TESTING} ); |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
# expires_in default should be ignored |
309
|
0
|
|
|
|
|
0
|
my $cache = $self->new_cache( expires_in => '1 hour' ); |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
# Expires immediately |
312
|
|
|
|
|
|
|
my $test_expires_immediately = sub { |
313
|
0
|
|
|
0
|
|
0
|
my ($set_option) = @_; |
314
|
0
|
|
|
|
|
0
|
my ( $key, $value ) = $self->kvpair(); |
315
|
0
|
|
|
|
|
0
|
my $desc = dump_one_line($set_option); |
316
|
0
|
|
|
|
|
0
|
is( $cache->set( $key, $value, $set_option ), $value, "set ($desc)" ); |
317
|
0
|
|
|
|
|
0
|
is_between( |
318
|
|
|
|
|
|
|
$cache->get_expires_at($key), |
319
|
|
|
|
|
|
|
time() - 4, |
320
|
|
|
|
|
|
|
time(), "expires_at ($desc)" |
321
|
|
|
|
|
|
|
); |
322
|
0
|
|
|
|
|
0
|
ok( $cache->exists_and_is_expired($key), "is_expired ($desc)" ); |
323
|
0
|
|
|
|
|
0
|
ok( !defined $cache->get($key), "immediate miss ($desc)" ); |
324
|
0
|
|
|
|
|
0
|
}; |
325
|
0
|
|
|
|
|
0
|
$test_expires_immediately->(0); |
326
|
0
|
|
|
|
|
0
|
$test_expires_immediately->(-1); |
327
|
0
|
|
|
|
|
0
|
$test_expires_immediately->("0 seconds"); |
328
|
0
|
|
|
|
|
0
|
$test_expires_immediately->("0 hours"); |
329
|
0
|
|
|
|
|
0
|
$test_expires_immediately->("-1 seconds"); |
330
|
0
|
|
|
|
|
0
|
$test_expires_immediately->( { expires_in => "0 seconds" } ); |
331
|
0
|
|
|
|
|
0
|
$test_expires_immediately->( { expires_at => time - 1 } ); |
332
|
0
|
|
|
|
|
0
|
$test_expires_immediately->("now"); |
333
|
9
|
|
|
9
|
|
4780
|
} |
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
53
|
|
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
sub test_expires_shortly : Tests { |
336
|
8
|
|
|
8
|
0
|
7782
|
my $self = shift; |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
return 'author testing only - timing is unreliable' |
339
|
8
|
50
|
|
|
|
61
|
unless ( $ENV{AUTHOR_TESTING} ); |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
# expires_in default should be ignored |
342
|
0
|
|
|
|
|
0
|
my $cache = $self->new_cache( expires_in => '1 hour' ); |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
# Expires shortly (real time) |
345
|
|
|
|
|
|
|
my $test_expires_shortly = sub { |
346
|
0
|
|
|
0
|
|
0
|
my ($set_option) = @_; |
347
|
0
|
|
|
|
|
0
|
my ( $key, $value ) = $self->kvpair(); |
348
|
0
|
|
|
|
|
0
|
my $desc = "set_option = " . dump_one_line($set_option); |
349
|
0
|
|
|
|
|
0
|
my $start_time = time(); |
350
|
0
|
|
|
|
|
0
|
is( $cache->set( $key, $value, $set_option ), $value, "set ($desc)" ); |
351
|
0
|
|
|
|
|
0
|
is( $cache->get($key), $value, "hit ($desc)" ); |
352
|
0
|
|
|
|
|
0
|
is_between( |
353
|
|
|
|
|
|
|
$cache->get_expires_at($key), |
354
|
|
|
|
|
|
|
$start_time + 1, |
355
|
|
|
|
|
|
|
$start_time + 8, |
356
|
|
|
|
|
|
|
"expires_at ($desc)" |
357
|
|
|
|
|
|
|
); |
358
|
0
|
|
|
|
|
0
|
ok( !$cache->exists_and_is_expired($key), "not expired ($desc)" ); |
359
|
0
|
|
|
|
|
0
|
ok( $cache->is_valid($key), "valid ($desc)" ); |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
# Only bother sleeping and expiring for one of the variants |
362
|
0
|
0
|
|
|
|
0
|
if ( $set_option eq "3 seconds" ) { |
363
|
0
|
|
|
|
|
0
|
sleep(3); |
364
|
0
|
|
|
|
|
0
|
ok( !defined $cache->get($key), "miss after 2 seconds ($desc)" ); |
365
|
0
|
|
|
|
|
0
|
ok( $cache->exists_and_is_expired($key), "is_expired ($desc)" ); |
366
|
0
|
|
|
|
|
0
|
ok( !$cache->is_valid($key), "invalid ($desc)" ); |
367
|
|
|
|
|
|
|
} |
368
|
0
|
|
|
|
|
0
|
}; |
369
|
0
|
|
|
|
|
0
|
$test_expires_shortly->(3); |
370
|
0
|
|
|
|
|
0
|
$test_expires_shortly->("3 seconds"); |
371
|
0
|
|
|
|
|
0
|
$test_expires_shortly->( { expires_at => time + 3 } ); |
372
|
9
|
|
|
9
|
|
5248
|
} |
|
9
|
|
|
|
|
23
|
|
|
9
|
|
|
|
|
42
|
|
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
sub test_expires_later : Tests { |
375
|
8
|
|
|
8
|
0
|
6155
|
my $self = shift; |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
return 'author testing only - timing is unreliable' |
378
|
8
|
50
|
|
|
|
61
|
unless ( $ENV{AUTHOR_TESTING} ); |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
# expires_in default should be ignored |
381
|
0
|
|
|
|
|
0
|
my $cache = $self->new_cache( expires_in => '1s' ); |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
# Expires later (test time) |
384
|
|
|
|
|
|
|
my $test_expires_later = sub { |
385
|
0
|
|
|
0
|
|
0
|
my ($set_option) = @_; |
386
|
0
|
|
|
|
|
0
|
my ( $key, $value ) = $self->kvpair(); |
387
|
0
|
|
|
|
|
0
|
my $desc = "set_option = " . dump_one_line($set_option); |
388
|
0
|
|
|
|
|
0
|
is( $cache->set( $key, $value, $set_option ), $value, "set ($desc)" ); |
389
|
0
|
|
|
|
|
0
|
is( $cache->get($key), $value, "hit ($desc)" ); |
390
|
0
|
|
|
|
|
0
|
my $start_time = time(); |
391
|
0
|
|
|
|
|
0
|
is_between( |
392
|
|
|
|
|
|
|
$cache->get_expires_at($key), |
393
|
|
|
|
|
|
|
$start_time + 3580, |
394
|
|
|
|
|
|
|
$start_time + 3620, |
395
|
|
|
|
|
|
|
"expires_at ($desc)" |
396
|
|
|
|
|
|
|
); |
397
|
0
|
|
|
|
|
0
|
ok( !$cache->exists_and_is_expired($key), "not expired ($desc)" ); |
398
|
0
|
|
|
|
|
0
|
ok( $cache->is_valid($key), "valid ($desc)" ); |
399
|
0
|
|
|
|
|
0
|
local $CHI::Driver::Test_Time = $start_time + 3590; |
400
|
0
|
|
|
|
|
0
|
ok( !$cache->exists_and_is_expired($key), "not expired ($desc)" ); |
401
|
0
|
|
|
|
|
0
|
ok( $cache->is_valid($key), "valid ($desc)" ); |
402
|
0
|
|
|
|
|
0
|
local $CHI::Driver::Test_Time = $start_time + 3610; |
403
|
0
|
|
|
|
|
0
|
ok( !defined $cache->get($key), "miss after 1 hour ($desc)" ); |
404
|
0
|
|
|
|
|
0
|
ok( $cache->exists_and_is_expired($key), "is_expired ($desc)" ); |
405
|
0
|
|
|
|
|
0
|
ok( !$cache->is_valid($key), "invalid ($desc)" ); |
406
|
0
|
|
|
|
|
0
|
}; |
407
|
0
|
|
|
|
|
0
|
$test_expires_later->(3600); |
408
|
0
|
|
|
|
|
0
|
$test_expires_later->("1 hour"); |
409
|
0
|
|
|
|
|
0
|
$test_expires_later->( { expires_at => time + 3600 } ); |
410
|
9
|
|
|
9
|
|
6030
|
} |
|
9
|
|
|
|
|
20
|
|
|
9
|
|
|
|
|
52
|
|
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
sub test_expires_never : Tests { |
413
|
8
|
|
|
8
|
0
|
7760
|
my $self = shift; |
414
|
8
|
|
|
|
|
19
|
my $cache; |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
# Expires never (will fail in 2037) |
417
|
8
|
|
|
|
|
42
|
my ( $key, $value ) = $self->kvpair(); |
418
|
|
|
|
|
|
|
my $test_expires_never = sub { |
419
|
16
|
|
|
16
|
|
54
|
my (@set_options) = @_; |
420
|
16
|
|
|
|
|
221
|
$cache->set( $key, $value, @set_options ); |
421
|
16
|
|
|
|
|
88
|
ok( |
422
|
|
|
|
|
|
|
$cache->get_expires_at($key) > |
423
|
|
|
|
|
|
|
time + Time::Duration::Parse::parse_duration('1 year'), |
424
|
|
|
|
|
|
|
"expires never" |
425
|
|
|
|
|
|
|
); |
426
|
16
|
|
|
|
|
9256
|
ok( !$cache->exists_and_is_expired($key), "not expired" ); |
427
|
16
|
|
|
|
|
6051
|
ok( $cache->is_valid($key), "valid" ); |
428
|
8
|
|
|
|
|
53
|
}; |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
# never is default |
431
|
8
|
|
|
|
|
37
|
$cache = $self->new_cache(); |
432
|
8
|
|
|
|
|
46
|
$test_expires_never->(); |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
# expires_in default should be ignored when never passed to set (RT #67970) |
435
|
8
|
|
|
|
|
3019
|
$cache = $self->new_cache( expires_in => '1s' ); |
436
|
8
|
|
|
|
|
38
|
$test_expires_never->('never'); |
437
|
9
|
|
|
9
|
|
4090
|
} |
|
9
|
|
|
|
|
25
|
|
|
9
|
|
|
|
|
55
|
|
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
sub test_expires_defaults : Tests { |
440
|
8
|
|
|
8
|
0
|
7771
|
my $self = shift; |
441
|
|
|
|
|
|
|
|
442
|
8
|
|
|
|
|
23
|
my $start_time = time(); |
443
|
8
|
|
|
|
|
26
|
local $CHI::Driver::Test_Time = $start_time; |
444
|
8
|
|
|
|
|
19
|
my $cache; |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
my $set_and_confirm_expires_at = sub { |
447
|
32
|
|
|
32
|
|
111
|
my ( $expected_expires_at, $desc ) = @_; |
448
|
32
|
|
|
|
|
132
|
my ( $key, $value ) = $self->kvpair(); |
449
|
32
|
|
|
|
|
398
|
$cache->set( $key, $value ); |
450
|
32
|
|
|
|
|
171
|
is( $cache->get_expires_at($key), $expected_expires_at, $desc ); |
451
|
32
|
|
|
|
|
15020
|
$cache->clear(); |
452
|
8
|
|
|
|
|
49
|
}; |
453
|
|
|
|
|
|
|
|
454
|
8
|
|
|
|
|
39
|
$cache = $self->new_cache( expires_in => 10 ); |
455
|
8
|
|
|
|
|
50
|
$set_and_confirm_expires_at->( |
456
|
|
|
|
|
|
|
$start_time + 10, |
457
|
|
|
|
|
|
|
"after expires_in constructor option" |
458
|
|
|
|
|
|
|
); |
459
|
8
|
|
|
|
|
1568
|
$cache->expires_in(20); |
460
|
8
|
|
|
|
|
222
|
$set_and_confirm_expires_at->( $start_time + 20, |
461
|
|
|
|
|
|
|
"after expires_in method" ); |
462
|
|
|
|
|
|
|
|
463
|
8
|
|
|
|
|
1432
|
$cache = $self->new_cache( expires_at => $start_time + 30 ); |
464
|
8
|
|
|
|
|
49
|
$set_and_confirm_expires_at->( |
465
|
|
|
|
|
|
|
$start_time + 30, |
466
|
|
|
|
|
|
|
"after expires_at constructor option" |
467
|
|
|
|
|
|
|
); |
468
|
8
|
|
|
|
|
1386
|
$cache->expires_at( $start_time + 40 ); |
469
|
8
|
|
|
|
|
32
|
$set_and_confirm_expires_at->( $start_time + 40, |
470
|
|
|
|
|
|
|
"after expires_at method" ); |
471
|
9
|
|
|
9
|
|
4072
|
} |
|
9
|
|
|
|
|
38
|
|
|
9
|
|
|
|
|
58
|
|
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
sub test_expires_manually : Tests { |
474
|
8
|
|
|
8
|
0
|
6039
|
my $self = shift; |
475
|
8
|
|
|
|
|
35
|
my $cache = $self->{cache}; |
476
|
|
|
|
|
|
|
|
477
|
8
|
|
|
|
|
42
|
my ( $key, $value ) = $self->kvpair(); |
478
|
8
|
|
|
|
|
31
|
my $desc = "expires manually"; |
479
|
8
|
|
|
|
|
161
|
$cache->set( $key, $value ); |
480
|
8
|
|
|
|
|
109
|
is( $cache->get($key), $value, "hit ($desc)" ); |
481
|
8
|
|
|
|
|
3944
|
$cache->expire($key); |
482
|
8
|
|
|
|
|
132
|
ok( !defined $cache->get($key), "miss after expire ($desc)" ); |
483
|
8
|
|
|
|
|
3692
|
ok( !$cache->is_valid($key), "invalid after expire ($desc)" ); |
484
|
9
|
|
|
9
|
|
3577
|
} |
|
9
|
|
|
|
|
31
|
|
|
9
|
|
|
|
|
71
|
|
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
sub test_expires_conditionally : Tests { |
487
|
8
|
|
|
8
|
0
|
10950
|
my $self = shift; |
488
|
8
|
|
|
|
|
26
|
my $cache = $self->{cache}; |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
# Expires conditionally |
491
|
|
|
|
|
|
|
my $test_expires_conditionally = sub { |
492
|
32
|
|
|
32
|
|
101
|
my ( $code, $cond_desc, $expect_expire ) = @_; |
493
|
|
|
|
|
|
|
|
494
|
32
|
|
|
|
|
130
|
my ( $key, $value ) = $self->kvpair(); |
495
|
32
|
|
|
|
|
120
|
my $desc = "expires conditionally ($cond_desc)"; |
496
|
32
|
|
|
|
|
453
|
$cache->set( $key, $value ); |
497
|
32
|
100
|
|
|
|
353
|
is( |
498
|
|
|
|
|
|
|
$cache->get( $key, expire_if => $code ), |
499
|
|
|
|
|
|
|
$expect_expire ? undef : $value, |
500
|
|
|
|
|
|
|
"get result ($desc)" |
501
|
|
|
|
|
|
|
); |
502
|
|
|
|
|
|
|
|
503
|
32
|
|
|
|
|
16897
|
is( $cache->get($key), $value, "hit after expire_if ($desc)" ); |
504
|
|
|
|
|
|
|
|
505
|
8
|
|
|
|
|
59
|
}; |
506
|
8
|
|
|
|
|
27
|
my $time = time(); |
507
|
8
|
|
|
9
|
|
50
|
$test_expires_conditionally->( sub { 1 }, 'true', 1 ); |
|
9
|
|
|
|
|
44
|
|
508
|
8
|
|
|
8
|
|
3222
|
$test_expires_conditionally->( sub { 0 }, 'false', 0 ); |
|
8
|
|
|
|
|
36
|
|
509
|
|
|
|
|
|
|
$test_expires_conditionally->( |
510
|
9
|
|
|
9
|
|
46
|
sub { $_[0]->created_at >= $time }, |
511
|
8
|
|
|
|
|
3301
|
'created_at >= now', 1 |
512
|
|
|
|
|
|
|
); |
513
|
|
|
|
|
|
|
$test_expires_conditionally->( |
514
|
8
|
|
|
8
|
|
44
|
sub { $_[0]->created_at < $time }, |
515
|
8
|
|
|
|
|
3234
|
'created_at < now', 0 |
516
|
|
|
|
|
|
|
); |
517
|
9
|
|
|
9
|
|
5023
|
} |
|
9
|
|
|
|
|
25
|
|
|
9
|
|
|
|
|
60
|
|
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
sub test_expires_variance : Tests { |
520
|
8
|
|
|
8
|
0
|
5949
|
my $self = shift; |
521
|
8
|
|
|
|
|
30
|
my $cache = $self->{cache}; |
522
|
|
|
|
|
|
|
|
523
|
8
|
|
|
|
|
77
|
my $start_time = time(); |
524
|
8
|
|
|
|
|
28
|
my $expires_at = $start_time + 10; |
525
|
8
|
|
|
|
|
44
|
my ( $key, $value ) = $self->kvpair(); |
526
|
8
|
|
|
|
|
154
|
$cache->set( $key, $value, |
527
|
|
|
|
|
|
|
{ expires_at => $expires_at, expires_variance => 0.5 } ); |
528
|
8
|
|
|
|
|
53
|
is( $cache->get_object($key)->expires_at(), |
529
|
|
|
|
|
|
|
$expires_at, "expires_at = $start_time" ); |
530
|
8
|
|
|
|
|
3602
|
is( |
531
|
|
|
|
|
|
|
$cache->get_object($key)->early_expires_at(), |
532
|
|
|
|
|
|
|
$start_time + 5, |
533
|
|
|
|
|
|
|
"early_expires_at = $start_time + 5" |
534
|
|
|
|
|
|
|
); |
535
|
|
|
|
|
|
|
|
536
|
8
|
|
|
|
|
2978
|
my %expire_count; |
537
|
8
|
|
|
|
|
72
|
for ( my $time = $start_time + 3 ; $time <= $expires_at + 1 ; $time++ ) { |
538
|
72
|
|
|
|
|
198
|
local $CHI::Driver::Test_Time = $time; |
539
|
72
|
|
|
|
|
204
|
for ( my $i = 0 ; $i < 100 ; $i++ ) { |
540
|
7200
|
100
|
|
|
|
70540
|
if ( !defined $cache->get($key) ) { |
541
|
3154
|
|
|
|
|
9694
|
$expire_count{$time}++; |
542
|
|
|
|
|
|
|
} |
543
|
|
|
|
|
|
|
} |
544
|
|
|
|
|
|
|
} |
545
|
8
|
|
|
|
|
79
|
for ( my $time = $start_time + 3 ; $time <= $start_time + 5 ; $time++ ) { |
546
|
24
|
|
|
|
|
8325
|
ok( !$expire_count{$time}, "got no expires at $time" ); |
547
|
|
|
|
|
|
|
} |
548
|
8
|
|
|
|
|
2796
|
for ( my $time = $start_time + 7 ; $time <= $start_time + 8 ; $time++ ) { |
549
|
16
|
|
33
|
|
|
3059
|
ok( $expire_count{$time} > 0 && $expire_count{$time} < 100, |
550
|
|
|
|
|
|
|
"got some expires at $time" ); |
551
|
|
|
|
|
|
|
} |
552
|
8
|
|
|
|
|
2802
|
for ( my $time = $expires_at ; $time <= $expires_at + 1 ; $time++ ) { |
553
|
16
|
|
|
|
|
2856
|
ok( $expire_count{$time} == 100, "got all expires at $time" ); |
554
|
|
|
|
|
|
|
} |
555
|
9
|
|
|
9
|
|
5275
|
} |
|
9
|
|
|
|
|
25
|
|
|
9
|
|
|
|
|
58
|
|
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
sub test_not_in_cache : Tests { |
558
|
8
|
|
|
8
|
0
|
6564
|
my $self = shift; |
559
|
8
|
|
|
|
|
27
|
my $cache = $self->{cache}; |
560
|
|
|
|
|
|
|
|
561
|
8
|
|
|
|
|
49
|
ok( !defined $cache->get_object('not in cache') ); |
562
|
8
|
|
|
|
|
3750
|
ok( !defined $cache->get_expires_at('not in cache') ); |
563
|
8
|
|
|
|
|
2870
|
ok( !$cache->is_valid('not in cache') ); |
564
|
9
|
|
|
9
|
|
3022
|
} |
|
9
|
|
|
|
|
34
|
|
|
9
|
|
|
|
|
57
|
|
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
sub test_serialize : Tests { |
567
|
7
|
|
|
7
|
0
|
6656
|
my $self = shift; |
568
|
7
|
|
|
|
|
24
|
my $cache = $self->{cache}; |
569
|
7
|
|
|
|
|
45
|
$self->num_tests( $self->{key_count} ); |
570
|
|
|
|
|
|
|
|
571
|
7
|
|
|
|
|
808
|
$self->set_some_keys($cache); |
572
|
7
|
|
|
|
|
24
|
foreach my $keyname ( @{ $self->{keynames} } ) { |
|
7
|
|
|
|
|
37
|
|
573
|
91
|
100
|
100
|
|
|
33102
|
my $expect_transformed = |
|
|
100
|
|
|
|
|
|
574
|
|
|
|
|
|
|
( $keyname eq 'arrayref' || $keyname eq 'hashref' ) ? 1 |
575
|
|
|
|
|
|
|
: ( $keyname eq 'utf8' ) ? 2 |
576
|
|
|
|
|
|
|
: 0; |
577
|
|
|
|
|
|
|
is( |
578
|
91
|
|
|
|
|
413
|
$cache->get_object( $self->{keys}->{$keyname} )->_is_transformed(), |
579
|
|
|
|
|
|
|
$expect_transformed, |
580
|
|
|
|
|
|
|
"is_transformed = $expect_transformed ($keyname)" |
581
|
|
|
|
|
|
|
); |
582
|
|
|
|
|
|
|
} |
583
|
9
|
|
|
9
|
|
3671
|
} |
|
9
|
|
|
|
|
32
|
|
|
9
|
|
|
|
|
57
|
|
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
{ |
586
|
|
|
|
|
|
|
package DummySerializer; |
587
|
|
|
|
|
|
|
$DummySerializer::VERSION = '0.61'; |
588
|
|
|
|
0
|
|
|
sub serialize { } |
589
|
|
|
|
0
|
|
|
sub deserialize { } |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
sub test_serializers : Tests { |
593
|
7
|
|
|
7
|
0
|
16256
|
my ($self) = @_; |
594
|
|
|
|
|
|
|
|
595
|
7
|
50
|
|
|
|
54
|
unless ( can_load('Data::Serializer') ) { |
596
|
7
|
|
|
|
|
48
|
$self->num_tests(1); |
597
|
7
|
|
|
|
|
801
|
return 'Data::Serializer not installed'; |
598
|
|
|
|
|
|
|
} |
599
|
|
|
|
|
|
|
|
600
|
0
|
|
|
|
|
0
|
my @modes = (qw(string hash object)); |
601
|
0
|
|
|
|
|
0
|
my @variants = (qw(Storable Data::Dumper YAML)); |
602
|
0
|
|
|
|
|
0
|
@variants = grep { can_load($_) } @variants; |
|
0
|
|
|
|
|
0
|
|
603
|
0
|
|
|
|
|
0
|
ok( scalar(@variants), "some variants ok" ); |
604
|
|
|
|
|
|
|
|
605
|
0
|
|
|
|
|
0
|
my $initial_count = 5; |
606
|
0
|
|
|
|
|
0
|
my $test_key_types_count = $self->{key_count}; |
607
|
0
|
|
|
|
|
0
|
my $test_count = $initial_count + |
608
|
|
|
|
|
|
|
scalar(@variants) * scalar(@modes) * ( 1 + $test_key_types_count ); |
609
|
|
|
|
|
|
|
|
610
|
0
|
|
|
|
|
0
|
my $cache1 = $self->new_cache(); |
611
|
0
|
|
|
|
|
0
|
isa_ok( $cache1->serializer, 'CHI::Serializer::Storable' ); |
612
|
0
|
|
|
|
|
0
|
my $cache2 = $self->new_cache(); |
613
|
0
|
|
|
|
|
0
|
is( $cache1->serializer, $cache2->serializer, |
614
|
|
|
|
|
|
|
'same serializer returned from two objects' ); |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
throws_ok( |
617
|
|
|
|
|
|
|
sub { |
618
|
0
|
|
|
0
|
|
0
|
$self->new_cache( serializer => [1] ); |
619
|
|
|
|
|
|
|
}, |
620
|
0
|
|
|
|
|
0
|
qr/Validation failed for|isa check for ".*?" failed/, |
621
|
|
|
|
|
|
|
"invalid serializer" |
622
|
|
|
|
|
|
|
); |
623
|
|
|
|
|
|
|
lives_ok( |
624
|
0
|
|
|
0
|
|
0
|
sub { $self->new_cache( serializer => bless( {}, 'DummySerializer' ) ) } |
625
|
|
|
|
|
|
|
, |
626
|
0
|
|
|
|
|
0
|
"valid dummy serializer" |
627
|
|
|
|
|
|
|
); |
628
|
|
|
|
|
|
|
|
629
|
0
|
|
|
|
|
0
|
foreach my $mode (@modes) { |
630
|
0
|
|
|
|
|
0
|
foreach my $variant (@variants) { |
631
|
0
|
0
|
|
|
|
0
|
my $serializer_param = ( |
|
|
0
|
|
|
|
|
|
632
|
|
|
|
|
|
|
$mode eq 'string' ? $variant |
633
|
|
|
|
|
|
|
: $mode eq 'hash' ? { serializer => $variant } |
634
|
|
|
|
|
|
|
: Data::Serializer->new( serializer => $variant ) |
635
|
|
|
|
|
|
|
); |
636
|
0
|
|
|
|
|
0
|
my $cache = $self->new_cache( serializer => $serializer_param ); |
637
|
0
|
|
|
|
|
0
|
is( $cache->serializer->serializer, |
638
|
|
|
|
|
|
|
$variant, "serializer = $variant, mode = $mode" ); |
639
|
0
|
|
|
|
|
0
|
$self->{cache} = $cache; |
640
|
|
|
|
|
|
|
|
641
|
0
|
|
|
|
|
0
|
foreach my $keyname ( @{ $self->{keynames} } ) { |
|
0
|
|
|
|
|
0
|
|
642
|
0
|
|
|
|
|
0
|
my $key = $self->{keys}->{$keyname}; |
643
|
0
|
|
|
|
|
0
|
my $value = $self->{values}->{$keyname}; |
644
|
0
|
|
|
|
|
0
|
$cache->set( $key, $value ); |
645
|
0
|
|
|
|
|
0
|
cmp_deeply( $cache->get($key), $value, |
646
|
|
|
|
|
|
|
"hit for key '$keyname'" ); |
647
|
|
|
|
|
|
|
} |
648
|
|
|
|
|
|
|
|
649
|
0
|
|
|
|
|
0
|
$self->num_tests($test_count); |
650
|
|
|
|
|
|
|
} |
651
|
|
|
|
|
|
|
} |
652
|
9
|
|
|
9
|
|
7509
|
} |
|
9
|
|
|
|
|
20
|
|
|
9
|
|
|
|
|
80
|
|
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
sub test_namespaces : Tests { |
655
|
8
|
|
|
8
|
0
|
6169
|
my $self = shift; |
656
|
8
|
|
|
|
|
22
|
my $cache = $self->{cache}; |
657
|
|
|
|
|
|
|
|
658
|
8
|
|
|
|
|
38
|
my $cache0 = $self->new_cache(); |
659
|
8
|
|
|
|
|
119
|
is( $cache0->namespace, 'Default', 'namespace defaults to "Default"' ); |
660
|
|
|
|
|
|
|
|
661
|
8
|
|
|
|
|
3770
|
my ( $ns1, $ns2, $ns3 ) = ( 'ns1', 'ns2', 'ns3' ); |
662
|
|
|
|
|
|
|
my ( $cache1, $cache1a, $cache2, $cache3 ) = |
663
|
8
|
|
|
|
|
35
|
map { $self->new_cache( namespace => $_ ) } ( $ns1, $ns1, $ns2, $ns3 ); |
|
32
|
|
|
|
|
96
|
|
664
|
|
|
|
|
|
|
cmp_deeply( |
665
|
8
|
|
|
|
|
41
|
[ map { $_->namespace } ( $cache1, $cache1a, $cache2, $cache3 ) ], |
|
32
|
|
|
|
|
137
|
|
666
|
|
|
|
|
|
|
[ $ns1, $ns1, $ns2, $ns3 ], |
667
|
|
|
|
|
|
|
'cache->namespace()' |
668
|
|
|
|
|
|
|
); |
669
|
8
|
|
|
|
|
13360
|
$self->set_some_keys($cache1); |
670
|
8
|
|
|
|
|
230
|
cmp_deeply( |
671
|
|
|
|
|
|
|
$cache1->dump_as_hash(), |
672
|
|
|
|
|
|
|
$cache1a->dump_as_hash(), |
673
|
|
|
|
|
|
|
'cache1 and cache1a are same cache' |
674
|
|
|
|
|
|
|
); |
675
|
8
|
|
|
|
|
36606
|
cmp_deeply( [ $cache2->get_keys() ], |
676
|
|
|
|
|
|
|
[], 'cache2 empty after setting keys in cache1' ); |
677
|
8
|
|
|
|
|
11737
|
$cache3->set( $self->{keys}->{medium}, 'different' ); |
678
|
|
|
|
|
|
|
is( |
679
|
|
|
|
|
|
|
$cache1->get('medium'), |
680
|
|
|
|
|
|
|
$self->{values}->{medium}, |
681
|
8
|
|
|
|
|
108
|
'cache1{medium} = medium' |
682
|
|
|
|
|
|
|
); |
683
|
8
|
|
|
|
|
3629
|
is( $cache3->get('medium'), 'different', 'cache1{medium} = different' ); |
684
|
|
|
|
|
|
|
|
685
|
8
|
50
|
|
|
|
3201
|
if ( $self->supports_get_namespaces() ) { |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
# get_namespaces may or may not automatically include empty namespaces |
688
|
8
|
|
|
|
|
281
|
cmp_deeply( |
689
|
|
|
|
|
|
|
[ $cache1->get_namespaces() ], |
690
|
|
|
|
|
|
|
supersetof( $ns1, $ns3 ), |
691
|
|
|
|
|
|
|
"get_namespaces contains $ns1 and $ns3" |
692
|
|
|
|
|
|
|
); |
693
|
|
|
|
|
|
|
|
694
|
8
|
|
|
|
|
13317
|
foreach my $c ( $cache0, $cache1, $cache1a, $cache2, $cache3 ) { |
695
|
40
|
|
|
|
|
93022
|
cmp_set( |
696
|
|
|
|
|
|
|
[ $cache->get_namespaces() ], |
697
|
|
|
|
|
|
|
[ $c->get_namespaces() ], |
698
|
|
|
|
|
|
|
'get_namespaces the same regardless of which cache asks' |
699
|
|
|
|
|
|
|
); |
700
|
|
|
|
|
|
|
} |
701
|
|
|
|
|
|
|
} |
702
|
|
|
|
|
|
|
else { |
703
|
|
|
|
|
|
|
throws_ok( |
704
|
0
|
|
|
0
|
|
0
|
sub { $cache1->get_namespaces() }, |
705
|
0
|
|
|
|
|
0
|
qr/not supported/, |
706
|
|
|
|
|
|
|
"get_namespaces not supported" |
707
|
|
|
|
|
|
|
); |
708
|
0
|
|
|
|
|
0
|
SKIP: { skip "get_namespaces not supported", 5 } |
|
0
|
|
|
|
|
0
|
|
709
|
|
|
|
|
|
|
} |
710
|
9
|
|
|
9
|
|
5848
|
} |
|
9
|
|
|
|
|
32
|
|
|
9
|
|
|
|
|
89
|
|
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
sub test_persist : Tests { |
713
|
8
|
|
|
8
|
0
|
7520
|
my $self = shift; |
714
|
8
|
|
|
|
|
28
|
my $cache = $self->{cache}; |
715
|
|
|
|
|
|
|
|
716
|
8
|
|
|
|
|
21
|
my $hash; |
717
|
|
|
|
|
|
|
{ |
718
|
8
|
|
|
|
|
18
|
my $cache1 = $self->new_cache(); |
|
8
|
|
|
|
|
35
|
|
719
|
8
|
|
|
|
|
139
|
$self->set_some_keys($cache1); |
720
|
8
|
|
|
|
|
55
|
$hash = $cache1->dump_as_hash(); |
721
|
|
|
|
|
|
|
} |
722
|
8
|
|
|
|
|
60
|
my $cache2 = $self->new_cache(); |
723
|
8
|
|
|
|
|
53
|
cmp_deeply( |
724
|
|
|
|
|
|
|
$hash, |
725
|
|
|
|
|
|
|
$cache2->dump_as_hash(), |
726
|
|
|
|
|
|
|
'cache persisted between cache object creations' |
727
|
|
|
|
|
|
|
); |
728
|
9
|
|
|
9
|
|
3295
|
} |
|
9
|
|
|
|
|
25
|
|
|
9
|
|
|
|
|
46
|
|
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
sub test_multi : Tests { |
731
|
8
|
|
|
8
|
0
|
6264
|
my $self = shift; |
732
|
8
|
|
|
|
|
28
|
my $cache = $self->{cache}; |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
my ( $keys, $values, $keynames ) = |
735
|
8
|
|
|
|
|
49
|
( $self->{keys}, $self->{values}, $self->{keynames} ); |
736
|
|
|
|
|
|
|
|
737
|
8
|
|
|
|
|
39
|
my @ordered_keys = map { $keys->{$_} } @{$keynames}; |
|
104
|
|
|
|
|
248
|
|
|
8
|
|
|
|
|
31
|
|
738
|
|
|
|
|
|
|
my @ordered_values = |
739
|
8
|
|
|
|
|
24
|
map { $values->{$_} } @{$keynames}; |
|
104
|
|
|
|
|
196
|
|
|
8
|
|
|
|
|
26
|
|
740
|
|
|
|
|
|
|
my %ordered_scalar_key_values = |
741
|
88
|
|
|
|
|
270
|
map { ( $keys->{$_}, $values->{$_} ) } |
742
|
8
|
|
|
|
|
24
|
grep { !ref( $keys->{$_} ) } @{$keynames}; |
|
104
|
|
|
|
|
213
|
|
|
8
|
|
|
|
|
35
|
|
743
|
|
|
|
|
|
|
|
744
|
8
|
|
|
|
|
95
|
cmp_deeply( $cache->get_multi_arrayref( ['foo'] ), |
745
|
|
|
|
|
|
|
[undef], "get_multi_arrayref before set" ); |
746
|
|
|
|
|
|
|
|
747
|
8
|
|
|
|
|
13601
|
$cache->set_multi( \%ordered_scalar_key_values ); |
748
|
8
|
|
|
|
|
117
|
$cache->set( $keys->{arrayref}, $values->{arrayref} ); |
749
|
8
|
|
|
|
|
107
|
$cache->set( $keys->{hashref}, $values->{hashref} ); |
750
|
|
|
|
|
|
|
|
751
|
8
|
|
|
|
|
69
|
cmp_deeply( $cache->get_multi_arrayref( \@ordered_keys ), |
752
|
|
|
|
|
|
|
\@ordered_values, "get_multi_arrayref" ); |
753
|
8
|
|
|
|
|
36020
|
cmp_deeply( $cache->get( $ordered_keys[0] ), |
754
|
|
|
|
|
|
|
$ordered_values[0], "get one after set_multi" ); |
755
|
8
|
|
|
|
|
4852
|
cmp_deeply( |
756
|
|
|
|
|
|
|
$cache->get_multi_arrayref( [ reverse @ordered_keys ] ), |
757
|
|
|
|
|
|
|
[ reverse @ordered_values ], |
758
|
|
|
|
|
|
|
"get_multi_arrayref" |
759
|
|
|
|
|
|
|
); |
760
|
|
|
|
|
|
|
cmp_deeply( |
761
|
8
|
|
|
|
|
35057
|
$cache->get_multi_hashref( [ grep { !ref($_) } @ordered_keys ] ), |
|
104
|
|
|
|
|
239
|
|
762
|
|
|
|
|
|
|
\%ordered_scalar_key_values, "get_multi_hashref" ); |
763
|
8
|
|
|
|
|
15876
|
cmp_set( |
764
|
|
|
|
|
|
|
[ $cache->get_keys ], |
765
|
|
|
|
|
|
|
[ $self->process_keys( $cache, @ordered_keys ) ], |
766
|
|
|
|
|
|
|
"get_keys after set_multi" |
767
|
|
|
|
|
|
|
); |
768
|
|
|
|
|
|
|
|
769
|
8
|
|
|
|
|
160499
|
$cache->remove_multi( \@ordered_keys ); |
770
|
8
|
|
|
|
|
270
|
cmp_deeply( |
771
|
|
|
|
|
|
|
$cache->get_multi_arrayref( \@ordered_keys ), |
772
|
|
|
|
|
|
|
[ (undef) x scalar(@ordered_values) ], |
773
|
|
|
|
|
|
|
"get_multi_arrayref after remove_multi" |
774
|
|
|
|
|
|
|
); |
775
|
8
|
|
|
|
|
14444
|
cmp_set( [ $cache->get_keys ], [], "get_keys after remove_multi" ); |
776
|
9
|
|
|
9
|
|
5538
|
} |
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
91
|
|
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
sub test_multi_no_keys : Tests { |
779
|
8
|
|
|
8
|
0
|
14341
|
my $self = shift; |
780
|
8
|
|
|
|
|
25
|
my $cache = $self->{cache}; |
781
|
|
|
|
|
|
|
|
782
|
8
|
|
|
|
|
75
|
cmp_deeply( $cache->get_multi_arrayref( [] ), |
783
|
|
|
|
|
|
|
[], "get_multi_arrayref (no args)" ); |
784
|
8
|
|
|
|
|
12572
|
cmp_deeply( $cache->get_multi_hashref( [] ), |
785
|
|
|
|
|
|
|
{}, "get_multi_hashref (no args)" ); |
786
|
8
|
|
|
8
|
|
11936
|
lives_ok { $cache->set_multi( {} ) } "set_multi (no args)"; |
|
8
|
|
|
|
|
396
|
|
787
|
8
|
|
|
8
|
|
3239
|
lives_ok { $cache->remove_multi( [] ) } "remove_multi (no args)"; |
|
8
|
|
|
|
|
268
|
|
788
|
9
|
|
|
9
|
|
3443
|
} |
|
9
|
|
|
|
|
19
|
|
|
9
|
|
|
|
|
51
|
|
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
sub test_l1_cache : Tests { |
791
|
6
|
|
|
6
|
0
|
5591
|
my $self = shift; |
792
|
6
|
|
|
|
|
26
|
my @keys = map { "key$_" } ( 0 .. 2 ); |
|
18
|
|
|
|
|
63
|
|
793
|
6
|
|
|
|
|
22
|
my @values = map { "value$_" } ( 0 .. 2 ); |
|
18
|
|
|
|
|
52
|
|
794
|
6
|
|
|
|
|
17
|
my ( $cache, $l1_cache ); |
795
|
|
|
|
|
|
|
|
796
|
6
|
50
|
|
|
|
24
|
return "skipping - no support for clear" unless $self->supports_clear(); |
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
my $test_l1_cache = sub { |
799
|
|
|
|
|
|
|
|
800
|
12
|
|
|
12
|
|
144
|
is( $l1_cache->subcache_type, "l1_cache", "subcache_type = l1_cache" ); |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
# Get on cache should populate l1 cache |
803
|
|
|
|
|
|
|
# |
804
|
12
|
|
|
|
|
5224
|
$cache->set( $keys[0], $values[0] ); |
805
|
12
|
|
|
|
|
169
|
$l1_cache->clear(); |
806
|
12
|
|
|
|
|
1336
|
ok( !$l1_cache->get( $keys[0] ), "l1 miss after clear" ); |
807
|
12
|
|
|
|
|
5895
|
is( $cache->get( $keys[0] ), |
808
|
|
|
|
|
|
|
$values[0], "primary hit after primary set" ); |
809
|
12
|
|
|
|
|
5088
|
is( $l1_cache->get( $keys[0] ), $values[0], |
810
|
|
|
|
|
|
|
"l1 hit after primary get" ); |
811
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
# Primary cache should be reading l1 cache first |
813
|
|
|
|
|
|
|
# |
814
|
12
|
|
|
|
|
4877
|
$l1_cache->set( $keys[0], $values[1] ); |
815
|
12
|
|
|
|
|
297
|
is( $cache->get( $keys[0] ), |
816
|
|
|
|
|
|
|
$values[1], "got new value set explicitly in l1 cache" ); |
817
|
12
|
|
|
|
|
5225
|
$l1_cache->remove( $keys[0] ); |
818
|
12
|
|
|
|
|
533
|
is( $cache->get( $keys[0] ), $values[0], "got old value again" ); |
819
|
|
|
|
|
|
|
|
820
|
12
|
|
|
|
|
5223
|
$cache->clear(); |
821
|
12
|
|
|
|
|
1503
|
ok( !$cache->get( $keys[0] ), "miss after clear" ); |
822
|
12
|
|
|
|
|
4594
|
ok( !$l1_cache->get( $keys[0] ), "miss after clear" ); |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
# get_multi_* - one from l1 cache, one from primary cache, one miss |
825
|
|
|
|
|
|
|
# |
826
|
12
|
|
|
|
|
4830
|
$cache->set( $keys[0], $values[0] ); |
827
|
12
|
|
|
|
|
368
|
$cache->set( $keys[1], $values[1] ); |
828
|
12
|
|
|
|
|
306
|
$l1_cache->remove( $keys[0] ); |
829
|
12
|
|
|
|
|
264
|
$l1_cache->set( $keys[1], $values[2] ); |
830
|
|
|
|
|
|
|
|
831
|
12
|
|
|
|
|
403
|
cmp_deeply( |
832
|
|
|
|
|
|
|
$cache->get_multi_arrayref( [ $keys[0], $keys[1], $keys[2] ] ), |
833
|
|
|
|
|
|
|
[ $values[0], $values[2], undef ], |
834
|
|
|
|
|
|
|
"get_multi_arrayref" |
835
|
|
|
|
|
|
|
); |
836
|
12
|
|
|
|
|
21367
|
cmp_deeply( |
837
|
|
|
|
|
|
|
$cache->get_multi_hashref( [ $keys[0], $keys[1], $keys[2] ] ), |
838
|
|
|
|
|
|
|
{ |
839
|
|
|
|
|
|
|
$keys[0] => $values[0], |
840
|
|
|
|
|
|
|
$keys[1] => $values[2], |
841
|
|
|
|
|
|
|
$keys[2] => undef |
842
|
|
|
|
|
|
|
}, |
843
|
|
|
|
|
|
|
"get_multi_hashref" |
844
|
|
|
|
|
|
|
); |
845
|
|
|
|
|
|
|
|
846
|
12
|
|
|
|
|
26454
|
$self->_test_logging_with_l1_cache( $cache, $l1_cache ); |
847
|
|
|
|
|
|
|
|
848
|
12
|
|
|
|
|
4685
|
$self->_test_common_subcache_features( $cache, $l1_cache, 'l1_cache' ); |
849
|
6
|
|
|
|
|
40
|
}; |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
# Test with current cache in primary position... |
852
|
|
|
|
|
|
|
# |
853
|
6
|
|
|
|
|
39
|
$cache = |
854
|
|
|
|
|
|
|
$self->new_cache( l1_cache => { driver => 'Memory', datastore => {} } ); |
855
|
6
|
|
|
|
|
159
|
$l1_cache = $cache->l1_cache; |
856
|
6
|
|
|
|
|
756
|
isa_ok( $cache, $self->testing_driver_class, 'cache' ); |
857
|
6
|
|
|
|
|
4361
|
isa_ok( $l1_cache, 'CHI::Driver::Memory', 'l1_cache' ); |
858
|
6
|
|
|
|
|
2468
|
$test_l1_cache->(); |
859
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
# and in l1 position |
861
|
|
|
|
|
|
|
# |
862
|
6
|
|
|
|
|
2638
|
$cache = $self->testing_chi_root_class->new( |
863
|
|
|
|
|
|
|
driver => 'Memory', |
864
|
|
|
|
|
|
|
datastore => {}, |
865
|
|
|
|
|
|
|
l1_cache => { $self->new_cache_options() } |
866
|
|
|
|
|
|
|
); |
867
|
6
|
|
|
|
|
170
|
$l1_cache = $cache->l1_cache; |
868
|
6
|
|
|
|
|
888
|
isa_ok( $cache, 'CHI::Driver::Memory', 'cache' ); |
869
|
6
|
|
|
|
|
4532
|
isa_ok( $l1_cache, $self->testing_driver_class, 'l1_cache' ); |
870
|
6
|
|
|
|
|
2643
|
$test_l1_cache->(); |
871
|
9
|
|
|
9
|
|
7100
|
} |
|
9
|
|
|
|
|
19
|
|
|
9
|
|
|
|
|
105
|
|
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
sub test_mirror_cache : Tests { |
874
|
6
|
|
|
6
|
0
|
4615
|
my $self = shift; |
875
|
6
|
|
|
|
|
19
|
my ( $cache, $mirror_cache ); |
876
|
6
|
|
|
|
|
34
|
my ( $key, $value, $key2, $value2 ) = $self->kvpair(2); |
877
|
|
|
|
|
|
|
|
878
|
6
|
50
|
|
|
|
31
|
return "skipping - no support for clear" unless $self->supports_clear(); |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
my $test_mirror_cache = sub { |
881
|
|
|
|
|
|
|
|
882
|
12
|
|
|
12
|
|
111
|
is( $mirror_cache->subcache_type, "mirror_cache" ); |
883
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
# Get on either cache should not populate the other, and should not be able to see |
885
|
|
|
|
|
|
|
# mirror keys from regular cache |
886
|
|
|
|
|
|
|
# |
887
|
12
|
|
|
|
|
5292
|
$cache->set( $key, $value ); |
888
|
12
|
|
|
|
|
349
|
$mirror_cache->remove($key); |
889
|
12
|
|
|
|
|
604
|
$cache->get($key); |
890
|
12
|
|
|
|
|
79
|
ok( !$mirror_cache->get($key), "key not in mirror_cache" ); |
891
|
|
|
|
|
|
|
|
892
|
12
|
|
|
|
|
5887
|
$mirror_cache->set( $key2, $value2 ); |
893
|
12
|
|
|
|
|
299
|
ok( !$cache->get($key2), "key2 not in cache" ); |
894
|
|
|
|
|
|
|
|
895
|
12
|
|
|
|
|
5101
|
$self->_test_logging_with_mirror_cache( $cache, $mirror_cache ); |
896
|
|
|
|
|
|
|
|
897
|
12
|
|
|
|
|
4893
|
$self->_test_common_subcache_features( $cache, $mirror_cache, |
898
|
|
|
|
|
|
|
'mirror_cache' ); |
899
|
6
|
|
|
|
|
38
|
}; |
900
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
my $file_cache_options = sub { |
902
|
12
|
|
|
12
|
|
112
|
my $root_dir = |
903
|
|
|
|
|
|
|
tempdir( "chi-test-mirror-cache-XXXX", TMPDIR => 1, CLEANUP => 1 ); |
904
|
12
|
|
|
|
|
6907
|
return ( driver => 'File', root_dir => $root_dir, depth => 3 ); |
905
|
6
|
|
|
|
|
26
|
}; |
906
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
# Test with current cache in primary position... |
908
|
|
|
|
|
|
|
# |
909
|
6
|
|
|
|
|
24
|
$cache = $self->new_cache( mirror_cache => { $file_cache_options->() } ); |
910
|
6
|
|
|
|
|
177
|
$mirror_cache = $cache->mirror_cache; |
911
|
6
|
|
|
|
|
722
|
isa_ok( $cache, $self->testing_driver_class ); |
912
|
6
|
|
|
|
|
3778
|
isa_ok( $mirror_cache, 'CHI::Driver::File' ); |
913
|
6
|
|
|
|
|
2578
|
$test_mirror_cache->(); |
914
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
# and in mirror position |
916
|
|
|
|
|
|
|
# |
917
|
6
|
|
|
|
|
2493
|
$cache = |
918
|
|
|
|
|
|
|
$self->testing_chi_root_class->new( $file_cache_options->(), |
919
|
|
|
|
|
|
|
mirror_cache => { $self->new_cache_options() } ); |
920
|
6
|
|
|
|
|
166
|
$mirror_cache = $cache->mirror_cache; |
921
|
6
|
|
|
|
|
866
|
isa_ok( $cache, 'CHI::Driver::File' ); |
922
|
6
|
|
|
|
|
3476
|
isa_ok( $mirror_cache, $self->testing_driver_class ); |
923
|
6
|
|
|
|
|
2628
|
$test_mirror_cache->(); |
924
|
9
|
|
|
9
|
|
5362
|
} |
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
50
|
|
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
sub test_subcache_overridable_params : Tests { |
927
|
7
|
|
|
7
|
0
|
5245
|
my ($self) = @_; |
928
|
|
|
|
|
|
|
|
929
|
7
|
|
|
|
|
19
|
my $cache; |
930
|
|
|
|
|
|
|
warning_like { |
931
|
7
|
|
|
7
|
|
517
|
$cache = $self->new_cache( |
932
|
|
|
|
|
|
|
l1_cache => { |
933
|
|
|
|
|
|
|
driver => 'Memory', |
934
|
|
|
|
|
|
|
on_get_error => 'log', |
935
|
|
|
|
|
|
|
datastore => {}, |
936
|
|
|
|
|
|
|
expires_variance => 0.5, |
937
|
|
|
|
|
|
|
serializer => 'Foo' |
938
|
|
|
|
|
|
|
} |
939
|
|
|
|
|
|
|
); |
940
|
|
|
|
|
|
|
} |
941
|
7
|
|
|
|
|
93
|
qr/cannot override these keys/, "non-overridable subcache keys"; |
942
|
7
|
|
|
|
|
3444
|
is( $cache->l1_cache->expires_variance, $cache->expires_variance ); |
943
|
7
|
|
|
|
|
2943
|
is( $cache->l1_cache->serializer, $cache->serializer ); |
944
|
7
|
|
|
|
|
2820
|
is( $cache->l1_cache->on_set_error, $cache->on_set_error ); |
945
|
7
|
|
|
|
|
2720
|
is( $cache->l1_cache->on_get_error, 'log' ); |
946
|
9
|
|
|
9
|
|
4121
|
} |
|
9
|
|
|
|
|
28
|
|
|
9
|
|
|
|
|
43
|
|
947
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
# Run logging tests for a cache with an l1_cache |
949
|
|
|
|
|
|
|
# |
950
|
|
|
|
|
|
|
sub _test_logging_with_l1_cache { |
951
|
12
|
|
|
12
|
|
51
|
my ( $self, $cache ) = @_; |
952
|
|
|
|
|
|
|
|
953
|
12
|
|
|
|
|
447
|
$cache->clear(); |
954
|
12
|
|
|
|
|
2231
|
my $log = activate_test_logger(); |
955
|
12
|
|
|
|
|
71
|
my ( $key, $value ) = $self->kvpair(); |
956
|
|
|
|
|
|
|
|
957
|
12
|
|
|
|
|
318
|
my $driver = $cache->label; |
958
|
|
|
|
|
|
|
|
959
|
12
|
|
|
|
|
118
|
my $miss_not_in_cache = 'MISS \(not in cache\)'; |
960
|
12
|
|
|
|
|
29
|
my $miss_expired = 'MISS \(expired\)'; |
961
|
|
|
|
|
|
|
|
962
|
12
|
|
|
|
|
33
|
my $start_time = time(); |
963
|
|
|
|
|
|
|
|
964
|
12
|
|
|
|
|
246
|
$cache->get($key); |
965
|
12
|
|
|
|
|
708
|
$log->contains_ok( |
966
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_not_in_cache/ |
967
|
|
|
|
|
|
|
); |
968
|
12
|
|
|
|
|
6398
|
$log->contains_ok( |
969
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='.*l1.*', time='[-\d]+ms': $miss_not_in_cache/ |
970
|
|
|
|
|
|
|
); |
971
|
12
|
|
|
|
|
5161
|
$log->empty_ok(); |
972
|
|
|
|
|
|
|
|
973
|
12
|
|
|
|
|
4928
|
$cache->set( $key, $value, 81 ); |
974
|
12
|
|
|
|
|
533
|
$log->contains_ok( |
975
|
|
|
|
|
|
|
qr/cache set for .* key='$key', size=\d+, expires='1m2[012]s', cache='$driver', time='[-\d]+ms'/ |
976
|
|
|
|
|
|
|
); |
977
|
|
|
|
|
|
|
|
978
|
12
|
|
|
|
|
5607
|
$log->contains_ok( |
979
|
|
|
|
|
|
|
qr/cache set for .* key='$key', size=\d+, expires='1m2[012]s', cache='.*l1.*', time='[-\d]+ms'/ |
980
|
|
|
|
|
|
|
); |
981
|
12
|
|
|
|
|
4967
|
$log->empty_ok(); |
982
|
|
|
|
|
|
|
|
983
|
12
|
|
|
|
|
4786
|
$cache->get($key); |
984
|
12
|
|
|
|
|
249
|
$log->contains_ok( |
985
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='.*l1.*', time='[-\d]+ms': HIT/); |
986
|
12
|
|
|
|
|
5429
|
$log->empty_ok(); |
987
|
|
|
|
|
|
|
|
988
|
12
|
|
|
|
|
4475
|
local $CHI::Driver::Test_Time = $start_time + 120; |
989
|
12
|
|
|
|
|
343
|
$cache->get($key); |
990
|
12
|
|
|
|
|
813
|
$log->contains_ok( |
991
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_expired/ |
992
|
|
|
|
|
|
|
); |
993
|
12
|
|
|
|
|
5427
|
$log->contains_ok( |
994
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='.*l1.*', time='[-\d]+ms': $miss_expired/ |
995
|
|
|
|
|
|
|
); |
996
|
12
|
|
|
|
|
4804
|
$log->empty_ok(); |
997
|
|
|
|
|
|
|
|
998
|
12
|
|
|
|
|
4745
|
$cache->remove($key); |
999
|
12
|
|
|
|
|
573
|
$cache->get($key); |
1000
|
12
|
|
|
|
|
411
|
$log->contains_ok( |
1001
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_not_in_cache/ |
1002
|
|
|
|
|
|
|
); |
1003
|
12
|
|
|
|
|
5400
|
$log->contains_ok( |
1004
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='.*l1.*', time='[-\d]+ms': $miss_not_in_cache/ |
1005
|
|
|
|
|
|
|
); |
1006
|
12
|
|
|
|
|
4932
|
$log->empty_ok(); |
1007
|
|
|
|
|
|
|
} |
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
sub _test_logging_with_mirror_cache { |
1010
|
12
|
|
|
12
|
|
42
|
my ( $self, $cache ) = @_; |
1011
|
|
|
|
|
|
|
|
1012
|
12
|
|
|
|
|
374
|
$cache->clear(); |
1013
|
12
|
|
|
|
|
2171
|
my $log = activate_test_logger(); |
1014
|
12
|
|
|
|
|
76
|
my ( $key, $value ) = $self->kvpair(); |
1015
|
|
|
|
|
|
|
|
1016
|
12
|
|
|
|
|
332
|
my $driver = $cache->label; |
1017
|
|
|
|
|
|
|
|
1018
|
12
|
|
|
|
|
112
|
my $miss_not_in_cache = 'MISS \(not in cache\)'; |
1019
|
12
|
|
|
|
|
30
|
my $miss_expired = 'MISS \(expired\)'; |
1020
|
|
|
|
|
|
|
|
1021
|
12
|
|
|
|
|
32
|
my $start_time = time(); |
1022
|
|
|
|
|
|
|
|
1023
|
12
|
|
|
|
|
248
|
$cache->get($key); |
1024
|
12
|
|
|
|
|
706
|
$log->contains_ok( |
1025
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_not_in_cache/ |
1026
|
|
|
|
|
|
|
); |
1027
|
12
|
|
|
|
|
6295
|
$log->empty_ok(); |
1028
|
|
|
|
|
|
|
|
1029
|
12
|
|
|
|
|
4791
|
$cache->set( $key, $value, 81 ); |
1030
|
12
|
|
|
|
|
621
|
$log->contains_ok( |
1031
|
|
|
|
|
|
|
qr/cache set for .* key='$key', size=\d+, expires='1m2[012]s', cache='$driver', time='[-\d]+ms'/ |
1032
|
|
|
|
|
|
|
); |
1033
|
|
|
|
|
|
|
|
1034
|
12
|
|
|
|
|
6222
|
$log->contains_ok( |
1035
|
|
|
|
|
|
|
qr/cache set for .* key='$key', size=\d+, expires='1m2[012]s', cache='.*mirror.*', time='[-\d]+ms'/ |
1036
|
|
|
|
|
|
|
); |
1037
|
12
|
|
|
|
|
5005
|
$log->empty_ok(); |
1038
|
|
|
|
|
|
|
|
1039
|
12
|
|
|
|
|
4809
|
$cache->get($key); |
1040
|
12
|
|
|
|
|
421
|
$log->contains_ok( |
1041
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': HIT/); |
1042
|
12
|
|
|
|
|
5070
|
$log->empty_ok(); |
1043
|
|
|
|
|
|
|
|
1044
|
12
|
|
|
|
|
4334
|
local $CHI::Driver::Test_Time = $start_time + 120; |
1045
|
12
|
|
|
|
|
390
|
$cache->get($key); |
1046
|
12
|
|
|
|
|
423
|
$log->contains_ok( |
1047
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_expired/ |
1048
|
|
|
|
|
|
|
); |
1049
|
12
|
|
|
|
|
5163
|
$log->empty_ok(); |
1050
|
|
|
|
|
|
|
|
1051
|
12
|
|
|
|
|
4698
|
$cache->remove($key); |
1052
|
12
|
|
|
|
|
539
|
$cache->get($key); |
1053
|
12
|
|
|
|
|
388
|
$log->contains_ok( |
1054
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_not_in_cache/ |
1055
|
|
|
|
|
|
|
); |
1056
|
12
|
|
|
|
|
5340
|
$log->empty_ok(); |
1057
|
|
|
|
|
|
|
} |
1058
|
|
|
|
|
|
|
|
1059
|
|
|
|
|
|
|
# Run tests common to l1_cache and mirror_cache |
1060
|
|
|
|
|
|
|
# |
1061
|
|
|
|
|
|
|
sub _test_common_subcache_features { |
1062
|
24
|
|
|
24
|
|
104
|
my ( $self, $cache, $subcache, $subcache_type ) = @_; |
1063
|
24
|
|
|
|
|
114
|
my ( $key, $value, $key2, $value2 ) = $self->kvpair(2); |
1064
|
|
|
|
|
|
|
|
1065
|
24
|
|
|
|
|
97
|
for ( $cache, $subcache ) { $_->clear() } |
|
48
|
|
|
|
|
3059
|
|
1066
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
# Test informational methods |
1068
|
|
|
|
|
|
|
# |
1069
|
24
|
|
|
|
|
596
|
ok( !$cache->is_subcache, "is_subcache - false" ); |
1070
|
24
|
|
|
|
|
10009
|
ok( $subcache->is_subcache, "is_subcache - true" ); |
1071
|
24
|
|
|
|
|
9379
|
ok( $cache->has_subcaches, "has_subcaches - true" ); |
1072
|
24
|
|
|
|
|
10469
|
ok( !$subcache->has_subcaches, "has_subcaches - false" ); |
1073
|
24
|
|
|
|
|
9894
|
ok( !$cache->can('parent_cache'), "parent_cache - cannot" ); |
1074
|
24
|
|
|
|
|
8915
|
is( $subcache->parent_cache, $cache, "parent_cache - defined" ); |
1075
|
24
|
|
|
|
|
9765
|
ok( !$cache->can('subcache_type'), "subcache_type - cannot" ); |
1076
|
24
|
|
|
|
|
8674
|
is( $subcache->subcache_type, $subcache_type, "subcache_type - defined" ); |
1077
|
24
|
|
|
|
|
9855
|
cmp_deeply( $cache->subcaches, [$subcache], "subcaches - defined" ); |
1078
|
24
|
|
|
|
|
39414
|
ok( !$subcache->can('subcaches'), "subcaches - cannot" ); |
1079
|
24
|
|
|
|
|
9447
|
is( $cache->$subcache_type, $subcache, "$subcache_type - defined" ); |
1080
|
24
|
|
|
|
|
9856
|
ok( !$subcache->can($subcache_type), "$subcache_type - cannot" ); |
1081
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
# Test that sets and various kinds of removals and expirations are distributed to both |
1083
|
|
|
|
|
|
|
# the primary cache and the subcache |
1084
|
|
|
|
|
|
|
# |
1085
|
24
|
|
|
|
|
8667
|
my ( $test_remove_method, $confirm_caches_empty, |
1086
|
|
|
|
|
|
|
$confirm_caches_populated ); |
1087
|
|
|
|
|
|
|
$test_remove_method = sub { |
1088
|
72
|
|
|
72
|
|
276
|
my ( $desc, $remove_code ) = @_; |
1089
|
72
|
|
|
|
|
227
|
$desc = "testing $desc"; |
1090
|
|
|
|
|
|
|
|
1091
|
72
|
|
|
|
|
321
|
$confirm_caches_empty->("$desc: before set"); |
1092
|
|
|
|
|
|
|
|
1093
|
72
|
|
|
|
|
29442
|
$cache->set( $key, $value ); |
1094
|
72
|
|
|
|
|
1717
|
$cache->set( $key2, $value2 ); |
1095
|
72
|
|
|
|
|
727
|
$confirm_caches_populated->("$desc: after set"); |
1096
|
72
|
|
|
|
|
28226
|
$remove_code->(); |
1097
|
|
|
|
|
|
|
|
1098
|
72
|
|
|
|
|
5429
|
$confirm_caches_empty->("$desc: before set_multi"); |
1099
|
72
|
|
|
|
|
28745
|
$cache->set_multi( { $key => $value, $key2 => $value2 } ); |
1100
|
72
|
|
|
|
|
1087
|
$confirm_caches_populated->("$desc: after set_multi"); |
1101
|
72
|
|
|
|
|
28488
|
$remove_code->(); |
1102
|
|
|
|
|
|
|
|
1103
|
72
|
|
|
|
|
5338
|
$confirm_caches_empty->("$desc: before return"); |
1104
|
24
|
|
|
|
|
237
|
}; |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
$confirm_caches_empty = sub { |
1107
|
216
|
|
|
216
|
|
559
|
my ($desc) = @_; |
1108
|
216
|
|
|
|
|
4794
|
ok( !defined( $cache->get($key) ), |
1109
|
|
|
|
|
|
|
"primary cache is not populated with '$key' - $desc" ); |
1110
|
216
|
|
|
|
|
87808
|
ok( !defined( $subcache->get($key) ), |
1111
|
|
|
|
|
|
|
"subcache is not populated with '$key' - $desc" ); |
1112
|
216
|
|
|
|
|
87809
|
ok( !defined( $cache->get($key2) ), |
1113
|
|
|
|
|
|
|
"primary cache is not populated #2 with '$key2' - $desc" ); |
1114
|
216
|
|
|
|
|
87257
|
ok( !defined( $subcache->get($key2) ), |
1115
|
|
|
|
|
|
|
"subcache is not populated #2 with '$key2' - $desc" ); |
1116
|
24
|
|
|
|
|
142
|
}; |
1117
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
$confirm_caches_populated = sub { |
1119
|
144
|
|
|
144
|
|
392
|
my ($desc) = @_; |
1120
|
144
|
|
|
|
|
2881
|
is( $cache->get($key), $value, |
1121
|
|
|
|
|
|
|
"primary cache is populated with '$key' - $desc" ); |
1122
|
144
|
|
|
|
|
64890
|
is( $subcache->get($key), |
1123
|
|
|
|
|
|
|
$value, "subcache is populated with '$key' - $desc" ); |
1124
|
144
|
|
|
|
|
61058
|
is( $cache->get($key2), $value2, |
1125
|
|
|
|
|
|
|
"primary cache is populated with '$key2' - $desc" ); |
1126
|
144
|
|
|
|
|
57935
|
is( $subcache->get($key2), |
1127
|
|
|
|
|
|
|
$value2, "subcache is populated with '$key2' - $desc" ); |
1128
|
24
|
|
|
|
|
149
|
}; |
1129
|
|
|
|
|
|
|
|
1130
|
|
|
|
|
|
|
$test_remove_method->( |
1131
|
48
|
|
|
48
|
|
1518
|
'remove', sub { $cache->remove($key); $cache->remove($key2) } |
|
48
|
|
|
|
|
2032
|
|
1132
|
24
|
|
|
|
|
150
|
); |
1133
|
|
|
|
|
|
|
$test_remove_method->( |
1134
|
48
|
|
|
48
|
|
1553
|
'expire', sub { $cache->expire($key); $cache->expire($key2) } |
|
48
|
|
|
|
|
1192
|
|
1135
|
24
|
|
|
|
|
10329
|
); |
1136
|
24
|
|
|
48
|
|
10477
|
$test_remove_method->( 'clear', sub { $cache->clear() } ); |
|
48
|
|
|
|
|
1417
|
|
1137
|
|
|
|
|
|
|
} |
1138
|
|
|
|
|
|
|
|
1139
|
|
|
|
|
|
|
sub _verify_cache_is_cleared { |
1140
|
25
|
|
|
25
|
|
85
|
my ( $self, $cache, $desc ) = @_; |
1141
|
|
|
|
|
|
|
|
1142
|
25
|
|
|
|
|
212
|
cmp_deeply( [ $cache->get_keys ], [], "get_keys ($desc)" ); |
1143
|
25
|
|
|
|
|
103800
|
is( scalar( $cache->get_keys ), 0, "scalar(get_keys) = 0 ($desc)" ); |
1144
|
25
|
|
|
|
|
9372
|
while ( my ( $keyname, $key ) = each( %{ $self->{keys} } ) ) { |
|
350
|
|
|
|
|
114512
|
|
1145
|
325
|
|
|
|
|
4918
|
ok( !defined $cache->get($key), |
1146
|
|
|
|
|
|
|
"key '$keyname' no longer defined ($desc)" ); |
1147
|
|
|
|
|
|
|
} |
1148
|
|
|
|
|
|
|
} |
1149
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
sub process_keys { |
1151
|
128
|
|
|
128
|
0
|
9525
|
my ( $self, $cache, @keys ) = @_; |
1152
|
128
|
|
|
|
|
510
|
$self->process_key( $cache, 'foo' ); |
1153
|
128
|
|
|
|
|
336
|
return map { $self->process_key( $cache, $_ ) } @keys; |
|
680
|
|
|
|
|
1238
|
|
1154
|
|
|
|
|
|
|
} |
1155
|
|
|
|
|
|
|
|
1156
|
|
|
|
|
|
|
sub process_key { |
1157
|
808
|
|
|
808
|
0
|
1712
|
my ( $self, $cache, $key ) = @_; |
1158
|
808
|
|
|
|
|
1722
|
return $cache->unescape_key( |
1159
|
|
|
|
|
|
|
$cache->escape_key( $cache->transform_key($key) ) ); |
1160
|
|
|
|
|
|
|
} |
1161
|
|
|
|
|
|
|
|
1162
|
|
|
|
|
|
|
sub test_clear : Tests { |
1163
|
8
|
|
|
8
|
0
|
7490
|
my $self = shift; |
1164
|
8
|
|
|
|
|
38
|
my $cache = $self->new_cache( namespace => 'name' ); |
1165
|
8
|
|
|
|
|
43
|
my $cache2 = $self->new_cache( namespace => 'other' ); |
1166
|
8
|
|
|
|
|
43
|
my $cache3 = $self->new_cache( namespace => 'name' ); |
1167
|
8
|
|
|
|
|
149
|
$self->num_tests( $self->{key_count} * 2 + 5 ); |
1168
|
|
|
|
|
|
|
|
1169
|
8
|
50
|
|
|
|
1067
|
if ( $self->supports_clear() ) { |
1170
|
8
|
|
|
|
|
70
|
$self->set_some_keys($cache); |
1171
|
8
|
|
|
|
|
43
|
$self->set_some_keys($cache2); |
1172
|
8
|
|
|
|
|
86
|
$cache->clear(); |
1173
|
|
|
|
|
|
|
|
1174
|
8
|
|
|
|
|
10373
|
$self->_verify_cache_is_cleared( $cache, 'cache after clear' ); |
1175
|
8
|
|
|
|
|
125
|
$self->_verify_cache_is_cleared( $cache3, 'cache3 after clear' ); |
1176
|
|
|
|
|
|
|
cmp_set( |
1177
|
|
|
|
|
|
|
[ $cache2->get_keys ], |
1178
|
8
|
|
|
|
|
56
|
[ $self->process_keys( $cache2, values( %{ $self->{keys} } ) ) ], |
|
8
|
|
|
|
|
9244
|
|
1179
|
|
|
|
|
|
|
'cache2 untouched by clear' |
1180
|
|
|
|
|
|
|
); |
1181
|
|
|
|
|
|
|
} |
1182
|
|
|
|
|
|
|
else { |
1183
|
|
|
|
|
|
|
throws_ok( |
1184
|
0
|
|
|
0
|
|
0
|
sub { $cache->clear() }, |
1185
|
0
|
|
|
|
|
0
|
qr/not supported/, |
1186
|
|
|
|
|
|
|
"clear not supported" |
1187
|
|
|
|
|
|
|
); |
1188
|
0
|
|
|
|
|
0
|
SKIP: { skip "clear not supported", 9 } |
|
0
|
|
|
|
|
0
|
|
1189
|
|
|
|
|
|
|
} |
1190
|
9
|
|
|
9
|
|
18163
|
} |
|
9
|
|
|
|
|
24
|
|
|
9
|
|
|
|
|
85
|
|
1191
|
|
|
|
|
|
|
|
1192
|
|
|
|
|
|
|
sub test_logging : Tests { |
1193
|
6
|
|
|
6
|
0
|
5067
|
my $self = shift; |
1194
|
6
|
|
|
|
|
20
|
my $cache = $self->{cache}; |
1195
|
|
|
|
|
|
|
|
1196
|
6
|
|
|
|
|
39
|
my $log = activate_test_logger(); |
1197
|
6
|
|
|
|
|
36
|
my ( $key, $value ) = $self->kvpair(); |
1198
|
|
|
|
|
|
|
|
1199
|
6
|
|
|
|
|
177
|
my $driver = $cache->label; |
1200
|
|
|
|
|
|
|
|
1201
|
6
|
|
|
|
|
18
|
my $miss_not_in_cache = 'MISS \(not in cache\)'; |
1202
|
6
|
|
|
|
|
15
|
my $miss_expired = 'MISS \(expired\)'; |
1203
|
|
|
|
|
|
|
|
1204
|
6
|
|
|
|
|
18
|
my $start_time = time(); |
1205
|
|
|
|
|
|
|
|
1206
|
6
|
|
|
|
|
71
|
$cache->get($key); |
1207
|
6
|
|
|
|
|
365
|
$log->contains_ok( |
1208
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_not_in_cache/ |
1209
|
|
|
|
|
|
|
); |
1210
|
6
|
|
|
|
|
3308
|
$log->empty_ok(); |
1211
|
|
|
|
|
|
|
|
1212
|
6
|
|
|
|
|
2303
|
$cache->set( $key, $value ); |
1213
|
6
|
|
|
|
|
294
|
$log->contains_ok( |
1214
|
|
|
|
|
|
|
qr/cache set for .* key='$key', size=\d+, expires='never', cache='$driver', time='[-\d]+ms'/ |
1215
|
|
|
|
|
|
|
); |
1216
|
6
|
|
|
|
|
2778
|
$log->empty_ok(); |
1217
|
6
|
|
|
|
|
2271
|
$cache->set( $key, $value, 81 ); |
1218
|
6
|
|
|
|
|
248
|
$log->contains_ok( |
1219
|
|
|
|
|
|
|
qr/cache set for .* key='$key', size=\d+, expires='1m2[012]s', cache='$driver', time='[-\d]+ms'/ |
1220
|
|
|
|
|
|
|
); |
1221
|
6
|
|
|
|
|
2754
|
$log->empty_ok(); |
1222
|
|
|
|
|
|
|
|
1223
|
6
|
|
|
|
|
2284
|
$cache->get($key); |
1224
|
6
|
|
|
|
|
214
|
$log->contains_ok( |
1225
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': HIT/); |
1226
|
6
|
|
|
|
|
2660
|
$log->empty_ok(); |
1227
|
|
|
|
|
|
|
|
1228
|
6
|
|
|
|
|
2301
|
local $CHI::Driver::Test_Time = $start_time + 120; |
1229
|
6
|
|
|
|
|
85
|
$cache->get($key); |
1230
|
6
|
|
|
|
|
219
|
$log->contains_ok( |
1231
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_expired/ |
1232
|
|
|
|
|
|
|
); |
1233
|
6
|
|
|
|
|
2459
|
$log->empty_ok(); |
1234
|
|
|
|
|
|
|
|
1235
|
6
|
|
|
|
|
2317
|
$cache->remove($key); |
1236
|
6
|
|
|
|
|
288
|
$cache->get($key); |
1237
|
6
|
|
|
|
|
233
|
$log->contains_ok( |
1238
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_not_in_cache/ |
1239
|
|
|
|
|
|
|
); |
1240
|
6
|
|
|
|
|
2497
|
$log->empty_ok(); |
1241
|
9
|
|
|
9
|
|
5070
|
} |
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
101
|
|
1242
|
|
|
|
|
|
|
|
1243
|
|
|
|
|
|
|
sub test_stats : Tests { |
1244
|
6
|
|
|
6
|
0
|
18440
|
my $self = shift; |
1245
|
|
|
|
|
|
|
|
1246
|
|
|
|
|
|
|
return 'author testing only - possible differences between JSON versions' |
1247
|
6
|
50
|
|
|
|
46
|
unless ( $ENV{AUTHOR_TESTING} ); |
1248
|
|
|
|
|
|
|
|
1249
|
0
|
|
|
|
|
0
|
my $stats = $self->testing_chi_root_class->stats; |
1250
|
0
|
|
|
|
|
0
|
$stats->enable(); |
1251
|
|
|
|
|
|
|
|
1252
|
0
|
|
|
|
|
0
|
my ( $key, $value ) = $self->kvpair(); |
1253
|
0
|
|
|
|
|
0
|
my $start_time = time(); |
1254
|
|
|
|
|
|
|
|
1255
|
0
|
|
|
|
|
0
|
my $cache; |
1256
|
0
|
|
|
|
|
0
|
$cache = $self->new_cache( namespace => 'Foo' ); |
1257
|
0
|
|
|
|
|
0
|
$cache->get($key); |
1258
|
0
|
|
|
|
|
0
|
$cache->set( $key, $value, 80 ); |
1259
|
0
|
|
|
|
|
0
|
$cache->get($key); |
1260
|
0
|
|
|
|
|
0
|
local $CHI::Driver::Test_Time = $start_time + 120; |
1261
|
0
|
|
|
|
|
0
|
$cache->get($key); |
1262
|
0
|
|
|
|
|
0
|
$cache->remove($key); |
1263
|
0
|
|
|
|
|
0
|
$cache->get($key); |
1264
|
|
|
|
|
|
|
|
1265
|
0
|
|
|
|
|
0
|
$cache = $self->new_cache( namespace => 'Bar' ); |
1266
|
0
|
|
|
|
|
0
|
$cache->set( $key, scalar( $value x 3 ) ); |
1267
|
0
|
|
|
|
|
0
|
$cache->set( $key, $value ); |
1268
|
|
|
|
|
|
|
|
1269
|
0
|
|
|
|
|
0
|
$cache = $self->new_cache( namespace => 'Baz' ); |
1270
|
0
|
|
|
0
|
|
0
|
my $code = sub { usleep(100000); scalar( $value x 5 ) }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1271
|
0
|
|
|
|
|
0
|
$cache->compute( $key, undef, $code ); |
1272
|
0
|
|
|
|
|
0
|
$cache->compute( $key, undef, $code ); |
1273
|
0
|
|
|
|
|
0
|
$cache->compute( $key, undef, $code ); |
1274
|
|
|
|
|
|
|
|
1275
|
0
|
|
|
|
|
0
|
my $log = activate_test_logger(); |
1276
|
0
|
|
|
|
|
0
|
my $label = $cache->label; |
1277
|
0
|
|
|
|
|
0
|
$log->empty_ok(); |
1278
|
0
|
|
|
|
|
0
|
$stats->flush(); |
1279
|
0
|
|
|
|
|
0
|
$log->contains_ok( |
1280
|
|
|
|
|
|
|
qr/CHI stats: \{"absent_misses":2,"end_time":\d+,"expired_misses":1,"get_time_ms":\d+,"hits":1,"label":"$label","namespace":"Foo","root_class":"CHI","set_key_size":6,"set_time_ms":\d+,"set_value_size":20,"sets":1,"start_time":\d+\}/ |
1281
|
|
|
|
|
|
|
); |
1282
|
0
|
|
|
|
|
0
|
$log->contains_ok( |
1283
|
|
|
|
|
|
|
qr/CHI stats: \{"end_time":\d+,"label":"$label","namespace":"Bar","root_class":"CHI","set_key_size":12,"set_time_ms":\d+,"set_value_size":52,"sets":2,"start_time":\d+\}/ |
1284
|
|
|
|
|
|
|
); |
1285
|
0
|
|
|
|
|
0
|
$log->contains_ok( |
1286
|
|
|
|
|
|
|
qr/CHI stats: \{"absent_misses":1,"compute_time_ms":\d+,"computes":1,"end_time":\d+,"get_time_ms":\d+,"hits":2,"label":"$label","namespace":"Baz","root_class":"CHI","set_key_size":6,"set_time_ms":\d+,"set_value_size":44,"sets":1,"start_time":\d+\}/ |
1287
|
|
|
|
|
|
|
); |
1288
|
0
|
|
|
|
|
0
|
$log->empty_ok(); |
1289
|
|
|
|
|
|
|
|
1290
|
0
|
|
|
|
|
0
|
my @logs = ( |
1291
|
|
|
|
|
|
|
'CHI stats: {"root_class":"CHI","namespace":"Foo","label":"File","start_time":1338404896,"end_time":1338404899,"hits":3,"sets":5,"set_time_ms":10}', |
1292
|
|
|
|
|
|
|
'CHI stats: {"root_class":"CHI","namespace":"Foo","label":"File","start_time":1338404896,"end_time":1338404899,"hits":1,"sets":7,"set_time_ms":14}', |
1293
|
|
|
|
|
|
|
'CHI stats: {"root_class":"CHI","namespace":"Bar","label":"File","start_time":1338404896,"end_time":1338404899,"hits":4,"sets":9,"set_time_ms":18}', |
1294
|
|
|
|
|
|
|
'CHI stats: {"root_class":"CHI","namespace":"Foo","label":"File","start_time":1338404896,"end_time":1338404899,"sets":3,"set_time_ms":6}', |
1295
|
|
|
|
|
|
|
'CHI stats: {"root_class":"CHI","namespace":"Foo","label":"File","start_time":1338404896,"end_time":1338404899,"hits":8}', |
1296
|
|
|
|
|
|
|
'CHI stats: {"root_class":"CHI","namespace":"Foo","label":"Memory","start_time":1338404896,"end_time":1338404899,"sets":2,"set_time_ms":4}', |
1297
|
|
|
|
|
|
|
'CHI stats: {"root_class":"CHI","namespace":"Bar","label":"File","start_time":1338404896,"end_time":1338404899,"hits":10,"sets":1,"set_time_ms":2}', |
1298
|
|
|
|
|
|
|
'CHI stats: {"root_class":"CHI","namespace":"Bar","label":"File","start_time":1338404896,"end_time":1338404899,"hits":3,"set_errors":2}', |
1299
|
|
|
|
|
|
|
); |
1300
|
0
|
|
|
|
|
0
|
my $log_dir = tempdir( "chi-test-stats-XXXX", TMPDIR => 1, CLEANUP => 1 ); |
1301
|
0
|
|
|
|
|
0
|
write_file( "$log_dir/log1", join( "\n", splice( @logs, 0, 4 ) ) . "\n" ); |
1302
|
0
|
|
|
|
|
0
|
write_file( "$log_dir/log2", join( "\n", @logs ) ); |
1303
|
0
|
0
|
|
|
|
0
|
open( my $fh2, "<", "$log_dir/log2" ) or die "cannot open $log_dir/log2"; |
1304
|
0
|
|
|
|
|
0
|
my $results = $stats->parse_stats_logs( "$log_dir/log1", $fh2 ); |
1305
|
0
|
|
|
|
|
0
|
close($fh2); |
1306
|
0
|
|
|
|
|
0
|
cmp_deeply( |
1307
|
|
|
|
|
|
|
$results, |
1308
|
|
|
|
|
|
|
Test::Deep::bag( |
1309
|
|
|
|
|
|
|
{ |
1310
|
|
|
|
|
|
|
avg_set_time_ms => '2', |
1311
|
|
|
|
|
|
|
gets => 12, |
1312
|
|
|
|
|
|
|
hit_rate => '1', |
1313
|
|
|
|
|
|
|
hits => 12, |
1314
|
|
|
|
|
|
|
label => 'File', |
1315
|
|
|
|
|
|
|
namespace => 'Foo', |
1316
|
|
|
|
|
|
|
root_class => 'CHI', |
1317
|
|
|
|
|
|
|
set_time_ms => 30, |
1318
|
|
|
|
|
|
|
sets => 15 |
1319
|
|
|
|
|
|
|
}, |
1320
|
|
|
|
|
|
|
{ |
1321
|
|
|
|
|
|
|
avg_set_time_ms => '2', |
1322
|
|
|
|
|
|
|
gets => 17, |
1323
|
|
|
|
|
|
|
hit_rate => '1', |
1324
|
|
|
|
|
|
|
hits => 17, |
1325
|
|
|
|
|
|
|
label => 'File', |
1326
|
|
|
|
|
|
|
namespace => 'Bar', |
1327
|
|
|
|
|
|
|
root_class => 'CHI', |
1328
|
|
|
|
|
|
|
set_errors => 2, |
1329
|
|
|
|
|
|
|
set_time_ms => 20, |
1330
|
|
|
|
|
|
|
sets => 10 |
1331
|
|
|
|
|
|
|
}, |
1332
|
|
|
|
|
|
|
{ |
1333
|
|
|
|
|
|
|
avg_set_time_ms => '2', |
1334
|
|
|
|
|
|
|
label => 'Memory', |
1335
|
|
|
|
|
|
|
namespace => 'Foo', |
1336
|
|
|
|
|
|
|
root_class => 'CHI', |
1337
|
|
|
|
|
|
|
set_time_ms => 4, |
1338
|
|
|
|
|
|
|
sets => 2 |
1339
|
|
|
|
|
|
|
}, |
1340
|
|
|
|
|
|
|
{ |
1341
|
|
|
|
|
|
|
avg_set_time_ms => '2', |
1342
|
|
|
|
|
|
|
hits => '29', |
1343
|
|
|
|
|
|
|
label => 'TOTALS', |
1344
|
|
|
|
|
|
|
namespace => 'TOTALS', |
1345
|
|
|
|
|
|
|
root_class => 'TOTALS', |
1346
|
|
|
|
|
|
|
set_errors => '2', |
1347
|
|
|
|
|
|
|
set_time_ms => 54, |
1348
|
|
|
|
|
|
|
sets => 27 |
1349
|
|
|
|
|
|
|
} |
1350
|
|
|
|
|
|
|
), |
1351
|
|
|
|
|
|
|
'parse_stats_logs' |
1352
|
|
|
|
|
|
|
); |
1353
|
9
|
|
|
9
|
|
7554
|
} |
|
9
|
|
|
|
|
27
|
|
|
9
|
|
|
|
|
51
|
|
1354
|
|
|
|
|
|
|
|
1355
|
|
|
|
|
|
|
sub test_cache_object : Tests { |
1356
|
8
|
|
|
8
|
0
|
7380
|
my $self = shift; |
1357
|
8
|
|
|
|
|
26
|
my $cache = $self->{cache}; |
1358
|
8
|
|
|
|
|
37
|
my ( $key, $value ) = $self->kvpair(); |
1359
|
8
|
|
|
|
|
27
|
my $start_time = time(); |
1360
|
8
|
|
|
|
|
128
|
$cache->set( $key, $value, { expires_at => $start_time + 10 } ); |
1361
|
8
|
|
|
|
|
57
|
is_between( $cache->get_object($key)->created_at, |
1362
|
|
|
|
|
|
|
$start_time, $start_time + 2 ); |
1363
|
8
|
|
|
|
|
3457
|
is_between( $cache->get_object($key)->get_created_at, |
1364
|
|
|
|
|
|
|
$start_time, $start_time + 2 ); |
1365
|
8
|
|
|
|
|
3077
|
is( $cache->get_object($key)->expires_at, $start_time + 10 ); |
1366
|
8
|
|
|
|
|
3220
|
is( $cache->get_object($key)->get_expires_at, $start_time + 10 ); |
1367
|
|
|
|
|
|
|
|
1368
|
8
|
|
|
|
|
2992
|
local $CHI::Driver::Test_Time = $start_time + 50; |
1369
|
8
|
|
|
|
|
117
|
$cache->set( $key, $value ); |
1370
|
8
|
|
|
|
|
43
|
is_between( |
1371
|
|
|
|
|
|
|
$cache->get_object($key)->created_at, |
1372
|
|
|
|
|
|
|
$start_time + 50, |
1373
|
|
|
|
|
|
|
$start_time + 52 |
1374
|
|
|
|
|
|
|
); |
1375
|
8
|
|
|
|
|
3110
|
is_between( |
1376
|
|
|
|
|
|
|
$cache->get_object($key)->get_created_at, |
1377
|
|
|
|
|
|
|
$start_time + 50, |
1378
|
|
|
|
|
|
|
$start_time + 52 |
1379
|
|
|
|
|
|
|
); |
1380
|
9
|
|
|
9
|
|
4148
|
} |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
48
|
|
1381
|
|
|
|
|
|
|
|
1382
|
|
|
|
|
|
|
sub test_size_awareness : Tests { |
1383
|
7
|
|
|
7
|
0
|
6791
|
my $self = shift; |
1384
|
7
|
|
|
|
|
42
|
my ( $key, $value ) = $self->kvpair(); |
1385
|
|
|
|
|
|
|
|
1386
|
7
|
|
|
|
|
42
|
ok( !$self->new_cleared_cache()->is_size_aware(), |
1387
|
|
|
|
|
|
|
"not size aware by default" ); |
1388
|
7
|
|
|
|
|
3270
|
ok( $self->new_cleared_cache( is_size_aware => 1 )->is_size_aware(), |
1389
|
|
|
|
|
|
|
"is_size_aware turns on size awareness" ); |
1390
|
7
|
|
|
|
|
3481
|
ok( $self->new_cleared_cache( max_size => 10 )->is_size_aware(), |
1391
|
|
|
|
|
|
|
"max_size turns on size awareness" ); |
1392
|
|
|
|
|
|
|
|
1393
|
7
|
|
|
|
|
3423
|
my $cache = $self->new_cleared_cache( is_size_aware => 1 ); |
1394
|
7
|
|
|
|
|
57
|
is( $cache->get_size(), 0, "size is 0 for empty" ); |
1395
|
7
|
|
|
|
|
3329
|
$cache->set( $key, $value ); |
1396
|
7
|
|
|
|
|
41
|
is_about( $cache->get_size, 20, "size is about 20 with one value" ); |
1397
|
7
|
|
|
|
|
3247
|
$cache->set( $key, scalar( $value x 5 ) ); |
1398
|
7
|
|
|
|
|
40
|
is_about( $cache->get_size, 45, "size is 45 after overwrite" ); |
1399
|
7
|
|
|
|
|
3156
|
$cache->set( $key, scalar( $value x 5 ) ); |
1400
|
7
|
|
|
|
|
41
|
is_about( $cache->get_size, 45, "size is still 45 after same overwrite" ); |
1401
|
7
|
|
|
|
|
3207
|
$cache->set( $key, scalar( $value x 2 ) ); |
1402
|
7
|
|
|
|
|
42
|
is_about( $cache->get_size, 26, "size is 26 after overwrite" ); |
1403
|
7
|
|
|
|
|
3300
|
$cache->remove($key); |
1404
|
7
|
|
|
|
|
52
|
is( $cache->get_size, 0, "size is 0 again after removing key" ); |
1405
|
7
|
|
|
|
|
3131
|
$cache->set( $key, $value ); |
1406
|
7
|
|
|
|
|
40
|
is_about( $cache->get_size, 20, "size is about 20 with one value" ); |
1407
|
7
|
|
|
|
|
3208
|
$cache->clear(); |
1408
|
7
|
|
|
|
|
1362
|
is( $cache->get_size, 0, "size is 0 again after clear" ); |
1409
|
|
|
|
|
|
|
|
1410
|
7
|
|
|
|
|
3040
|
my $time = time() + 10; |
1411
|
7
|
|
|
|
|
123
|
$cache->set( $key, $value, { expires_at => $time } ); |
1412
|
7
|
|
|
|
|
213
|
is( $cache->get_expires_at($key), |
1413
|
|
|
|
|
|
|
$time, "set options respected by size aware cache" ); |
1414
|
9
|
|
|
9
|
|
4984
|
} |
|
9
|
|
|
|
|
23
|
|
|
9
|
|
|
|
|
74
|
|
1415
|
|
|
|
|
|
|
|
1416
|
|
|
|
|
|
|
sub test_max_size : Tests { |
1417
|
7
|
|
|
7
|
0
|
9038
|
my $self = shift; |
1418
|
|
|
|
|
|
|
|
1419
|
7
|
|
|
|
|
44
|
is( $self->new_cache( max_size => '30k' )->max_size, |
1420
|
|
|
|
|
|
|
30 * 1024, 'max_size parsing' ); |
1421
|
|
|
|
|
|
|
|
1422
|
7
|
|
|
|
|
3836
|
my $cache = $self->new_cleared_cache( max_size => 99 ); |
1423
|
7
|
|
|
|
|
211
|
ok( $cache->is_size_aware, "is size aware when max_size specified" ); |
1424
|
7
|
|
|
|
|
4469
|
my $value_20 = 'x' x 6; |
1425
|
|
|
|
|
|
|
|
1426
|
7
|
|
|
|
|
44
|
for ( my $i = 0 ; $i < 5 ; $i++ ) { |
1427
|
35
|
|
|
|
|
559
|
$cache->set( "key$i", $value_20 ); |
1428
|
|
|
|
|
|
|
} |
1429
|
7
|
|
|
|
|
90
|
for ( my $i = 0 ; $i < 10 ; $i++ ) { |
1430
|
70
|
|
|
|
|
26822
|
$cache->set( "key" . int( rand(10) ), $value_20 ); |
1431
|
70
|
|
|
|
|
348
|
is_between( $cache->get_size, 60, 99, |
1432
|
|
|
|
|
|
|
"after iteration $i, size = " . $cache->get_size ); |
1433
|
70
|
|
|
|
|
34202
|
is_between( scalar( $cache->get_keys ), |
1434
|
|
|
|
|
|
|
3, 5, "after iteration $i, keys = " . scalar( $cache->get_keys ) ); |
1435
|
|
|
|
|
|
|
} |
1436
|
9
|
|
|
9
|
|
4372
|
} |
|
9
|
|
|
|
|
32
|
|
|
9
|
|
|
|
|
102
|
|
1437
|
|
|
|
|
|
|
|
1438
|
|
|
|
|
|
|
sub test_max_size_with_l1_cache : Tests { |
1439
|
8
|
|
|
8
|
0
|
12547
|
my $self = shift; |
1440
|
|
|
|
|
|
|
|
1441
|
8
|
|
|
|
|
75
|
my $cache = $self->new_cleared_cache( |
1442
|
|
|
|
|
|
|
l1_cache => { driver => 'Memory', datastore => {}, max_size => 99 } ); |
1443
|
8
|
|
|
|
|
548
|
my $l1_cache = $cache->l1_cache; |
1444
|
8
|
|
|
|
|
305
|
ok( $l1_cache->is_size_aware, "is size aware when max_size specified" ); |
1445
|
8
|
|
|
|
|
4596
|
my $value_20 = 'x' x 6; |
1446
|
|
|
|
|
|
|
|
1447
|
8
|
|
|
|
|
39
|
my @keys = map { "key$_" } ( 0 .. 9 ); |
|
80
|
|
|
|
|
189
|
|
1448
|
8
|
|
|
|
|
79
|
my @shuffle_keys = shuffle(@keys); |
1449
|
8
|
|
|
|
|
44
|
for ( my $i = 0 ; $i < 5 ; $i++ ) { |
1450
|
40
|
|
|
|
|
1073
|
$cache->set( "key$i", $value_20 ); |
1451
|
|
|
|
|
|
|
} |
1452
|
8
|
|
|
|
|
114
|
for ( my $i = 0 ; $i < 10 ; $i++ ) { |
1453
|
80
|
|
|
|
|
26298
|
my $key = $shuffle_keys[$i]; |
1454
|
80
|
|
|
|
|
2254
|
$cache->set( $key, $value_20 ); |
1455
|
80
|
|
|
|
|
612
|
is_between( $l1_cache->get_size, 60, 99, |
1456
|
|
|
|
|
|
|
"after iteration $i, size = " . $l1_cache->get_size ); |
1457
|
80
|
|
|
|
|
34392
|
is_between( scalar( $l1_cache->get_keys ), |
1458
|
|
|
|
|
|
|
3, 5, |
1459
|
|
|
|
|
|
|
"after iteration $i, keys = " . scalar( $l1_cache->get_keys ) ); |
1460
|
|
|
|
|
|
|
} |
1461
|
8
|
|
|
|
|
3013
|
cmp_deeply( [ sort $cache->get_keys ], |
1462
|
|
|
|
|
|
|
\@keys, "primary cache still has all keys" ); |
1463
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
# Now test population by writeback |
1465
|
8
|
|
|
|
|
21826
|
$l1_cache->clear(); |
1466
|
8
|
|
|
|
|
71
|
is( $l1_cache->get_size, 0, "l1 size is 0 after clear" ); |
1467
|
8
|
|
|
|
|
3145
|
for ( my $i = 0 ; $i < 5 ; $i++ ) { |
1468
|
40
|
|
|
|
|
985
|
$cache->get("key$i"); |
1469
|
|
|
|
|
|
|
} |
1470
|
8
|
|
|
|
|
64
|
for ( my $i = 0 ; $i < 10 ; $i++ ) { |
1471
|
80
|
|
|
|
|
25366
|
my $key = $shuffle_keys[$i]; |
1472
|
80
|
|
|
|
|
2323
|
$cache->get($key); |
1473
|
80
|
|
|
|
|
264
|
is_between( $l1_cache->get_size, 60, 99, |
1474
|
|
|
|
|
|
|
"after iteration $i, size = " . $l1_cache->get_size ); |
1475
|
80
|
|
|
|
|
33043
|
is_between( scalar( $l1_cache->get_keys ), |
1476
|
|
|
|
|
|
|
3, 5, |
1477
|
|
|
|
|
|
|
"after iteration $i, keys = " . scalar( $l1_cache->get_keys ) ); |
1478
|
|
|
|
|
|
|
} |
1479
|
9
|
|
|
9
|
|
6211
|
} |
|
9
|
|
|
|
|
23
|
|
|
9
|
|
|
|
|
53
|
|
1480
|
|
|
|
|
|
|
|
1481
|
|
|
|
|
|
|
sub test_custom_discard_policy : Tests { |
1482
|
7
|
|
|
7
|
0
|
6260
|
my $self = shift; |
1483
|
7
|
|
|
|
|
22
|
my $value_20 = 'x' x 6; |
1484
|
|
|
|
|
|
|
my $highest_first = sub { |
1485
|
70
|
|
|
70
|
|
153
|
my $c = shift; |
1486
|
70
|
|
|
|
|
385
|
my @sorted_keys = sort( $c->get_keys ); |
1487
|
70
|
|
|
|
|
68708
|
return sub { pop(@sorted_keys) }; |
|
315
|
|
|
|
|
1044
|
|
1488
|
7
|
|
|
|
|
41
|
}; |
1489
|
7
|
|
|
|
|
57
|
my $cache = $self->new_cleared_cache( |
1490
|
|
|
|
|
|
|
is_size_aware => 1, |
1491
|
|
|
|
|
|
|
discard_policy => $highest_first |
1492
|
|
|
|
|
|
|
); |
1493
|
7
|
|
|
|
|
58
|
for ( my $j = 0 ; $j < 10 ; $j += 2 ) { |
1494
|
35
|
|
|
|
|
44274
|
$cache->clear(); |
1495
|
35
|
|
|
|
|
5676
|
for ( my $i = 0 ; $i < 10 ; $i++ ) { |
1496
|
350
|
|
|
|
|
1140
|
my $k = ( $i + $j ) % 10; |
1497
|
350
|
|
|
|
|
4138
|
$cache->set( "key$k", $value_20 ); |
1498
|
|
|
|
|
|
|
} |
1499
|
35
|
|
|
|
|
332
|
$cache->discard_to_size(100); |
1500
|
|
|
|
|
|
|
cmp_set( |
1501
|
|
|
|
|
|
|
[ $cache->get_keys ], |
1502
|
35
|
|
|
|
|
169
|
[ map { "key$_" } ( 0 .. 4 ) ], |
|
175
|
|
|
|
|
30426
|
|
1503
|
|
|
|
|
|
|
"5 lowest" |
1504
|
|
|
|
|
|
|
); |
1505
|
35
|
|
|
|
|
136960
|
$cache->discard_to_size(20); |
1506
|
35
|
|
|
|
|
162
|
cmp_set( [ $cache->get_keys ], ["key0"], "1 lowest" ); |
1507
|
|
|
|
|
|
|
} |
1508
|
9
|
|
|
9
|
|
4607
|
} |
|
9
|
|
|
|
|
20
|
|
|
9
|
|
|
|
|
51
|
|
1509
|
|
|
|
|
|
|
|
1510
|
|
|
|
|
|
|
sub test_discard_timeout : Tests { |
1511
|
8
|
|
|
8
|
0
|
18629
|
my $self = shift; |
1512
|
8
|
50
|
|
|
|
62
|
return 'author testing only' unless ( $ENV{AUTHOR_TESTING} ); |
1513
|
|
|
|
|
|
|
|
1514
|
|
|
|
|
|
|
my $bad_policy = sub { |
1515
|
0
|
|
|
0
|
|
0
|
return sub { '1' }; |
|
0
|
|
|
|
|
0
|
|
1516
|
0
|
|
|
|
|
0
|
}; |
1517
|
0
|
|
|
|
|
0
|
my $cache = $self->new_cleared_cache( |
1518
|
|
|
|
|
|
|
is_size_aware => 1, |
1519
|
|
|
|
|
|
|
discard_policy => $bad_policy |
1520
|
|
|
|
|
|
|
); |
1521
|
0
|
|
0
|
|
|
0
|
ok( defined( $cache->discard_timeout ) && $cache->discard_timeout > 1, |
1522
|
|
|
|
|
|
|
"positive discard timeout" ); |
1523
|
0
|
|
|
|
|
0
|
$cache->discard_timeout(1); |
1524
|
0
|
|
|
|
|
0
|
is( $cache->discard_timeout, 1, "can set timeout" ); |
1525
|
0
|
|
|
|
|
0
|
my $start_time = time; |
1526
|
0
|
|
|
|
|
0
|
$cache->set( 2, 2 ); |
1527
|
0
|
|
|
0
|
|
0
|
throws_ok { $cache->discard_to_size(0) } qr/discard timeout .* reached/; |
|
0
|
|
|
|
|
0
|
|
1528
|
0
|
|
0
|
|
|
0
|
ok( |
1529
|
|
|
|
|
|
|
time >= $start_time && time <= $start_time + 4, |
1530
|
|
|
|
|
|
|
sprintf( |
1531
|
|
|
|
|
|
|
"time (%d) is between %d and %d", |
1532
|
|
|
|
|
|
|
time, $start_time, $start_time + 4 |
1533
|
|
|
|
|
|
|
) |
1534
|
|
|
|
|
|
|
); |
1535
|
9
|
|
|
9
|
|
4527
|
} |
|
9
|
|
|
|
|
20
|
|
|
9
|
|
|
|
|
57
|
|
1536
|
|
|
|
|
|
|
|
1537
|
|
|
|
|
|
|
sub test_size_awareness_with_subcaches : Tests { |
1538
|
7
|
|
|
7
|
0
|
8021
|
my $self = shift; |
1539
|
|
|
|
|
|
|
|
1540
|
7
|
|
|
|
|
24
|
my ( $cache, $l1_cache ); |
1541
|
|
|
|
|
|
|
my $set_values = sub { |
1542
|
21
|
|
|
21
|
|
65
|
my $value_20 = 'x' x 6; |
1543
|
21
|
|
|
|
|
95
|
for ( my $i = 0 ; $i < 20 ; $i++ ) { |
1544
|
420
|
|
|
|
|
10962
|
$cache->set( "key$i", $value_20 ); |
1545
|
|
|
|
|
|
|
} |
1546
|
21
|
|
|
|
|
564
|
$l1_cache = $cache->l1_cache; |
1547
|
7
|
|
|
|
|
42
|
}; |
1548
|
|
|
|
|
|
|
my $is_size_aware = sub { |
1549
|
28
|
|
|
28
|
|
75
|
my $c = shift; |
1550
|
28
|
|
|
|
|
636
|
my $label = $c->label; |
1551
|
|
|
|
|
|
|
|
1552
|
28
|
|
|
|
|
586
|
ok( $c->is_size_aware, "$label is size aware" ); |
1553
|
28
|
|
|
|
|
13971
|
my $max_size = $c->max_size; |
1554
|
28
|
|
|
|
|
306
|
ok( $max_size > 0, "$label has max size" ); |
1555
|
28
|
|
|
|
|
9381
|
is_between( $c->get_size, $max_size - 40, |
1556
|
|
|
|
|
|
|
$max_size, "$label size = " . $c->get_size ); |
1557
|
28
|
|
|
|
|
10081
|
is_between( |
1558
|
|
|
|
|
|
|
scalar( $c->get_keys ), |
1559
|
|
|
|
|
|
|
( $max_size + 1 ) / 20 - 2, |
1560
|
|
|
|
|
|
|
( $max_size + 1 ) / 20, |
1561
|
|
|
|
|
|
|
"$label keys = " . scalar( $c->get_keys ) |
1562
|
|
|
|
|
|
|
); |
1563
|
7
|
|
|
|
|
43
|
}; |
1564
|
|
|
|
|
|
|
my $is_not_size_aware = sub { |
1565
|
7
|
|
|
7
|
|
17
|
my $c = shift; |
1566
|
7
|
|
|
|
|
127
|
my $label = $c->label; |
1567
|
|
|
|
|
|
|
|
1568
|
7
|
|
|
|
|
246
|
ok( !$c->is_size_aware, "$label is not size aware" ); |
1569
|
7
|
|
|
|
|
3992
|
is( $c->get_keys, 20, "$label keys = 20" ); |
1570
|
7
|
|
|
|
|
34
|
}; |
1571
|
|
|
|
|
|
|
|
1572
|
7
|
|
|
|
|
57
|
$cache = $self->new_cleared_cache( |
1573
|
|
|
|
|
|
|
l1_cache => { driver => 'Memory', datastore => {}, max_size => 99 } ); |
1574
|
7
|
|
|
|
|
42
|
$set_values->(); |
1575
|
7
|
|
|
|
|
92
|
$is_not_size_aware->($cache); |
1576
|
7
|
|
|
|
|
3046
|
$is_size_aware->($l1_cache); |
1577
|
|
|
|
|
|
|
|
1578
|
7
|
|
|
|
|
2303
|
$cache = $self->new_cleared_cache( |
1579
|
|
|
|
|
|
|
l1_cache => { driver => 'Memory', datastore => {}, max_size => 99 }, |
1580
|
|
|
|
|
|
|
max_size => 199 |
1581
|
|
|
|
|
|
|
); |
1582
|
7
|
|
|
|
|
42
|
$set_values->(); |
1583
|
7
|
|
|
|
|
258
|
$is_size_aware->($cache); |
1584
|
7
|
|
|
|
|
2860
|
$is_size_aware->($l1_cache); |
1585
|
|
|
|
|
|
|
|
1586
|
7
|
|
|
|
|
2354
|
$cache = $self->new_cleared_cache( |
1587
|
|
|
|
|
|
|
l1_cache => { driver => 'Memory', datastore => {} }, |
1588
|
|
|
|
|
|
|
max_size => 199 |
1589
|
|
|
|
|
|
|
); |
1590
|
7
|
|
|
|
|
44
|
$set_values->(); |
1591
|
7
|
|
|
|
|
291
|
$is_size_aware->($cache); |
1592
|
|
|
|
|
|
|
|
1593
|
|
|
|
|
|
|
# Cannot call is_not_size_aware because the get_keys check will |
1594
|
|
|
|
|
|
|
# fail. Keys will be removed from the l1_cache when they are removed |
1595
|
|
|
|
|
|
|
# from the main cache, even though l1_cache does not have a max |
1596
|
|
|
|
|
|
|
# size. Not sure if this is the correct behavior, but for now, we're not |
1597
|
|
|
|
|
|
|
# going to test it. Normally, l1 caches will be more size limited than |
1598
|
|
|
|
|
|
|
# their parent caches. |
1599
|
|
|
|
|
|
|
# |
1600
|
7
|
|
|
|
|
2757
|
ok( !$l1_cache->is_size_aware, $l1_cache->label . " is not size aware" ); |
1601
|
9
|
|
|
9
|
|
6206
|
} |
|
9
|
|
|
|
|
24
|
|
|
9
|
|
|
|
|
42
|
|
1602
|
|
|
|
|
|
|
|
1603
|
|
|
|
|
|
|
sub is_about { |
1604
|
35
|
|
|
35
|
0
|
112
|
my ( $value, $expected, $msg ) = @_; |
1605
|
|
|
|
|
|
|
|
1606
|
35
|
|
|
|
|
116
|
my $margin = int( $expected * 0.1 ); |
1607
|
35
|
50
|
|
|
|
159
|
if ( abs( $value - $expected ) <= $margin ) { |
1608
|
35
|
|
|
|
|
153
|
pass($msg); |
1609
|
|
|
|
|
|
|
} |
1610
|
|
|
|
|
|
|
else { |
1611
|
0
|
|
|
|
|
|
fail("$msg - got $value, expected $expected"); |
1612
|
|
|
|
|
|
|
} |
1613
|
|
|
|
|
|
|
} |
1614
|
|
|
|
|
|
|
|
1615
|
|
|
|
|
|
|
sub test_busy_lock : Tests { |
1616
|
8
|
|
|
8
|
0
|
7529
|
my $self = shift; |
1617
|
8
|
|
|
|
|
27
|
my $cache = $self->{cache}; |
1618
|
|
|
|
|
|
|
|
1619
|
8
|
|
|
|
|
57
|
my ( $key, $value ) = $self->kvpair(); |
1620
|
8
|
|
|
|
|
34
|
my @bl = ( busy_lock => '30 sec' ); |
1621
|
8
|
|
|
|
|
21
|
my $start_time = time(); |
1622
|
|
|
|
|
|
|
|
1623
|
8
|
|
|
|
|
21
|
local $CHI::Driver::Test_Time = $start_time; |
1624
|
8
|
|
|
|
|
114
|
$cache->set( $key, $value, 100 ); |
1625
|
8
|
|
|
|
|
30
|
local $CHI::Driver::Test_Time = $start_time + 90; |
1626
|
8
|
|
|
|
|
117
|
is( $cache->get( $key, @bl ), $value, "hit before expiration" ); |
1627
|
8
|
|
|
|
|
3623
|
is( |
1628
|
|
|
|
|
|
|
$cache->get_expires_at($key), |
1629
|
|
|
|
|
|
|
$start_time + 100, |
1630
|
|
|
|
|
|
|
"expires_at before expiration" |
1631
|
|
|
|
|
|
|
); |
1632
|
8
|
|
|
|
|
3039
|
local $CHI::Driver::Test_Time = $start_time + 110; |
1633
|
8
|
|
|
|
|
116
|
ok( !defined( $cache->get( $key, @bl ) ), "miss after expiration" ); |
1634
|
8
|
|
|
|
|
3048
|
is( |
1635
|
|
|
|
|
|
|
$cache->get_expires_at($key), |
1636
|
|
|
|
|
|
|
$start_time + 140, |
1637
|
|
|
|
|
|
|
"expires_at after busy lock" |
1638
|
|
|
|
|
|
|
); |
1639
|
8
|
|
|
|
|
3199
|
is( $cache->get( $key, @bl ), $value, "hit after busy lock" ); |
1640
|
9
|
|
|
9
|
|
4908
|
} |
|
9
|
|
|
|
|
27
|
|
|
9
|
|
|
|
|
44
|
|
1641
|
|
|
|
|
|
|
|
1642
|
|
|
|
|
|
|
sub test_obj_ref : Tests { |
1643
|
8
|
|
|
8
|
0
|
6055
|
my $self = shift; |
1644
|
|
|
|
|
|
|
|
1645
|
|
|
|
|
|
|
# Make sure obj_ref works in conjunction with subcaches too |
1646
|
8
|
|
|
|
|
64
|
my $cache = |
1647
|
|
|
|
|
|
|
$self->new_cache( l1_cache => { driver => 'Memory', datastore => {} } ); |
1648
|
8
|
|
|
|
|
28
|
my $obj; |
1649
|
8
|
|
|
|
|
41
|
my ( $key, $value ) = ( 'medium', [ a => 5, b => 6 ] ); |
1650
|
|
|
|
|
|
|
|
1651
|
|
|
|
|
|
|
my $validate_obj = sub { |
1652
|
16
|
|
|
16
|
|
86
|
isa_ok( $obj, 'CHI::CacheObject' ); |
1653
|
16
|
|
|
|
|
8062
|
is( $obj->key, $key, "keys match" ); |
1654
|
16
|
|
|
|
|
6137
|
cmp_deeply( $obj->value, $value, "values match" ); |
1655
|
8
|
|
|
|
|
63
|
}; |
1656
|
|
|
|
|
|
|
|
1657
|
8
|
|
|
|
|
230
|
$cache->get( $key, obj_ref => \$obj ); |
1658
|
8
|
|
|
|
|
56
|
ok( !defined($obj), "obj not defined on miss" ); |
1659
|
8
|
|
|
|
|
4684
|
$cache->set( $key, $value, { obj_ref => \$obj } ); |
1660
|
8
|
|
|
|
|
86
|
$validate_obj->(); |
1661
|
8
|
|
|
|
|
3824
|
undef $obj; |
1662
|
8
|
|
|
|
|
52
|
ok( !defined($obj), "obj not defined before get" ); |
1663
|
8
|
|
|
|
|
3100
|
$cache->get( $key, obj_ref => \$obj ); |
1664
|
8
|
|
|
|
|
32
|
$validate_obj->(); |
1665
|
9
|
|
|
9
|
|
4235
|
} |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
40
|
|
1666
|
|
|
|
|
|
|
|
1667
|
|
|
|
|
|
|
sub test_metacache : Tests { |
1668
|
8
|
|
|
8
|
0
|
17153
|
my $self = shift; |
1669
|
8
|
|
|
|
|
31
|
my $cache = $self->{cache}; |
1670
|
|
|
|
|
|
|
|
1671
|
8
|
|
|
|
|
66
|
ok( !defined( $cache->{metacache} ), "metacache is lazy" ); |
1672
|
8
|
|
|
|
|
3729
|
$cache->metacache->set( 'foo', 5 ); |
1673
|
8
|
|
|
|
|
1393
|
ok( defined( $cache->{metacache} ), "metacache autovivified" ); |
1674
|
8
|
|
|
|
|
3586
|
is( $cache->metacache->get('foo'), 5 ); |
1675
|
9
|
|
|
9
|
|
3253
|
} |
|
9
|
|
|
|
|
23
|
|
|
9
|
|
|
|
|
52
|
|
1676
|
|
|
|
|
|
|
|
1677
|
|
|
|
|
|
|
sub test_scalar_return_values : Tests { |
1678
|
7
|
|
|
7
|
0
|
22846
|
my $self = shift; |
1679
|
7
|
|
|
|
|
22
|
my $cache = $self->{cache}; |
1680
|
|
|
|
|
|
|
|
1681
|
|
|
|
|
|
|
my $check = sub { |
1682
|
35
|
|
|
35
|
|
90
|
my ($code) = @_; |
1683
|
35
|
|
|
|
|
86
|
my $scalar_result = $code->(); |
1684
|
35
|
|
|
|
|
840
|
my @list = $code->(); |
1685
|
35
|
|
|
|
|
935
|
cmp_deeply( \@list, [$scalar_result] ); |
1686
|
7
|
|
|
|
|
40
|
}; |
1687
|
|
|
|
|
|
|
|
1688
|
7
|
|
|
14
|
|
46
|
$check->( sub { $cache->fetch('a') } ); |
|
14
|
|
|
|
|
54
|
|
1689
|
7
|
|
|
14
|
|
11285
|
$check->( sub { $cache->get('a') } ); |
|
14
|
|
|
|
|
207
|
|
1690
|
7
|
|
|
14
|
|
9872
|
$check->( sub { $cache->set( 'a', 5 ) } ); |
|
14
|
|
|
|
|
229
|
|
1691
|
7
|
|
|
14
|
|
10807
|
$check->( sub { $cache->fetch('a') } ); |
|
14
|
|
|
|
|
64
|
|
1692
|
7
|
|
|
14
|
|
9805
|
$check->( sub { $cache->get('a') } ); |
|
14
|
|
|
|
|
209
|
|
1693
|
9
|
|
|
9
|
|
4381
|
} |
|
9
|
|
|
|
|
22
|
|
|
9
|
|
|
|
|
50
|
|
1694
|
|
|
|
|
|
|
|
1695
|
|
|
|
|
|
|
sub test_no_leak : Tests { |
1696
|
8
|
|
|
8
|
0
|
6317
|
my ($self) = @_; |
1697
|
|
|
|
|
|
|
|
1698
|
8
|
|
|
|
|
26
|
my $weakref; |
1699
|
|
|
|
|
|
|
{ |
1700
|
8
|
|
|
|
|
20
|
my $cache = $self->new_cache(); |
|
8
|
|
|
|
|
37
|
|
1701
|
8
|
|
|
|
|
30
|
$weakref = $cache; |
1702
|
8
|
|
|
|
|
50
|
weaken($weakref); |
1703
|
8
|
|
33
|
|
|
132
|
ok( defined($weakref) && $weakref->isa('CHI::Driver'), |
1704
|
|
|
|
|
|
|
"weakref is defined" ); |
1705
|
|
|
|
|
|
|
} |
1706
|
8
|
|
|
|
|
3727
|
ok( !defined($weakref), "weakref is no longer defined - cache was freed" ); |
1707
|
9
|
|
|
9
|
|
3407
|
} |
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
47
|
|
1708
|
|
|
|
|
|
|
|
1709
|
|
|
|
|
|
|
{ |
1710
|
|
|
|
|
|
|
package My::CHI; |
1711
|
|
|
|
|
|
|
$My::CHI::VERSION = '0.61'; |
1712
|
|
|
|
|
|
|
our @ISA = qw(CHI); |
1713
|
|
|
|
|
|
|
} |
1714
|
|
|
|
|
|
|
|
1715
|
|
|
|
|
|
|
sub test_driver_properties : Tests { |
1716
|
8
|
|
|
8
|
0
|
6155
|
my $self = shift; |
1717
|
8
|
|
|
|
|
28
|
my $cache = $self->{cache}; |
1718
|
|
|
|
|
|
|
|
1719
|
8
|
|
|
|
|
94
|
is( $cache->chi_root_class, 'CHI', 'chi_root_class=CHI' ); |
1720
|
8
|
|
|
|
|
3870
|
my $cache2 = My::CHI->new( $self->new_cache_options() ); |
1721
|
8
|
|
|
|
|
71
|
is( $cache2->chi_root_class, 'My::CHI', 'chi_root_class=My::CHI' ); |
1722
|
9
|
|
|
9
|
|
3440
|
} |
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
40
|
|
1723
|
|
|
|
|
|
|
|
1724
|
|
|
|
|
|
|
sub test_missing_params : Tests { |
1725
|
8
|
|
|
8
|
0
|
6285
|
my $self = shift; |
1726
|
8
|
|
|
|
|
28
|
my $cache = $self->{cache}; |
1727
|
|
|
|
|
|
|
|
1728
|
|
|
|
|
|
|
# These methods require a key |
1729
|
8
|
|
|
|
|
33
|
foreach my $method ( |
1730
|
|
|
|
|
|
|
qw(get get_object get_expires_at exists_and_is_expired is_valid set expire compute get_multi_arrayref get_multi_hashref set_multi remove_multi) |
1731
|
|
|
|
|
|
|
) |
1732
|
|
|
|
|
|
|
{ |
1733
|
|
|
|
|
|
|
throws_ok( |
1734
|
96
|
|
|
96
|
|
4037
|
sub { $cache->$method() }, |
1735
|
96
|
|
|
|
|
69267
|
qr/must specify key/, |
1736
|
|
|
|
|
|
|
"$method throws error when no key passed" |
1737
|
|
|
|
|
|
|
); |
1738
|
|
|
|
|
|
|
} |
1739
|
9
|
|
|
9
|
|
3577
|
} |
|
9
|
|
|
|
|
20
|
|
|
9
|
|
|
|
|
51
|
|
1740
|
|
|
|
|
|
|
|
1741
|
|
|
|
|
|
|
sub test_compute : Tests { |
1742
|
8
|
|
|
8
|
0
|
8224
|
my $self = shift; |
1743
|
8
|
|
|
|
|
25
|
my $cache = $self->{cache}; |
1744
|
|
|
|
|
|
|
|
1745
|
|
|
|
|
|
|
# Test current arg order and pre-0.40 arg order |
1746
|
8
|
|
|
|
|
42
|
foreach my $iter ( 0 .. 1 ) { |
1747
|
16
|
|
|
|
|
3007
|
my $count = 5; |
1748
|
16
|
|
|
|
|
43
|
my $expire_time = time + 10; |
1749
|
16
|
|
|
16
|
|
99
|
my @args1 = ( { expires_at => $expire_time }, sub { $count++ } ); |
|
16
|
|
|
|
|
50
|
|
1750
|
|
|
|
|
|
|
my @args2 = ( |
1751
|
|
|
|
|
|
|
{ |
1752
|
18
|
|
|
18
|
|
67
|
expire_if => sub { 1 } |
1753
|
|
|
|
|
|
|
}, |
1754
|
16
|
|
|
16
|
|
43
|
sub { $count++ } |
1755
|
16
|
|
|
|
|
95
|
); |
1756
|
16
|
100
|
|
|
|
62
|
if ($iter) { |
1757
|
8
|
|
|
|
|
24
|
@args1 = reverse(@args1); |
1758
|
8
|
|
|
|
|
23
|
@args2 = reverse(@args2); |
1759
|
|
|
|
|
|
|
} |
1760
|
16
|
|
|
|
|
119
|
$cache->clear; |
1761
|
16
|
|
|
|
|
1612
|
is( $cache->get('foo'), undef, "miss" ); |
1762
|
16
|
|
|
|
|
7744
|
is( $cache->compute( 'foo', @args1 ), 5, "compute - 5" ); |
1763
|
16
|
|
|
|
|
6318
|
is( $cache->get('foo'), 5, "hit - 5" ); |
1764
|
16
|
|
|
|
|
5978
|
is( $cache->get_object('foo')->expires_at, $expire_time, |
1765
|
|
|
|
|
|
|
"expire time" ); |
1766
|
16
|
|
|
|
|
6092
|
is( $cache->compute( 'foo', @args2 ), 6, "compute - 6" ); |
1767
|
16
|
|
|
|
|
6352
|
is( $cache->get('foo'), 6, "hit - 6" ); |
1768
|
|
|
|
|
|
|
} |
1769
|
|
|
|
|
|
|
|
1770
|
|
|
|
|
|
|
# Test wantarray |
1771
|
8
|
|
|
|
|
3074
|
$cache->clear(); |
1772
|
|
|
|
|
|
|
my $compute_list = sub { |
1773
|
16
|
|
|
16
|
|
131
|
$cache->compute( 'foo', {}, sub { ( int( rand(10000) ) ) x 5 } ); |
|
8
|
|
|
|
|
187
|
|
1774
|
8
|
|
|
|
|
1267
|
}; |
1775
|
8
|
|
|
|
|
38
|
my @list1 = $compute_list->(); |
1776
|
8
|
|
|
|
|
53
|
my @list2 = $compute_list->(); |
1777
|
8
|
|
|
|
|
65
|
is( scalar(@list1), 5, "list has 5 items" ); |
1778
|
8
|
|
|
|
|
3143
|
cmp_deeply( \@list1, \@list2, "lists are the same" ); |
1779
|
9
|
|
|
9
|
|
5588
|
} |
|
9
|
|
|
|
|
31
|
|
|
9
|
|
|
|
|
56
|
|
1780
|
|
|
|
|
|
|
|
1781
|
|
|
|
|
|
|
sub test_compress_threshold : Tests { |
1782
|
7
|
|
|
7
|
0
|
5239
|
my $self = shift; |
1783
|
7
|
|
|
|
|
21
|
my $cache = $self->{cache}; |
1784
|
|
|
|
|
|
|
|
1785
|
7
|
|
|
|
|
21
|
my $s0 = 'x' x 180; |
1786
|
7
|
|
|
|
|
23
|
my $s1 = 'x' x 200; |
1787
|
7
|
|
|
|
|
129
|
$cache->set( 'key0', $s0 ); |
1788
|
7
|
|
|
|
|
97
|
$cache->set( 'key1', $s1 ); |
1789
|
7
|
|
|
|
|
40
|
is_between( $cache->get_object('key0')->size, 180, 220 ); |
1790
|
7
|
|
|
|
|
2963
|
is_between( $cache->get_object('key1')->size, 200, 240 ); |
1791
|
|
|
|
|
|
|
|
1792
|
7
|
|
|
|
|
2524
|
my $cache2 = $self->new_cache( compress_threshold => 190 ); |
1793
|
7
|
|
|
|
|
101
|
$cache2->set( 'key0', $s0 ); |
1794
|
7
|
|
|
|
|
96
|
$cache2->set( 'key1', $s1 ); |
1795
|
7
|
|
|
|
|
55
|
is_between( $cache2->get_object('key0')->size, 180, 220 ); |
1796
|
7
|
|
|
|
|
4792
|
ok( $cache2->get_object('key1')->size < 100 ); |
1797
|
7
|
|
|
|
|
2738
|
is( $cache2->get('key0'), $s0 ); |
1798
|
7
|
|
|
|
|
2866
|
is( $cache2->get('key1'), $s1 ); |
1799
|
9
|
|
|
9
|
|
4180
|
} |
|
9
|
|
|
|
|
23
|
|
|
9
|
|
|
|
|
51
|
|
1800
|
|
|
|
|
|
|
|
1801
|
|
|
|
|
|
|
sub test_expires_on_backend : Tests { |
1802
|
8
|
|
|
8
|
0
|
7989
|
my $self = shift; |
1803
|
|
|
|
|
|
|
|
1804
|
8
|
100
|
|
|
|
66
|
return "skipping - no support for expires_on_backend" |
1805
|
|
|
|
|
|
|
unless $self->supports_expires_on_backend(); |
1806
|
1
|
|
|
|
|
4
|
foreach my $expires_on_backend ( 0, 1 ) { |
1807
|
2
|
|
|
|
|
474
|
my $cache = |
1808
|
|
|
|
|
|
|
$self->new_cache( expires_on_backend => $expires_on_backend ); |
1809
|
2
|
|
|
|
|
14
|
$cache->set( 'key0', 5, '2s' ); |
1810
|
2
|
|
|
|
|
14
|
$cache->set( 'key1', 6, { expires_at => time + 2 } ); |
1811
|
2
|
|
|
|
|
13
|
is( $cache->get('key0'), 5, 'hit key0 before expire' ); |
1812
|
2
|
|
|
|
|
1358
|
is( $cache->get('key1'), 6, 'hit key1 before expire' ); |
1813
|
2
|
|
|
|
|
6001403
|
sleep(3); |
1814
|
2
|
|
|
|
|
88
|
ok( !defined( $cache->get('key0') ), 'miss key0 after expire' ); |
1815
|
2
|
|
|
|
|
1943
|
ok( !defined( $cache->get('key1') ), 'miss key1 after expire' ); |
1816
|
|
|
|
|
|
|
|
1817
|
2
|
100
|
|
|
|
914
|
if ($expires_on_backend) { |
1818
|
1
|
|
|
|
|
6
|
ok( |
1819
|
|
|
|
|
|
|
!defined( $cache->get_object('key0') ), |
1820
|
|
|
|
|
|
|
'cannot get_object(key0) after expire' |
1821
|
|
|
|
|
|
|
); |
1822
|
1
|
|
|
|
|
610
|
ok( |
1823
|
|
|
|
|
|
|
!defined( $cache->get_object('key1') ), |
1824
|
|
|
|
|
|
|
'cannot get_object(key1) after expire' |
1825
|
|
|
|
|
|
|
); |
1826
|
|
|
|
|
|
|
} |
1827
|
|
|
|
|
|
|
else { |
1828
|
1
|
|
|
|
|
7
|
ok( |
1829
|
|
|
|
|
|
|
$cache->get_object('key0')->is_expired(), |
1830
|
|
|
|
|
|
|
'can get_object(key0) after expire' |
1831
|
|
|
|
|
|
|
); |
1832
|
1
|
|
|
|
|
463
|
ok( |
1833
|
|
|
|
|
|
|
$cache->get_object('key1')->is_expired(), |
1834
|
|
|
|
|
|
|
'can get_object(key1) after expire' |
1835
|
|
|
|
|
|
|
); |
1836
|
|
|
|
|
|
|
} |
1837
|
|
|
|
|
|
|
} |
1838
|
9
|
|
|
9
|
|
4314
|
} |
|
9
|
|
|
|
|
22
|
|
|
9
|
|
|
|
|
50
|
|
1839
|
|
|
|
|
|
|
|
1840
|
|
|
|
|
|
|
sub test_append : Tests { |
1841
|
6
|
|
|
6
|
0
|
6116
|
my $self = shift; |
1842
|
6
|
|
|
|
|
18
|
my $cache = $self->{cache}; |
1843
|
|
|
|
|
|
|
my ( $key, $value ) = |
1844
|
6
|
|
|
|
|
30
|
( $self->{keys}->{arrayref}, $self->{values}->{medium} ); |
1845
|
|
|
|
|
|
|
|
1846
|
|
|
|
|
|
|
# Appending to non-existent key has no effect |
1847
|
|
|
|
|
|
|
# |
1848
|
6
|
|
|
|
|
223
|
$cache->append( $key, $value ); |
1849
|
6
|
|
|
|
|
307
|
ok( !$cache->get($key) ); |
1850
|
|
|
|
|
|
|
|
1851
|
6
|
|
|
|
|
2651
|
ok( $cache->set( $key, $value ) ); |
1852
|
6
|
|
|
|
|
2491
|
$cache->append( $key, $value ); |
1853
|
6
|
|
|
|
|
70
|
is( $cache->get($key), $value . $value ); |
1854
|
6
|
|
|
|
|
2629
|
$cache->append( $key, $value ); |
1855
|
6
|
|
|
|
|
72
|
is( $cache->get($key), $value . $value . $value ); |
1856
|
9
|
|
|
9
|
|
3643
|
} |
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
39
|
|
1857
|
|
|
|
|
|
|
|
1858
|
|
|
|
|
|
|
sub test_add : Tests { |
1859
|
8
|
|
|
8
|
0
|
35153
|
my $self = shift; |
1860
|
8
|
|
|
|
|
26
|
my $cache = $self->{cache}; |
1861
|
|
|
|
|
|
|
my ( $key, $value ) = |
1862
|
8
|
|
|
|
|
42
|
( $self->{keys}->{arrayref}, $self->{values}->{medium} ); |
1863
|
|
|
|
|
|
|
|
1864
|
8
|
|
|
|
|
36
|
my $t = time(); |
1865
|
|
|
|
|
|
|
|
1866
|
8
|
|
|
|
|
125
|
$cache->add( $key, $value, { expires_at => $t + 100 } ); |
1867
|
8
|
|
|
|
|
143
|
is( $cache->get($key), $value, "get" ); |
1868
|
8
|
|
|
|
|
4882
|
is( $cache->get_object($key)->expires_at, $t + 100, "expires_at" ); |
1869
|
|
|
|
|
|
|
|
1870
|
8
|
|
|
|
|
2855
|
$cache->add( $key, $value . $value, { expires_at => $t + 200 } ); |
1871
|
8
|
|
|
|
|
116
|
is( $cache->get($key), $value, "get (after add)" ); |
1872
|
8
|
|
|
|
|
3036
|
is( $cache->get_object($key)->expires_at, |
1873
|
|
|
|
|
|
|
$t + 100, "expires_at (after add)" ); |
1874
|
|
|
|
|
|
|
|
1875
|
8
|
|
|
|
|
3111
|
$cache->remove($key); |
1876
|
8
|
|
|
|
|
741
|
$cache->add( $key, $value . $value, { expires_at => $t + 200 } ); |
1877
|
8
|
|
|
|
|
105
|
is( $cache->get($key), $value . $value, "get (after expire and add)" ); |
1878
|
8
|
|
|
|
|
3086
|
is( $cache->get_object($key)->expires_at, |
1879
|
|
|
|
|
|
|
$t + 200, "expires_at (after expire and add)" ); |
1880
|
9
|
|
|
9
|
|
4132
|
} |
|
9
|
|
|
|
|
19
|
|
|
9
|
|
|
|
|
50
|
|
1881
|
|
|
|
|
|
|
|
1882
|
|
|
|
|
|
|
sub test_replace : Tests { |
1883
|
8
|
|
|
8
|
0
|
16274
|
my $self = shift; |
1884
|
8
|
|
|
|
|
25
|
my $cache = $self->{cache}; |
1885
|
|
|
|
|
|
|
my ( $key, $value ) = |
1886
|
8
|
|
|
|
|
51
|
( $self->{keys}->{arrayref}, $self->{values}->{medium} ); |
1887
|
|
|
|
|
|
|
|
1888
|
8
|
|
|
|
|
25
|
my $t = time(); |
1889
|
|
|
|
|
|
|
|
1890
|
8
|
|
|
|
|
187
|
$cache->replace( $key, $value, { expires_at => $t + 100 } ); |
1891
|
8
|
|
|
|
|
45
|
ok( !$cache->get_object($key), "get" ); |
1892
|
|
|
|
|
|
|
|
1893
|
8
|
|
|
|
|
3933
|
$cache->set( $key, $value . $value, { expires_at => $t + 200 } ); |
1894
|
8
|
|
|
|
|
64
|
$cache->replace( $key, $value, { expires_at => $t + 100 } ); |
1895
|
8
|
|
|
|
|
108
|
is( $cache->get($key), $value, "get (after replace)" ); |
1896
|
8
|
|
|
|
|
4499
|
is( $cache->get_object($key)->expires_at, |
1897
|
|
|
|
|
|
|
$t + 100, "expires_at (after replace)" ); |
1898
|
9
|
|
|
9
|
|
3715
|
} |
|
9
|
|
|
|
|
22
|
|
|
9
|
|
|
|
|
45
|
|
1899
|
|
|
|
|
|
|
|
1900
|
|
|
|
|
|
|
sub test_max_key_length : Tests { |
1901
|
6
|
|
|
6
|
0
|
5580
|
my $self = shift; |
1902
|
|
|
|
|
|
|
|
1903
|
|
|
|
|
|
|
# Test max_key_length and also that key does not get transformed twice in mirror_cache |
1904
|
|
|
|
|
|
|
# |
1905
|
6
|
|
|
|
|
21
|
my $mirror_store = {}; |
1906
|
6
|
|
|
|
|
48
|
my $cache = $self->new_cleared_cache( |
1907
|
|
|
|
|
|
|
max_key_length => 10, |
1908
|
|
|
|
|
|
|
mirror_cache => { driver => 'Memory', datastore => $mirror_store } |
1909
|
|
|
|
|
|
|
); |
1910
|
|
|
|
|
|
|
|
1911
|
6
|
|
|
|
|
25
|
foreach my $keyname ( 'medium', 'large' ) { |
1912
|
|
|
|
|
|
|
my ( $key, $value ) = |
1913
|
12
|
|
|
|
|
2456
|
( $self->{keys}->{$keyname}, $self->{values}->{$keyname} ); |
1914
|
12
|
|
|
|
|
312
|
$cache->set( $key, $value ); |
1915
|
12
|
|
|
|
|
363
|
is( $cache->get($key), $value, $keyname ); |
1916
|
12
|
|
|
|
|
6363
|
is( $cache->mirror_cache->get($key), $value, $keyname ); |
1917
|
12
|
100
|
|
|
|
4712
|
if ( $keyname eq 'medium' ) { |
1918
|
6
|
|
|
|
|
33
|
is( $cache->get_object($key)->key(), $key, "medium key stored" ); |
1919
|
|
|
|
|
|
|
} |
1920
|
|
|
|
|
|
|
else { |
1921
|
6
|
|
|
|
|
36
|
isnt( $cache->get_object($key)->key(), $key, "md5 key stored" ); |
1922
|
6
|
|
|
|
|
2476
|
is( length( $cache->get_object($key)->key() ), |
1923
|
|
|
|
|
|
|
32, "md5 key stored" ); |
1924
|
|
|
|
|
|
|
} |
1925
|
|
|
|
|
|
|
} |
1926
|
9
|
|
|
9
|
|
4073
|
} |
|
9
|
|
|
|
|
25
|
|
|
9
|
|
|
|
|
47
|
|
1927
|
|
|
|
|
|
|
|
1928
|
|
|
|
|
|
|
# Test that cache does not get corrupted with multiple concurrent processes writing |
1929
|
|
|
|
|
|
|
# |
1930
|
|
|
|
|
|
|
sub test_multiple_processes : Tests { |
1931
|
5
|
|
|
5
|
0
|
3952
|
my $self = shift; |
1932
|
5
|
50
|
|
|
|
40
|
return "author test only" unless $ENV{AUTHOR_TESTING}; |
1933
|
0
|
0
|
|
|
|
0
|
return "does not pass on file driver" |
1934
|
|
|
|
|
|
|
if $self->new_cache->short_driver_name eq 'File'; |
1935
|
|
|
|
|
|
|
|
1936
|
0
|
|
|
|
|
0
|
my ( @values, @pids, %valid_values ); |
1937
|
0
|
|
|
|
|
0
|
my $shared_key = $self->{keys}->{medium}; |
1938
|
0
|
|
|
|
|
0
|
my $num_procs = 4; |
1939
|
|
|
|
|
|
|
|
1940
|
0
|
|
|
|
|
0
|
local $SIG{CHLD} = 'IGNORE'; |
1941
|
|
|
|
|
|
|
|
1942
|
|
|
|
|
|
|
# Each child continuously writes a unique 10000 byte string to a single shared key |
1943
|
|
|
|
|
|
|
# |
1944
|
|
|
|
|
|
|
my $child_action = sub { |
1945
|
0
|
|
|
0
|
|
0
|
my $p = shift; |
1946
|
0
|
|
|
|
|
0
|
my $value = $values[$p]; |
1947
|
0
|
|
|
|
|
0
|
my $child_cache = $self->new_cache(); |
1948
|
|
|
|
|
|
|
|
1949
|
0
|
|
|
|
|
0
|
sleep(1); # Wait for parent to be ready |
1950
|
0
|
|
|
|
|
0
|
my $child_end_time = time() + 5; |
1951
|
0
|
|
|
|
|
0
|
while ( time < $child_end_time ) { |
1952
|
0
|
|
|
|
|
0
|
$child_cache->set( $shared_key, $value ); |
1953
|
|
|
|
|
|
|
} |
1954
|
0
|
|
|
|
|
0
|
$child_cache->set( "done$p", 1 ); |
1955
|
0
|
|
|
|
|
0
|
}; |
1956
|
|
|
|
|
|
|
|
1957
|
0
|
|
|
|
|
0
|
foreach my $p ( 0 .. $num_procs ) { |
1958
|
0
|
|
|
|
|
0
|
$values[$p] = random_string(10000); |
1959
|
0
|
|
|
|
|
0
|
$valid_values{ $values[$p] } = $p; |
1960
|
0
|
0
|
|
|
|
0
|
if ( my $pid = fork() ) { |
1961
|
0
|
|
|
|
|
0
|
$pids[$p] = $pid; |
1962
|
|
|
|
|
|
|
} |
1963
|
|
|
|
|
|
|
else { |
1964
|
0
|
|
|
|
|
0
|
$child_action->($p); |
1965
|
0
|
|
|
|
|
0
|
exit; |
1966
|
|
|
|
|
|
|
} |
1967
|
|
|
|
|
|
|
} |
1968
|
|
|
|
|
|
|
|
1969
|
|
|
|
|
|
|
# Parent continuously gets shared key, makes sure it is one of the valid values. |
1970
|
|
|
|
|
|
|
# Loop until we see done flag for each child process, or until 10 secs pass. |
1971
|
|
|
|
|
|
|
# At end make sure we saw each process's value once. |
1972
|
|
|
|
|
|
|
# |
1973
|
0
|
|
|
|
|
0
|
my ( %seen, $error ); |
1974
|
0
|
|
|
|
|
0
|
my $parent_end_time = time() + 10; |
1975
|
0
|
|
|
|
|
0
|
my $parent_cache = $self->new_cache(); |
1976
|
0
|
|
|
|
|
0
|
while ( !$error ) { |
1977
|
0
|
|
|
|
|
0
|
for ( my $i = 0 ; $i < 100 ; $i++ ) { |
1978
|
0
|
|
|
|
|
0
|
my $value = $parent_cache->get($shared_key); |
1979
|
0
|
0
|
|
|
|
0
|
if ( defined($value) ) { |
1980
|
0
|
0
|
|
|
|
0
|
if ( defined( my $p = $valid_values{$value} ) ) { |
1981
|
0
|
|
|
|
|
0
|
$seen{$p} = 1; |
1982
|
|
|
|
|
|
|
} |
1983
|
|
|
|
|
|
|
else { |
1984
|
0
|
|
|
|
|
0
|
$error = "got invalid value '$value' from shared key"; |
1985
|
0
|
|
|
|
|
0
|
last; |
1986
|
|
|
|
|
|
|
} |
1987
|
|
|
|
|
|
|
} |
1988
|
|
|
|
|
|
|
} |
1989
|
0
|
0
|
|
|
|
0
|
if ( !grep { !$parent_cache->get("done$_") } ( 0 .. $num_procs ) ) { |
|
0
|
|
|
|
|
0
|
|
1990
|
0
|
|
|
|
|
0
|
last; |
1991
|
|
|
|
|
|
|
} |
1992
|
0
|
0
|
|
|
|
0
|
if ( time() >= $parent_end_time ) { |
1993
|
0
|
|
|
|
|
0
|
$error = "did not see all done flags after 10 secs"; |
1994
|
|
|
|
|
|
|
} |
1995
|
|
|
|
|
|
|
} |
1996
|
|
|
|
|
|
|
|
1997
|
0
|
0
|
|
|
|
0
|
if ( !$error ) { |
1998
|
0
|
0
|
|
|
|
0
|
if ( my ($p) = grep { !$seen{$_} } ( 0 .. $num_procs ) ) { |
|
0
|
|
|
|
|
0
|
|
1999
|
0
|
|
|
|
|
0
|
$error = "never saw value from process $p"; |
2000
|
|
|
|
|
|
|
} |
2001
|
|
|
|
|
|
|
} |
2002
|
|
|
|
|
|
|
|
2003
|
0
|
0
|
|
|
|
0
|
if ($error) { |
2004
|
0
|
|
|
|
|
0
|
ok( 0, $error ); |
2005
|
|
|
|
|
|
|
} |
2006
|
|
|
|
|
|
|
else { |
2007
|
0
|
|
|
|
|
0
|
ok( 1, "passed" ); |
2008
|
|
|
|
|
|
|
} |
2009
|
9
|
|
|
9
|
|
6989
|
} |
|
9
|
|
|
|
|
30
|
|
|
9
|
|
|
|
|
45
|
|
2010
|
|
|
|
|
|
|
|
2011
|
|
|
|
|
|
|
1; |